cells</b> check-box prevents merging medium nodes of quadratic
elements with corner nodes. This check-box is enabled provided
that the selected mesh includes quadratic elements.</li>
+<li>Activation of <b>Avoid making holes</b> check-box prevents merging
+ nodes that make elements invalid (but not degenerated) and hence
+ removed. Thus, no holes in place of removed elements appear. </li>
<li><b>Exclude groups from detection</b> group allows to ignore the
nodes which belong to the specified mesh groups. This control is
active provided that the mesh includes groups.</li>
raises (SALOME::SALOME_Exception);
void MergeNodes (in array_of_long_array GroupsOfNodes,
- in SMESH::ListOfIDSources NodesToKeep)
+ in SMESH::ListOfIDSources NodesToKeep,
+ in boolean AvoidMakingHoles)
raises (SALOME::SALOME_Exception);
/*!
};
typedef NCollection_DataMap<gp_Pnt,SMDS_MeshNode*,Hasher> TDataMapOfPntNodePtr;
- const int HEADER_SIZE = 84;
+ const int HEADER_SIZE = 84; // 80 chars + int
const int SIZEOF_STL_FACET = 50;
const int ASCII_LINES_PER_FACET = 7;
const int SIZE_OF_FLOAT = 4;
static Standard_Real readFloat(SMESH_File& theFile)
{
union {
- Standard_Boolean i;
- Standard_ShortReal f;
+ int i;
+ float f;
} u;
const char* c = theFile;
+ u.i = 0;
u.i = c[0] & 0xFF;
u.i |= (c[1] & 0xFF) << 0x08;
u.i |= (c[2] & 0xFF) << 0x10;
//=======================================================================
//function : readAscii
-//purpose :
+//purpose :
//=======================================================================
Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readAscii(SMESH_File& theFile) const
{
Status aResult = DRS_OK;
+ // get a solid name
+ if ( strncmp( "solid ", theFile, strlen("solid ")) == 0 ) // not empty
+ {
+ const char * header = theFile;
+ std::string& name = const_cast<std::string&>( myName );
+ for ( header += strlen("solid "); !iscntrl( *header ); ++header )
+ name.push_back( *header );
+
+ std::string::iterator i = name.begin();
+ while ( i != name.end() && isspace( *i )) ++i;
+ name.erase( name.begin(), i );
+
+ size_t n = name.size();
+ while ( n > 0 && isspace( name[ n - 1 ] )) --n;
+ name.resize( n );
+ }
+
// get the file size
long filesize = theFile.size();
theFile.close();
- // Open the file
+ // Open the file
FILE* file = fopen( myFile.c_str(),"r");
// count the number of lines
Standard_Integer nbLines = 0;
- for (long ipos = 0; ipos < filesize; ++ipos) {
+ for (long ipos = 0; ipos < filesize; ++ipos)
+ {
if (getc(file) == '\n')
nbLines++;
}
// go back to the beginning of the file
rewind(file);
-
+
Standard_Integer nbTri = (nbLines / ASCII_LINES_PER_FACET);
TDataMapOfPntNodePtr uniqnodes;
while (getc(file) != '\n');
// main reading
- for (Standard_Integer iTri = 0; iTri < nbTri; ++iTri) {
-
+ for (Standard_Integer iTri = 0; iTri < nbTri; ++iTri)
+ {
// skipping the facet normal
Standard_ShortReal normal[3];
fscanf(file,"%*s %*s %f %f %f\n",&normal[0],&normal[1],&normal[2]);
long filesize = file.size();
- if ( (filesize - HEADER_SIZE) % SIZEOF_STL_FACET !=0
+ if ( (filesize - HEADER_SIZE) % SIZEOF_STL_FACET != 0
// Commented to allow reading small files (ex: 1 face)
/*|| (filesize < STL_MIN_FILE_SIZE)*/) {
Standard_NoMoreObject::Raise("DriverSTL_R_SMDS_MESH::readBinary (wrong file size)");
// sometimes it is wrong, and with this technique we don't need to swap endians for integer
Standard_Integer nbTri = ((filesize - HEADER_SIZE) / SIZEOF_STL_FACET);
+ // get a solid name
+ if ( strncmp( "name: ", file, strlen("name: ")) == 0 ) // name present
+ {
+ const char * header = file;
+ std::string& name = const_cast<std::string&>( myName );
+ header += strlen("name: ");
+ name.assign( header, HEADER_SIZE - strlen("name: ") - 4);
+
+ size_t n = name.size();
+ while ( n > 0 && isspace( name[ n - 1 ] )) --n;
+ name.resize( n );
+ }
+
// skip the header
file += HEADER_SIZE;
DriverSTL_R_SMDS_Mesh();
virtual Status Perform();
void SetIsCreateFaces( const bool theIsCreate = true );
+ std::string GetName() const { return myName; }
private:
// PRIVATE METHODS
- Status readAscii (SMESH_File& file) const;
- Status readBinary(SMESH_File& file) const;
-
+ Status readAscii (SMESH_File& file) const;
+ Status readBinary(SMESH_File& file) const;
+
private:
// PRIVATE FIELDS
- bool myIsCreateFaces;
- bool myIsAscii;
+ bool myIsCreateFaces;
+ bool myIsAscii;
+ std::string myName;
};
#endif
{
union {
Standard_ShortReal f;
- char c[4];
+ char c[4];
} u;
u.f = theVal;
SMESH_File aFile( myFile, /*openForReading=*/false );
aFile.openForWriting();
- std::string buf("solid\n");
+ std::string buf("solid ");
+ buf += myName + "\n";
aFile.writeRaw( buf.c_str(), buf.size() );
char sval[128];
" endfacet\n", 21 );
}
}
- aFile.writeRaw ("endsolid\n" , 9 );
+ buf = "endsolid " + myName + "\n";
+ aFile.writeRaw( buf.c_str(), buf.size() );
return aResult;
}
}
}
std::string sval( LABEL_SIZE, ' ' );
+ if ( !myName.empty() )
+ {
+ sval = "name: " + myName;
+ sval.resize( LABEL_SIZE, ' ' );
+ }
aFile.write( sval.c_str(), LABEL_SIZE );
// write number of triangles
~DriverSTL_W_SMDS_Mesh();
virtual Status Perform();
void SetIsAscii( const bool theIsAscii = false );
+ void SetName( const std::string name ) { myName = name; }
private:
// PRIVATE METHODS
private:
// PRIVATE FIELDS
- bool myIsAscii;
+ bool myIsAscii;
+ std::string myName;
int myNbVolumeTrias;
std::vector<const SMDS_MeshElement*> myVolumeFacets; // tmp faces
};
//purpose : Set volume to iterate on
//=======================================================================
-bool SMDS_VolumeTool::Set (const SMDS_MeshElement* theVolume,
- const bool ignoreCentralNodes)
+bool SMDS_VolumeTool::Set (const SMDS_MeshElement* theVolume,
+ const bool ignoreCentralNodes,
+ const std::vector<const SMDS_MeshNode*>* otherNodes)
{
// reset fields
myVolume = 0;
}
// set nodes
- int iNode = 0;
myVolumeNodes.resize( myVolume->NbNodes() );
- SMDS_ElemIteratorPtr nodeIt = myVolume->nodesIterator();
- while ( nodeIt->more() )
- myVolumeNodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
+ if ( otherNodes )
+ {
+ if ( otherNodes->size() != myVolumeNodes.size() )
+ return ( myVolume = 0 );
+ for ( size_t i = 0; i < otherNodes->size(); ++i )
+ if ( ! ( myVolumeNodes[i] = (*otherNodes)[0] ))
+ return ( myVolume = 0 );
+ }
+ else
+ {
+ int iNode = 0;
+ SMDS_ElemIteratorPtr nodeIt = myVolume->nodesIterator();
+ while ( nodeIt->more() )
+ myVolumeNodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
+ }
// check validity
if ( !setFace(0) )
SMDS_VolumeTool ();
~SMDS_VolumeTool ();
- SMDS_VolumeTool (const SMDS_MeshElement* theVolume,
- const bool ignoreCentralNodes=true);
+ SMDS_VolumeTool( const SMDS_MeshElement* theVolume,
+ const bool ignoreCentralNodes = true);
- bool Set (const SMDS_MeshElement* theVolume,
- const bool ignoreCentralNodes=true);
+ bool Set( const SMDS_MeshElement* theVolume,
+ const bool ignoreCentralNodes = true,
+ const std::vector<const SMDS_MeshNode*>* nodes = 0);
// Set volume.
// Return false if theVolume is not of type SMDSAbs_Volume.
// ignoreCentralNodes makes skip nodes at face centers when returning
- // nodes of faces of SMDSEntity_TriQuad_Hexa
+ // nodes of faces of SMDSEntity_TriQuad_Hexa.
+ // alternative nodes can be provided
const SMDS_MeshVolume* Element() const;
// return element
// top and bottom faces are reversed.
// Result of IsForward() and methods returning nodes change
- const SMDS_MeshNode** GetNodes() { return &myVolumeNodes[0]; }
+ const SMDS_MeshNode** GetNodes() const { return (const SMDS_MeshNode**) &myVolumeNodes[0]; }
// Return array of volume nodes
- int NbNodes() { return myVolumeNodes.size(); }
+ int NbNodes() const { return myVolumeNodes.size(); }
// Return array of volume nodes
double GetSize() const;
//purpose :
//=======================================================================
-int SMESH_Mesh::STLToMesh(const char* theFileName)
+std::string SMESH_Mesh::STLToMesh(const char* theFileName)
{
if(_isShapeToMesh)
throw SALOME_Exception(LOCALIZED("a shape to mesh has already been defined"));
myReader.SetMeshId(-1);
myReader.Perform();
- return 1;
+ return myReader.GetName();
}
//================================================================================
void SMESH_Mesh::ExportSTL(const char * file,
const bool isascii,
+ const char * name,
const SMESHDS_Mesh* meshPart) throw(SALOME_Exception)
{
Unexpect aCatch(SalomeException);
myWriter.SetIsAscii( isascii );
myWriter.SetMesh( meshPart ? (SMESHDS_Mesh*) meshPart : _myMeshDS);
myWriter.SetMeshId(_id);
+ if ( name ) myWriter.SetName( name );
myWriter.Perform();
}
int MEDToMesh(const char* theFileName, const char* theMeshName);
- int STLToMesh(const char* theFileName);
+ std::string STLToMesh(const char* theFileName);
int CGNSToMesh(const char* theFileName, const int theMeshIndex, std::string& theMeshName);
const SMESHDS_Mesh* meshPart = 0) throw(SALOME_Exception);
void ExportSTL(const char * file,
const bool isascii,
+ const char * name = 0,
const SMESHDS_Mesh* meshPart = 0) throw(SALOME_Exception);
void ExportCGNS(const char * file,
const SMESHDS_Mesh* mesh,
aPrms.push_back( aT );
}
//Extrusion_Error err =
- MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
+ makeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
} else if( aS.ShapeType() == TopAbs_WIRE ) {
list< SMESH_subMesh* > LSM;
TopTools_SequenceOfShape Edges;
}
list<SMESH_MeshEditor_PathPoint> LPP;
//Extrusion_Error err =
- MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
+ makeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
LLPPs.push_back(LPP);
UsedNums.Add(k);
// update startN for search following egde
return EXTR_BAD_PATH_SHAPE;
}
- return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
+ return makeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
theHasRefPoint, theRefPoint, theMakeGroups);
}
TopoDS_Edge e = BRepBuilderAPI_MakeEdge( p1, p2 );
list<SMESH_MeshEditor_PathPoint> LPP;
aPrms.clear();
- MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
+ 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();
aPrms.push_back( aT );
}
//Extrusion_Error err =
- MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
+ makeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
}
else if( aS.ShapeType() == TopAbs_WIRE ) {
list< SMESH_subMesh* > LSM;
}
list<SMESH_MeshEditor_PathPoint> LPP;
//Extrusion_Error err =
- MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
+ makeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
LLPPs.push_back(LPP);
UsedNums.Add(k);
// update startN for search following egde
return EXTR_BAD_PATH_SHAPE;
}
- return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
+ return makeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
theHasRefPoint, theRefPoint, theMakeGroups);
}
//=======================================================================
-//function : MakeEdgePathPoints
+//function : makeEdgePathPoints
//purpose : auxiliary for ExtrusionAlongTrack
//=======================================================================
SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
+SMESH_MeshEditor::makeEdgePathPoints(std::list<double>& aPrms,
const TopoDS_Edge& aTrackEdge,
bool FirstIsStart,
list<SMESH_MeshEditor_PathPoint>& LPP)
//=======================================================================
-//function : MakeExtrElements
+//function : makeExtrElements
//purpose : auxiliary for ExtrusionAlongTrack
//=======================================================================
SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets[2],
+SMESH_MeshEditor::makeExtrElements(TIDSortedElemSet theElemSets[2],
list<SMESH_MeshEditor_PathPoint>& fullList,
const bool theHasAngles,
list<double>& theAngles,
// Angles
if( theHasAngles && !theAngles.empty() && theLinearVariation )
- LinearAngleVariation(aNbTP-1, theAngles);
+ linearAngleVariation(aNbTP-1, theAngles);
// fill vector of path points with angles
vector<SMESH_MeshEditor_PathPoint> aPPs;
//=======================================================================
-//function : LinearAngleVariation
+//function : linearAngleVariation
//purpose : spread values over nbSteps
//=======================================================================
-void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
+void SMESH_MeshEditor::linearAngleVariation(const int nbSteps,
list<double>& Angles)
{
int nbAngles = Angles.size();
}
else
while ( nIt->more() )
- theNodes.insert( theNodes.end(),nIt->next() );
+ theNodes.insert( theNodes.end(), nIt->next() );
}
else if ( theSeparateCornersAndMedium ) // separate corners from medium nodes
{
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
- SMESHDS_Mesh* aMesh = GetMeshDS();
+ SMESHDS_Mesh* mesh = GetMeshDS();
TNodeNodeMap nodeNodeMap; // node to replace - new node
set<const SMDS_MeshElement*> elems; // all elements with changed nodes
list< int > rmElemIds, rmNodeIds;
+ vector< ElemFeatures > newElemDefs;
// Fill nodeNodeMap and elems
{
const SMDS_MeshNode* nToRemove = *nIt;
nodeNodeMap.insert( make_pair( nToRemove, nToKeep ));
- if ( nToRemove != nToKeep )
- {
- 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();
}
}
}
- // Change element nodes or remove an element
- set<const SMDS_MeshNode*> nodeSet;
- vector< const SMDS_MeshNode*> curNodes, uniqueNodes;
- vector<int> iRepl;
- ElemFeatures elemType;
+ // Apply recursive replacements (BUG 0020185)
+ TNodeNodeMap::iterator nnIt = nodeNodeMap.begin();
+ for ( ; nnIt != nodeNodeMap.end(); ++nnIt )
+ {
+ const SMDS_MeshNode* nToKeep = nnIt->second;
+ TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( nToKeep );
+ while ( nnIt_i != nodeNodeMap.end() && nnIt_i->second != nnIt->second )
+ nToKeep = nnIt_i->second;
+ nnIt->second = nToKeep;
+ }
+
+ if ( theAvoidMakingHoles )
+ {
+ // find elements whose topology changes
+
+ vector<const SMDS_MeshElement*> pbElems;
+ set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
+ for ( ; eIt != elems.end(); ++eIt )
+ {
+ const SMDS_MeshElement* elem = *eIt;
+ 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() && elem->GetNodeIndex( nnIt->second ) >= 0 )
+ {
+ // several nodes of elem stick
+ pbElems.push_back( elem );
+ break;
+ }
+ }
+ }
+ // exclude from merge nodes causing spoiling element
+ for ( size_t iLoop = 0; iLoop < pbElems.size(); ++iLoop ) // avoid infinite cycle
+ {
+ bool nodesExcluded = false;
+ for ( size_t i = 0; i < pbElems.size(); ++i )
+ {
+ size_t prevNbMergeNodes = nodeNodeMap.size();
+ if ( !applyMerge( pbElems[i], newElemDefs, nodeNodeMap, /*noHoles=*/true ) &&
+ prevNbMergeNodes < nodeNodeMap.size() )
+ nodesExcluded = true;
+ }
+ if ( !nodesExcluded )
+ break;
+ }
+ }
+
+ for ( nnIt = nodeNodeMap.begin(); nnIt != nodeNodeMap.end(); ++nnIt )
+ {
+ const SMDS_MeshNode* nToRemove = nnIt->first;
+ const SMDS_MeshNode* nToKeep = nnIt->second;
+ if ( nToRemove != nToKeep )
+ {
+ rmNodeIds.push_back( nToRemove->GetID() );
+ AddToSameGroups( nToKeep, nToRemove, mesh );
+ // set _alwaysComputed to a sub-mesh of VERTEX to enable further mesh computing
+ // w/o creating node in place of merged ones.
+ const SMDS_PositionPtr& pos = nToRemove->GetPosition();
+ if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX )
+ if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() ))
+ sm->SetIsAlwaysComputed( true );
+ }
+ }
+
+ // Change element nodes or remove an element
set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
for ( ; eIt != elems.end(); eIt++ )
{
const SMDS_MeshElement* elem = *eIt;
- const int nbNodes = elem->NbNodes();
- const int aShapeId = FindShape( elem );
- SMDSAbs_EntityType entity = elem->GetEntityType();
+ SMESHDS_SubMesh* sm = mesh->MeshElements( elem->getshapeId() );
- nodeSet.clear();
- curNodes.resize( nbNodes );
- uniqueNodes.resize( nbNodes );
- iRepl.resize( nbNodes );
- int iUnique = 0, iCur = 0, nbRepl = 0;
+ bool keepElem = applyMerge( elem, newElemDefs, nodeNodeMap, /*noHoles=*/false );
+ if ( !keepElem )
+ rmElemIds.push_back( elem->GetID() );
- // get new seq of nodes
- SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- while ( itN->more() )
- {
- const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( itN->next() );
-
- TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
- if ( nnIt != nodeNodeMap.end() ) { // n sticks
- n = (*nnIt).second;
- { ////////// BUG 0020185: begin
- bool stopRecur = false;
- set<const SMDS_MeshNode*> nodesRecur;
- nodesRecur.insert(n);
- while (!stopRecur) {
- TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
- if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
- n = (*nnIt_i).second;
- if (!nodesRecur.insert(n).second) {
- // error: recursive dependency
- stopRecur = true;
- }
- }
- else
- stopRecur = true;
- }
- } ////////// BUG 0020185: end
+ for ( size_t i = 0; i < newElemDefs.size(); ++i )
+ {
+ if ( i > 0 || !mesh->ChangeElementNodes( elem, &
+ newElemDefs[i].myNodes[0],
+ newElemDefs[i].myNodes.size() ))
+ {
+ if ( i == 0 )
+ {
+ newElemDefs[i].SetID( elem->GetID() );
+ mesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
+ if ( !keepElem ) rmElemIds.pop_back();
+ }
+ else
+ {
+ newElemDefs[i].SetID( -1 );
+ }
+ SMDS_MeshElement* newElem = this->AddElement( newElemDefs[i].myNodes, newElemDefs[i] );
+ if ( sm && newElem )
+ sm->AddElement( newElem );
+ if ( elem != newElem )
+ ReplaceElemInGroups( elem, newElem, mesh );
}
- curNodes[ iCur ] = n;
- bool isUnique = nodeSet.insert( n ).second;
- if ( isUnique )
- uniqueNodes[ iUnique++ ] = n;
- else
- iRepl[ nbRepl++ ] = iCur;
- iCur++;
}
+ }
- // Analyse element topology after replacement
+ // Remove bad elements, then equal nodes (order important)
+ Remove( rmElemIds, false );
+ Remove( rmNodeIds, true );
- bool isOk = true;
- int nbUniqueNodes = nodeSet.size();
- if ( nbNodes != nbUniqueNodes ) // some nodes stick
- {
- 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 );
-
- // 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 ));
+ return;
+}
- SMDS_MeshElement* newElem = AddElement( face_nodes, elemType.SetID(-1));
- if ( aShapeId )
- aMesh->SetMeshElementOnShape(newElem, aShapeId);
- }
- }
- rmElemIds.push_back(elem->GetID());
+//=======================================================================
+//function : applyMerge
+//purpose : Compute new connectivity of an element after merging nodes
+// \param [in] elems - the element
+// \param [out] newElemDefs - definition(s) of result element(s)
+// \param [inout] nodeNodeMap - nodes to merge
+// \param [in] avoidMakingHoles - if true and and the element becomes invalid
+// after merging (but not degenerated), removes nodes causing
+// the invalidity from \a nodeNodeMap.
+// \return bool - true if the element should be removed
+//=======================================================================
- } // Polygon
+bool SMESH_MeshEditor::applyMerge( const SMDS_MeshElement* elem,
+ vector< ElemFeatures >& newElemDefs,
+ TNodeNodeMap& nodeNodeMap,
+ const bool avoidMakingHoles )
+{
+ bool toRemove = false; // to remove elem
+ int nbResElems = 1; // nb new elements
- else if ( elem->GetType() == SMDSAbs_Volume ) // Polyhedral volume
- {
- if ( nbUniqueNodes < 4 ) {
- rmElemIds.push_back(elem->GetID());
- }
- else {
- // each face has to be analyzed in order to check volume validity
- const SMDS_VtkVolume* aPolyedre = dynamic_cast<const SMDS_VtkVolume*>( elem );
- if ( aPolyedre )
- {
- int nbFaces = aPolyedre->NbFaces();
+ newElemDefs.resize(nbResElems);
+ newElemDefs[0].Init( elem );
+ newElemDefs[0].myNodes.clear();
- vector<const SMDS_MeshNode *> poly_nodes;
- vector<int> quantities;
- vector<const SMDS_MeshNode *> faceNodes;
+ set<const SMDS_MeshNode*> nodeSet;
+ vector< const SMDS_MeshNode*> curNodes;
+ vector< const SMDS_MeshNode*> & uniqueNodes = newElemDefs[0].myNodes;
+ vector<int> iRepl;
- for (int iface = 1; iface <= nbFaces; iface++)
- {
- int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
- faceNodes.resize( nbFaceNodes );
- for (int inode = 1; inode <= nbFaceNodes; inode++)
- {
- const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
- TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
- if ( nnIt != nodeNodeMap.end() ) // faceNode sticks
- faceNode = (*nnIt).second;
- faceNodes[inode - 1] = faceNode;
- }
- SimplifyFace(faceNodes, poly_nodes, quantities);
- }
+ const int nbNodes = elem->NbNodes();
+ SMDSAbs_EntityType entity = elem->GetEntityType();
- if ( quantities.size() > 3 ) {
- // TODO: remove coincident faces
- }
+ curNodes.resize( nbNodes );
+ uniqueNodes.resize( nbNodes );
+ iRepl.resize( nbNodes );
+ int iUnique = 0, iCur = 0, nbRepl = 0;
- if ( quantities.size() > 3 )
- {
- 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() );
- }
- }
- }
- else {
- }
+ // Get new seq of nodes
- continue;
- } // poly element
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() )
+ {
+ const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( itN->next() );
- // Regular elements
- // TODO not all the possible cases are solved. Find something more generic?
- switch ( entity ) {
- case SMDSEntity_Edge: //////// EDGE
- case SMDSEntity_Triangle: //// TRIANGLE
- case SMDSEntity_Quad_Triangle:
- case SMDSEntity_Tetra:
- case SMDSEntity_Quad_Tetra: // TETRAHEDRON
- {
- isOk = false;
- break;
- }
- case SMDSEntity_Quad_Edge:
- {
- isOk = false; // to linear EDGE ???????
- break;
- }
- case SMDSEntity_Quadrangle: //////////////////////////////////// QUADRANGLE
+ TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
+ if ( nnIt != nodeNodeMap.end() ) {
+ n = (*nnIt).second;
+ }
+ curNodes[ iCur ] = n;
+ bool isUnique = nodeSet.insert( n ).second;
+ if ( isUnique )
+ uniqueNodes[ iUnique++ ] = n;
+ else
+ iRepl[ nbRepl++ ] = iCur;
+ iCur++;
+ }
+
+ // Analyse element topology after replacement
+
+ int nbUniqueNodes = nodeSet.size();
+ if ( nbNodes != nbUniqueNodes ) // some nodes stick
+ {
+ toRemove = true;
+ nbResElems = 0;
+
+ switch ( entity )
+ {
+ case SMDSEntity_Polygon:
+ case SMDSEntity_Quad_Polygon: // Polygon
+ {
+ ElemFeatures* elemType = & newElemDefs[0];
+ const bool isQuad = elemType->myIsQuad;
+ if ( isQuad )
+ SMDS_MeshCell::applyInterlace // interlace medium and corner nodes
+ ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, nbNodes ), curNodes );
+
+ // a polygon can divide into several elements
+ vector<const SMDS_MeshNode *> polygons_nodes;
+ vector<int> quantities;
+ nbResElems = SimplifyFace( curNodes, polygons_nodes, quantities );
+ newElemDefs.resize( nbResElems );
+ for ( int inode = 0, iface = 0; iface < nbResElems; iface++ )
{
- if ( nbUniqueNodes < 3 )
- isOk = false;
- else if ( nbRepl == 1 && curNodes[ iRepl[0]] == curNodes[( iRepl[0]+2 )%4 ])
- isOk = false; // opposite nodes stick
- break;
- }
- case SMDSEntity_Quad_Quadrangle: // Quadratic QUADRANGLE
- {
- // 1 5 2
- // +---+---+
- // | |
- // 4+ +6
- // | |
- // +---+---+
- // 0 7 3
- if (( nbUniqueNodes == 6 && nbRepl == 2 ) &&
- (( iRepl[0] == 1 && iRepl[1] == 4 && curNodes[1] == curNodes[0] ) ||
- ( iRepl[0] == 2 && iRepl[1] == 5 && curNodes[2] == curNodes[1] ) ||
- ( iRepl[0] == 3 && iRepl[1] == 6 && curNodes[3] == curNodes[2] ) ||
- ( iRepl[0] == 3 && iRepl[1] == 7 && curNodes[3] == curNodes[0] )))
- {
- isOk = true;
- }
- break;
- }
- case SMDSEntity_BiQuad_Quadrangle: // Bi-Quadratic QUADRANGLE
- {
- // 1 5 2
- // +---+---+
- // | |
- // 4+ 8+ +6
- // | |
- // +---+---+
- // 0 7 3
- if (( nbUniqueNodes == 7 && nbRepl == 2 && iRepl[1] != 8 ) &&
- (( iRepl[0] == 1 && iRepl[1] == 4 && curNodes[1] == curNodes[0] ) ||
- ( iRepl[0] == 2 && iRepl[1] == 5 && curNodes[2] == curNodes[1] ) ||
- ( iRepl[0] == 3 && iRepl[1] == 6 && curNodes[3] == curNodes[2] ) ||
- ( iRepl[0] == 3 && iRepl[1] == 7 && curNodes[3] == curNodes[0] )))
+ ElemFeatures* elemType = & newElemDefs[iface];
+ if ( iface ) elemType->Init( elem );
+
+ vector<const SMDS_MeshNode *>& face_nodes = elemType->myNodes;
+ int nbNewNodes = quantities[iface];
+ face_nodes.assign( polygons_nodes.begin() + inode,
+ polygons_nodes.begin() + inode + nbNewNodes );
+ inode += nbNewNodes;
+ if ( isQuad ) // check if a result elem is a valid quadratic polygon
{
- isOk = true;
- }
- break;
- }
- case SMDSEntity_Penta: ///////////////////////////////////// PENTAHEDRON
+ bool isValid = ( nbNewNodes % 2 == 0 );
+ for ( int i = 0; i < nbNewNodes && isValid; ++i )
+ isValid = ( elem->IsMediumNode( face_nodes[i]) == bool( i % 2 ));
+ elemType->SetQuad( isValid );
+ if ( isValid ) // put medium nodes after corners
+ SMDS_MeshCell::applyInterlaceRev
+ ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon,
+ nbNewNodes ), face_nodes );
+ }
+ elemType->SetPoly(( nbNewNodes / ( elemType->myIsQuad + 1 ) > 4 ));
+ }
+ nbUniqueNodes = newElemDefs[0].myNodes.size();
+ break;
+ } // Polygon
+
+ case SMDSEntity_Polyhedra: // Polyhedral volume
+ {
+ if ( nbUniqueNodes >= 4 )
{
- isOk = false;
- if ( nbUniqueNodes == 4 ) {
- // ---------------------------------> tetrahedron
- if ( curNodes[3] == curNodes[4] &&
- curNodes[3] == curNodes[5] ) {
- // top nodes stick
- isOk = true;
- }
- else if ( curNodes[0] == curNodes[1] &&
- curNodes[0] == curNodes[2] ) {
- // bottom nodes stick: set a top before
- uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
- uniqueNodes[ 0 ] = curNodes [ 5 ];
- uniqueNodes[ 1 ] = curNodes [ 4 ];
- uniqueNodes[ 2 ] = curNodes [ 3 ];
- isOk = true;
- }
- else if (( curNodes[0] == curNodes[3] ) +
- ( curNodes[1] == curNodes[4] ) +
- ( curNodes[2] == curNodes[5] ) == 2 ) {
- // a lateral face turns into a line
- isOk = true;
- }
- }
- else if ( nbUniqueNodes == 5 ) {
- // PENTAHEDRON --------------------> pyramid
- if ( curNodes[0] == curNodes[3] )
- {
- uniqueNodes[ 0 ] = curNodes[ 1 ];
- uniqueNodes[ 1 ] = curNodes[ 4 ];
- uniqueNodes[ 2 ] = curNodes[ 5 ];
- uniqueNodes[ 3 ] = curNodes[ 2 ];
- uniqueNodes[ 4 ] = curNodes[ 0 ];
- isOk = true;
- }
- if ( curNodes[1] == curNodes[4] )
+ // each face has to be analyzed in order to check volume validity
+ if ( const SMDS_VtkVolume* aPolyedre = dynamic_cast<const SMDS_VtkVolume*>( elem ))
+ {
+ int nbFaces = aPolyedre->NbFaces();
+
+ vector<const SMDS_MeshNode *>& poly_nodes = newElemDefs[0].myNodes;
+ vector<int> & quantities = newElemDefs[0].myPolyhedQuantities;
+ vector<const SMDS_MeshNode *> faceNodes;
+ poly_nodes.clear();
+ quantities.clear();
+
+ for (int iface = 1; iface <= nbFaces; iface++)
{
- uniqueNodes[ 0 ] = curNodes[ 0 ];
- uniqueNodes[ 1 ] = curNodes[ 2 ];
- uniqueNodes[ 2 ] = curNodes[ 5 ];
- uniqueNodes[ 3 ] = curNodes[ 3 ];
- uniqueNodes[ 4 ] = curNodes[ 1 ];
- isOk = true;
+ int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
+ faceNodes.resize( nbFaceNodes );
+ for (int inode = 1; inode <= nbFaceNodes; inode++)
+ {
+ const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
+ TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
+ if ( nnIt != nodeNodeMap.end() ) // faceNode sticks
+ faceNode = (*nnIt).second;
+ faceNodes[inode - 1] = faceNode;
+ }
+ SimplifyFace(faceNodes, poly_nodes, quantities);
}
- if ( curNodes[2] == curNodes[5] )
+
+ if ( quantities.size() > 3 )
{
- uniqueNodes[ 0 ] = curNodes[ 0 ];
- uniqueNodes[ 1 ] = curNodes[ 3 ];
- uniqueNodes[ 2 ] = curNodes[ 4 ];
- uniqueNodes[ 3 ] = curNodes[ 1 ];
- uniqueNodes[ 4 ] = curNodes[ 2 ];
- isOk = true;
+ // TODO: remove coincident faces
+ nbResElems = 1;
+ nbUniqueNodes = newElemDefs[0].myNodes.size();
}
}
- break;
}
- case SMDSEntity_Hexa:
+ }
+ break;
+
+ // Regular elements
+ // TODO not all the possible cases are solved. Find something more generic?
+ case SMDSEntity_Edge: //////// EDGE
+ case SMDSEntity_Triangle: //// TRIANGLE
+ case SMDSEntity_Quad_Triangle:
+ case SMDSEntity_Tetra:
+ case SMDSEntity_Quad_Tetra: // TETRAHEDRON
+ {
+ break;
+ }
+ case SMDSEntity_Quad_Edge:
+ {
+ break;
+ }
+ case SMDSEntity_Quadrangle: //////////////////////////////////// QUADRANGLE
+ {
+ if ( nbUniqueNodes < 3 )
+ toRemove = true;
+ else if ( nbRepl == 1 && curNodes[ iRepl[0]] == curNodes[( iRepl[0]+2 )%4 ])
+ toRemove = true; // opposite nodes stick
+ else
+ toRemove = false;
+ break;
+ }
+ case SMDSEntity_Quad_Quadrangle: // Quadratic QUADRANGLE
+ {
+ // 1 5 2
+ // +---+---+
+ // | |
+ // 4+ +6
+ // | |
+ // +---+---+
+ // 0 7 3
+ if (( nbUniqueNodes == 6 && nbRepl == 2 ) &&
+ (( iRepl[0] == 1 && iRepl[1] == 4 && curNodes[1] == curNodes[0] ) ||
+ ( iRepl[0] == 2 && iRepl[1] == 5 && curNodes[2] == curNodes[1] ) ||
+ ( iRepl[0] == 3 && iRepl[1] == 6 && curNodes[3] == curNodes[2] ) ||
+ ( iRepl[0] == 3 && iRepl[1] == 7 && curNodes[3] == curNodes[0] )))
{
- //////////////////////////////////// HEXAHEDRON
- isOk = false;
- SMDS_VolumeTool hexa (elem);
- hexa.SetExternalNormal();
- if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
- //////////////////////// HEX ---> tetrahedron
- for ( int iFace = 0; iFace < 6; iFace++ ) {
- const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
- if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
- curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
- curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
- // one face turns into a point ...
- int pickInd = ind[ 0 ];
- int iOppFace = hexa.GetOppFaceIndex( iFace );
- ind = hexa.GetFaceNodesIndices( iOppFace );
- int nbStick = 0;
- uniqueNodes.clear();
- for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
- if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
- nbStick++;
- else
- uniqueNodes.push_back( curNodes[ind[ iCur ]]);
- }
- if ( nbStick == 1 ) {
- // ... and the opposite one - into a triangle.
- // set a top node
- uniqueNodes.push_back( curNodes[ pickInd ]);
- isOk = true;
- }
- break;
- }
- }
+ toRemove = false;
+ }
+ break;
+ }
+ case SMDSEntity_BiQuad_Quadrangle: // Bi-Quadratic QUADRANGLE
+ {
+ // 1 5 2
+ // +---+---+
+ // | |
+ // 4+ 8+ +6
+ // | |
+ // +---+---+
+ // 0 7 3
+ if (( nbUniqueNodes == 7 && nbRepl == 2 && iRepl[1] != 8 ) &&
+ (( iRepl[0] == 1 && iRepl[1] == 4 && curNodes[1] == curNodes[0] ) ||
+ ( iRepl[0] == 2 && iRepl[1] == 5 && curNodes[2] == curNodes[1] ) ||
+ ( iRepl[0] == 3 && iRepl[1] == 6 && curNodes[3] == curNodes[2] ) ||
+ ( iRepl[0] == 3 && iRepl[1] == 7 && curNodes[3] == curNodes[0] )))
+ {
+ toRemove = false;
+ }
+ break;
+ }
+ case SMDSEntity_Penta: ///////////////////////////////////// PENTAHEDRON
+ {
+ if ( nbUniqueNodes == 4 ) {
+ // ---------------------------------> tetrahedron
+ if ( curNodes[3] == curNodes[4] &&
+ curNodes[3] == curNodes[5] ) {
+ // top nodes stick
+ toRemove = false;
+ }
+ else if ( curNodes[0] == curNodes[1] &&
+ curNodes[0] == curNodes[2] ) {
+ // bottom nodes stick: set a top before
+ uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
+ uniqueNodes[ 0 ] = curNodes [ 5 ];
+ uniqueNodes[ 1 ] = curNodes [ 4 ];
+ uniqueNodes[ 2 ] = curNodes [ 3 ];
+ toRemove = false;
+ }
+ else if (( curNodes[0] == curNodes[3] ) +
+ ( curNodes[1] == curNodes[4] ) +
+ ( curNodes[2] == curNodes[5] ) == 2 ) {
+ // a lateral face turns into a line
+ toRemove = false;
+ }
+ }
+ else if ( nbUniqueNodes == 5 ) {
+ // PENTAHEDRON --------------------> pyramid
+ if ( curNodes[0] == curNodes[3] )
+ {
+ uniqueNodes[ 0 ] = curNodes[ 1 ];
+ uniqueNodes[ 1 ] = curNodes[ 4 ];
+ uniqueNodes[ 2 ] = curNodes[ 5 ];
+ uniqueNodes[ 3 ] = curNodes[ 2 ];
+ uniqueNodes[ 4 ] = curNodes[ 0 ];
+ toRemove = false;
+ }
+ if ( curNodes[1] == curNodes[4] )
+ {
+ uniqueNodes[ 0 ] = curNodes[ 0 ];
+ uniqueNodes[ 1 ] = curNodes[ 2 ];
+ uniqueNodes[ 2 ] = curNodes[ 5 ];
+ uniqueNodes[ 3 ] = curNodes[ 3 ];
+ uniqueNodes[ 4 ] = curNodes[ 1 ];
+ toRemove = false;
+ }
+ if ( curNodes[2] == curNodes[5] )
+ {
+ uniqueNodes[ 0 ] = curNodes[ 0 ];
+ uniqueNodes[ 1 ] = curNodes[ 3 ];
+ uniqueNodes[ 2 ] = curNodes[ 4 ];
+ uniqueNodes[ 3 ] = curNodes[ 1 ];
+ uniqueNodes[ 4 ] = curNodes[ 2 ];
+ toRemove = false;
}
- else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
- //////////////////////// HEX ---> prism
- int nbTria = 0, iTria[3];
- const int *ind; // indices of face nodes
- // look for triangular faces
- for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
- ind = hexa.GetFaceNodesIndices( iFace );
- TIDSortedNodeSet faceNodes;
- for ( iCur = 0; iCur < 4; iCur++ )
- faceNodes.insert( curNodes[ind[iCur]] );
- if ( faceNodes.size() == 3 )
- iTria[ nbTria++ ] = iFace;
- }
- // check if triangles are opposite
- if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
- {
- // set nodes of the bottom triangle
- ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
- vector<int> indB;
- for ( iCur = 0; iCur < 4; iCur++ )
- if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
- indB.push_back( ind[iCur] );
- if ( !hexa.IsForward() )
- std::swap( indB[0], indB[2] );
- for ( iCur = 0; iCur < 3; iCur++ )
- uniqueNodes[ iCur ] = curNodes[indB[iCur]];
- // set nodes of the top triangle
- const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
- for ( iCur = 0; iCur < 3; ++iCur )
- for ( int j = 0; j < 4; ++j )
- if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
- {
- uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
- break;
- }
- isOk = true;
+ }
+ break;
+ }
+ case SMDSEntity_Hexa:
+ {
+ //////////////////////////////////// HEXAHEDRON
+ SMDS_VolumeTool hexa (elem);
+ hexa.SetExternalNormal();
+ if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
+ //////////////////////// HEX ---> tetrahedron
+ for ( int iFace = 0; iFace < 6; iFace++ ) {
+ const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
+ if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
+ curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
+ curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
+ // one face turns into a point ...
+ int pickInd = ind[ 0 ];
+ int iOppFace = hexa.GetOppFaceIndex( iFace );
+ ind = hexa.GetFaceNodesIndices( iOppFace );
+ int nbStick = 0;
+ uniqueNodes.clear();
+ for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
+ if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
+ nbStick++;
+ else
+ uniqueNodes.push_back( curNodes[ind[ iCur ]]);
+ }
+ if ( nbStick == 1 ) {
+ // ... and the opposite one - into a triangle.
+ // set a top node
+ uniqueNodes.push_back( curNodes[ pickInd ]);
+ toRemove = false;
+ }
break;
}
}
- else if (nbUniqueNodes == 5 && nbRepl == 3 ) {
- //////////////////// HEXAHEDRON ---> pyramid
- for ( int iFace = 0; iFace < 6; iFace++ ) {
- const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
- if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
- curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
- curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
- // one face turns into a point ...
- int iOppFace = hexa.GetOppFaceIndex( iFace );
- ind = hexa.GetFaceNodesIndices( iOppFace );
- uniqueNodes.clear();
- for ( iCur = 0; iCur < 4; iCur++ ) {
- if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
- break;
- else
- uniqueNodes.push_back( curNodes[ind[ iCur ]]);
- }
- if ( uniqueNodes.size() == 4 ) {
- // ... and the opposite one is a quadrangle
- // set a top node
- const int* indTop = hexa.GetFaceNodesIndices( iFace );
- uniqueNodes.push_back( curNodes[indTop[ 0 ]]);
- isOk = true;
+ }
+ else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
+ //////////////////////// HEX ---> prism
+ int nbTria = 0, iTria[3];
+ const int *ind; // indices of face nodes
+ // look for triangular faces
+ for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
+ ind = hexa.GetFaceNodesIndices( iFace );
+ TIDSortedNodeSet faceNodes;
+ for ( iCur = 0; iCur < 4; iCur++ )
+ faceNodes.insert( curNodes[ind[iCur]] );
+ if ( faceNodes.size() == 3 )
+ iTria[ nbTria++ ] = iFace;
+ }
+ // check if triangles are opposite
+ if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
+ {
+ // set nodes of the bottom triangle
+ ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
+ vector<int> indB;
+ for ( iCur = 0; iCur < 4; iCur++ )
+ if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
+ indB.push_back( ind[iCur] );
+ if ( !hexa.IsForward() )
+ std::swap( indB[0], indB[2] );
+ for ( iCur = 0; iCur < 3; iCur++ )
+ uniqueNodes[ iCur ] = curNodes[indB[iCur]];
+ // set nodes of the top triangle
+ const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
+ for ( iCur = 0; iCur < 3; ++iCur )
+ for ( int j = 0; j < 4; ++j )
+ if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
+ {
+ uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
+ break;
}
- break;
+ toRemove = false;
+ break;
+ }
+ }
+ else if (nbUniqueNodes == 5 && nbRepl == 3 ) {
+ //////////////////// HEXAHEDRON ---> pyramid
+ for ( int iFace = 0; iFace < 6; iFace++ ) {
+ const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
+ if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
+ curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
+ curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
+ // one face turns into a point ...
+ int iOppFace = hexa.GetOppFaceIndex( iFace );
+ ind = hexa.GetFaceNodesIndices( iOppFace );
+ uniqueNodes.clear();
+ for ( iCur = 0; iCur < 4; iCur++ ) {
+ if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
+ break;
+ else
+ uniqueNodes.push_back( curNodes[ind[ iCur ]]);
}
+ if ( uniqueNodes.size() == 4 ) {
+ // ... and the opposite one is a quadrangle
+ // set a top node
+ const int* indTop = hexa.GetFaceNodesIndices( iFace );
+ uniqueNodes.push_back( curNodes[indTop[ 0 ]]);
+ toRemove = false;
+ }
+ break;
}
}
+ }
- if ( !isOk && nbUniqueNodes > 4 ) {
- ////////////////// HEXAHEDRON ---> polyhedron
- hexa.SetExternalNormal();
- vector<const SMDS_MeshNode *> poly_nodes; poly_nodes.reserve( 6 * 4 );
- vector<int> quantities; quantities.reserve( 6 );
- for ( int iFace = 0; iFace < 6; iFace++ )
+ if ( toRemove && nbUniqueNodes > 4 ) {
+ ////////////////// HEXAHEDRON ---> polyhedron
+ hexa.SetExternalNormal();
+ vector<const SMDS_MeshNode *>& poly_nodes = newElemDefs[0].myNodes;
+ vector<int> & quantities = newElemDefs[0].myPolyhedQuantities;
+ poly_nodes.reserve( 6 * 4 ); poly_nodes.clear();
+ quantities.reserve( 6 ); quantities.clear();
+ for ( int iFace = 0; iFace < 6; iFace++ )
+ {
+ const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
+ if ( curNodes[ind[0]] == curNodes[ind[2]] ||
+ curNodes[ind[1]] == curNodes[ind[3]] )
{
- const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
- if ( curNodes[ind[0]] == curNodes[ind[2]] ||
- curNodes[ind[1]] == curNodes[ind[3]] )
- {
- quantities.clear();
- break; // opposite nodes stick
- }
- nodeSet.clear();
- for ( iCur = 0; iCur < 4; iCur++ )
- {
- if ( nodeSet.insert( curNodes[ind[ iCur ]] ).second )
- poly_nodes.push_back( curNodes[ind[ iCur ]]);
- }
- if ( nodeSet.size() < 3 )
- poly_nodes.resize( poly_nodes.size() - nodeSet.size() );
- else
- quantities.push_back( nodeSet.size() );
+ quantities.clear();
+ break; // opposite nodes stick
}
- if ( quantities.size() >= 4 )
+ nodeSet.clear();
+ for ( iCur = 0; iCur < 4; iCur++ )
{
- const SMDS_MeshElement* newElem = aMesh->AddPolyhedralVolume( poly_nodes, quantities );
- myLastCreatedElems.Append( newElem );
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- rmElemIds.push_back( elem->GetID() );
+ if ( nodeSet.insert( curNodes[ind[ iCur ]] ).second )
+ poly_nodes.push_back( curNodes[ind[ iCur ]]);
}
+ if ( nodeSet.size() < 3 )
+ poly_nodes.resize( poly_nodes.size() - nodeSet.size() );
+ else
+ quantities.push_back( nodeSet.size() );
}
- break;
- } // case HEXAHEDRON
+ if ( quantities.size() >= 4 )
+ {
+ nbResElems = 1;
+ nbUniqueNodes = poly_nodes.size();
+ newElemDefs[0].SetPoly(true);
+ }
+ }
+ break;
+ } // case HEXAHEDRON
- default:
- isOk = false;
- } // switch ( nbNodes )
+ default:
+ toRemove = true;
- } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
+ } // switch ( entity )
- if ( isOk ) // a non-poly elem remains valid after sticking nodes
+ if ( toRemove && nbResElems == 0 && avoidMakingHoles )
{
- if ( nbNodes != nbUniqueNodes ||
- !aMesh->ChangeElementNodes( elem, & curNodes[0], nbNodes ))
- {
- elemType.Init( elem ).SetID( elem->GetID() );
-
- SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
- aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
-
- uniqueNodes.resize(nbUniqueNodes);
- SMDS_MeshElement* newElem = this->AddElement( uniqueNodes, elemType );
- if ( sm && newElem )
- sm->AddElement( newElem );
- if ( elem != newElem )
- ReplaceElemInGroups( elem, newElem, aMesh );
- }
- }
- else {
- // Remove invalid regular element or invalid polygon
- rmElemIds.push_back( elem->GetID() );
+ // erase from nodeNodeMap nodes whose merge spoils elem
+ vector< const SMDS_MeshNode* > noMergeNodes;
+ SMESH_MeshAlgos::DeMerge( elem, curNodes, noMergeNodes );
+ for ( size_t i = 0; i < noMergeNodes.size(); ++i )
+ nodeNodeMap.erase( noMergeNodes[i] );
}
+
+ } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
- } // loop on elements
+ uniqueNodes.resize( nbUniqueNodes );
- // Remove bad elements, then equal nodes (order important)
+ if ( !toRemove && nbResElems == 0 )
+ nbResElems = 1;
- Remove( rmElemIds, false );
- Remove( rmNodeIds, true );
+ newElemDefs.resize( nbResElems );
- return;
+ return !toRemove;
}
// --------------------------------------------------------------------------------
struct ElemFeatures //!< Features of element to create
{
- SMDSAbs_ElementType myType;
- bool myIsPoly, myIsQuad;
- int myID;
- double myBallDiameter;
- std::vector<int> myPolyhedQuantities;
+ SMDSAbs_ElementType myType;
+ bool myIsPoly, myIsQuad;
+ int myID;
+ double myBallDiameter;
+ std::vector<int> myPolyhedQuantities;
+ std::vector<const SMDS_MeshNode*> myNodes; // not managed by ElemFeatures
SMESH_EXPORT ElemFeatures( SMDSAbs_ElementType type=SMDSAbs_All, bool isPoly=false, bool isQuad=false )
:myType( type ), myIsPoly(isPoly), myIsQuad(isQuad), myID(-1), myBallDiameter(0) {}
const size_t nbSteps,
SMESH_SequenceOfElemPtr& srcElements);
+ /*!
+ * \brief Computes new connectivity of an element after merging nodes
+ * \param [in] elems - the element
+ * \param [out] newElemDefs - definition(s) of result element(s)
+ * \param [inout] nodeNodeMap - nodes to merge
+ * \param [in] avoidMakingHoles - if true and and the element becomes invalid
+ * after merging (but not degenerated), removes nodes causing
+ * the invalidity from \a nodeNodeMap.
+ * \return bool - true if the element should be removed
+ */
+ bool applyMerge( const SMDS_MeshElement* elems,
+ std::vector< ElemFeatures >& newElemDefs,
+ TNodeNodeMap& nodeNodeMap,
+ const bool avoidMakingHoles );
/*!
* \brief Create 1D and 2D elements around swept elements
* \param mapNewNodes - source nodes and ones generated from them
double Angle ()const { return myAngle; }
double Parameter ()const { return myPrm; }
};
- Extrusion_Error MakeEdgePathPoints(std::list<double>& aPrms,
+ Extrusion_Error makeEdgePathPoints(std::list<double>& aPrms,
const TopoDS_Edge& aTrackEdge,
bool aFirstIsStart,
std::list<SMESH_MeshEditor_PathPoint>& aLPP);
- Extrusion_Error MakeExtrElements(TIDSortedElemSet theElements[2],
+ Extrusion_Error makeExtrElements(TIDSortedElemSet theElements[2],
std::list<SMESH_MeshEditor_PathPoint>& theFullList,
const bool theHasAngles,
std::list<double>& theAngles,
const bool theHasRefPoint,
const gp_Pnt& theRefPoint,
const bool theMakeGroups);
- static void LinearAngleVariation(const int NbSteps,
+ static void linearAngleVariation(const int NbSteps,
std::list<double>& theAngles);
bool doubleNodes( SMESHDS_Mesh* theMeshDS,
QStringList filter;
std::string myExtension;
- if ( theCommandID == SMESHOp::OpImportMED ) {
+ if ( theCommandID == SMESHOp::OpImportMED ||
+ theCommandID == SMESHOp::OpPopupImportMED ) {
filter.append( QObject::tr( "MED_FILES_FILTER" ) + " (*.*med)" );
filter.append( QObject::tr( "ALL_FILES_FILTER" ) + " (*)" );
}
- else if ( theCommandID == SMESHOp::OpImportUNV ) {
+ else if ( theCommandID == SMESHOp::OpImportUNV ||
+ theCommandID == SMESHOp::OpPopupImportUNV ) {
filter.append( QObject::tr( "IDEAS_FILES_FILTER" ) + " (*.unv)" );
}
- else if ( theCommandID == SMESHOp::OpImportDAT ) {
+ else if ( theCommandID == SMESHOp::OpImportDAT ||
+ theCommandID == SMESHOp::OpPopupImportDAT ) {
filter.append( QObject::tr( "DAT_FILES_FILTER" ) + " (*.dat)" );
}
- else if ( theCommandID == SMESHOp::OpImportSTL ) {
+ else if ( theCommandID == SMESHOp::OpImportSTL ||
+ theCommandID == SMESHOp::OpPopupImportSTL ) {
filter.append( QObject::tr( "STL_FILES_FILTER" ) + " (*.stl)" );
}
- #ifdef WITH_CGNS
- else if ( theCommandID == SMESHOp::OpImportCGNS ) {
+ else if ( theCommandID == SMESHOp::OpImportCGNS ||
+ theCommandID == SMESHOp::OpPopupImportCGNS ) {
filter.append( QObject::tr( "CGNS_FILES_FILTER" ) + " (*.cgns)" );
}
- #endif
- else if ( theCommandID == SMESHOp::OpImportSAUV ) {
+ else if ( theCommandID == SMESHOp::OpImportSAUV ||
+ theCommandID == SMESHOp::OpPopupImportSAUV ) {
filter.append( QObject::tr( "SAUV files (*.sauv*)" ) );
filter.append( QObject::tr( "All files (*)" ) );
}
- else if ( theCommandID == SMESHOp::OpImportGMF ) {
+ else if ( theCommandID == SMESHOp::OpImportGMF ||
+ theCommandID == SMESHOp::OpPopupImportGMF ) {
filter.append( QObject::tr( "GMF_ASCII_FILES_FILTER" ) + " (*.mesh)" );
filter.append( QObject::tr( "GMF_BINARY_FILES_FILTER") + " (*.meshb)" );
}
try {
switch ( theCommandID ) {
case SMESHOp::OpImportDAT:
+ case SMESHOp::OpPopupImportDAT:
{
// DAT format (currently unsupported)
errors.append( QString( "%1 :\n\t%2" ).arg( filename ).
break;
}
case SMESHOp::OpImportUNV:
+ case SMESHOp::OpPopupImportUNV:
{
// UNV format
aMeshes->length( 1 );
break;
}
case SMESHOp::OpImportMED:
+ case SMESHOp::OpPopupImportMED:
{
// MED format
SMESH::DriverMED_ReadStatus res;
break;
}
case SMESHOp::OpImportSTL:
+ case SMESHOp::OpPopupImportSTL:
{
// STL format
aMeshes->length( 1 );
}
break;
}
- #ifdef WITH_CGNS
case SMESHOp::OpImportCGNS:
+ case SMESHOp::OpPopupImportCGNS:
{
// CGNS format
SMESH::DriverMED_ReadStatus res;
}
break;
}
- #endif
case SMESHOp::OpImportSAUV:
+ case SMESHOp::OpPopupImportSAUV:
{
// SAUV format
SMESH::DriverMED_ReadStatus res;
break;
}
case SMESHOp::OpImportGMF:
+ case SMESHOp::OpPopupImportGMF:
{
// GMF format
SMESH::ComputeError_var res;
theCommandID == SMESHOp::OpPopupExportUNV );
const bool isSTL = ( theCommandID == SMESHOp::OpExportSTL ||
theCommandID == SMESHOp::OpPopupExportSTL );
-#ifdef WITH_CGNS
const bool isCGNS= ( theCommandID == SMESHOp::OpExportCGNS ||
theCommandID == SMESHOp::OpPopupExportCGNS );
-#else
- const bool isCGNS= false;
-#endif
const bool isSAUV= ( theCommandID == SMESHOp::OpExportSAUV ||
theCommandID == SMESHOp::OpPopupExportSAUV );
const bool isGMF = ( theCommandID == SMESHOp::OpExportGMF ||
case SMESHOp::OpImportUNV:
case SMESHOp::OpImportMED:
case SMESHOp::OpImportSTL:
-#ifdef WITH_CGNS
case SMESHOp::OpImportCGNS:
-#endif
case SMESHOp::OpImportSAUV:
case SMESHOp::OpImportGMF:
+ case SMESHOp::OpPopupImportDAT:
+ case SMESHOp::OpPopupImportUNV:
+ case SMESHOp::OpPopupImportMED:
+ case SMESHOp::OpPopupImportSTL:
+ case SMESHOp::OpPopupImportCGNS:
+ case SMESHOp::OpPopupImportSAUV:
+ case SMESHOp::OpPopupImportGMF:
{
if(checkLock(aStudy)) break;
::ImportMeshesFromFile(GetSMESHGen(),theCommandID);
case SMESHOp::OpExportMED:
case SMESHOp::OpExportUNV:
case SMESHOp::OpExportSTL:
-#ifdef WITH_CGNS
case SMESHOp::OpExportCGNS:
-#endif
case SMESHOp::OpExportSAUV:
case SMESHOp::OpExportGMF:
case SMESHOp::OpPopupExportDAT:
case SMESHOp::OpPopupExportMED:
case SMESHOp::OpPopupExportUNV:
case SMESHOp::OpPopupExportSTL:
-#ifdef WITH_CGNS
case SMESHOp::OpPopupExportCGNS:
-#endif
case SMESHOp::OpPopupExportSAUV:
case SMESHOp::OpPopupExportGMF:
{
extractContainers( sel_objects, to_process );
try {
-#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
OCC_CATCH_SIGNALS;
-#endif
if (vtkwnd) {
SALOME_ListIteratorOfListIO It( to_process );
for ( ; It.More(); It.Next())
//createSMESHAction( SMESHOp::OpImportDAT, "IMPORT_DAT", "", (Qt::CTRL+Qt::Key_B) );
createSMESHAction( SMESHOp::OpImportUNV, "IMPORT_UNV", "", (Qt::CTRL+Qt::Key_I) );
createSMESHAction( SMESHOp::OpImportMED, "IMPORT_MED", "", (Qt::CTRL+Qt::Key_M) );
- //createSMESHAction( 114, "NUM" );
createSMESHAction( SMESHOp::OpImportSTL, "IMPORT_STL" );
#ifdef WITH_CGNS
createSMESHAction( SMESHOp::OpImportCGNS, "IMPORT_CGNS" );
#endif
createSMESHAction( SMESHOp::OpImportSAUV, "IMPORT_SAUV" );
createSMESHAction( SMESHOp::OpImportGMF, "IMPORT_GMF" );
+ createSMESHAction( SMESHOp::OpPopupImportUNV, "IMPORT_UNV");
+ createSMESHAction( SMESHOp::OpPopupImportMED, "IMPORT_MED");
+ createSMESHAction( SMESHOp::OpPopupImportSTL, "IMPORT_STL" );
+#ifdef WITH_CGNS
+ createSMESHAction( SMESHOp::OpPopupImportCGNS, "IMPORT_CGNS" );
+#endif
+ createSMESHAction( SMESHOp::OpPopupImportSAUV, "IMPORT_SAUV" );
+ createSMESHAction( SMESHOp::OpPopupImportGMF, "IMPORT_GMF" );
+
createSMESHAction( SMESHOp::OpExportDAT, "DAT" );
createSMESHAction( SMESHOp::OpExportMED, "MED" );
createSMESHAction( SMESHOp::OpExportUNV, "UNV" );
group = pat.arg( SMESHGUI_Selection::typeName( SMESH::GROUP ) ),
hypo = pat.arg( SMESHGUI_Selection::typeName( SMESH::HYPOTHESIS ) ),
algo = pat.arg( SMESHGUI_Selection::typeName( SMESH::ALGORITHM ) ),
+ smesh = pat.arg( SMESHGUI_Selection::typeName( SMESH::COMPONENT ) ),
elems = QString( "'%1' '%2' '%3' '%4' '%5' '%6'" ).
arg( SMESHGUI_Selection::typeName( SMESH::SUBMESH_VERTEX ) ).
arg( SMESHGUI_Selection::typeName( SMESH::SUBMESH_EDGE ) ).
createPopupItem( SMESHOp::OpPopupExportDAT, OB, mesh_group, only_one_non_empty, anId );
createPopupItem( SMESHOp::OpDelete, OB, mesh_part + " " + hyp_alg );
createPopupItem( SMESHOp::OpDeleteGroup, OB, group );
+
+ anId = popupMgr()->insert( tr( "MEN_IMPORT" ), -1, -1 ); // IMPORT submenu
+ createPopupItem( SMESHOp::OpPopupImportMED, OB, smesh, "", anId );
+ createPopupItem( SMESHOp::OpPopupImportUNV, OB, smesh, "", anId );
+ createPopupItem( SMESHOp::OpPopupImportSTL, OB, smesh, "", anId );
+#ifdef WITH_CGNS
+ createPopupItem( SMESHOp::OpPopupImportCGNS, OB, smesh, "", anId );
+#endif
+ createPopupItem( SMESHOp::OpPopupImportSAUV, OB, smesh, "", anId );
+ createPopupItem( SMESHOp::OpPopupImportGMF, OB, smesh, "", anId );
+ createPopupItem( SMESHOp::OpPopupImportDAT, OB, smesh, "", anId );
popupMgr()->insert( separator(), -1, 0 );
// popup for viewer
// Controls
//-------------------------------------------------
QString
- aMeshInVtkHasNodes = aMeshInVTK + "&&" + hasNodes,
- aMeshInVtkHasEdges = aMeshInVTK + "&&" + hasEdges,
- aMeshInVtkHasFaces = aMeshInVTK + "&&" + hasFaces,
+ aMeshInVtkHasNodes = aMeshInVTK + "&&" + hasNodes,
+ aMeshInVtkHasEdges = aMeshInVTK + "&&" + hasEdges,
+ aMeshInVtkHasFaces = aMeshInVTK + "&&" + hasFaces,
aMeshInVtkHasVolumes = aMeshInVTK + "&&" + hasVolumes;
anId = popupMgr()->insert( tr( "MEN_CTRL" ), -1, -1 );
CheckBoxMerge = new QCheckBox(tr("MERGE_NODES_AND_ELEMENTS"), GroupArgs);
TextLabelTol = new QLabel(tr("SMESH_TOLERANCE"), GroupArgs);
- TextLabelTol->setAlignment(Qt::AlignCenter);
+ //TextLabelTol->setAlignment(Qt::AlignCenter);
SpinBoxTol = new SMESHGUI_SpinBox(GroupArgs);
SpinBoxTol->RangeStepAndValidator(0.0, COORD_MAX, 0.00001, "len_tol_precision" );
GroupArgsLayout->addWidget(ComboBoxUnion, 1, 3);
GroupArgsLayout->addWidget(CheckBoxCommon, 2, 0, 1, 4);
GroupArgsLayout->addWidget(CheckBoxMerge, 3, 0, 1, 4);
- GroupArgsLayout->addWidget(TextLabelTol, 4, 0, 1, 2);
- GroupArgsLayout->addWidget(SpinBoxTol, 4, 2, 1, 2);
+ GroupArgsLayout->addWidget(TextLabelTol, 4, 0);
+ GroupArgsLayout->addWidget(SpinBoxTol, 4, 1, 1, 3);
/***************************************************************/
GroupButtons = new QGroupBox(this);
if (!isValid())
return false;
+ SUIT_OverrideCursor aWaitCursor;
+
SMESH::SMESH_Mesh_var aMesh;
if (!myMesh->_is_nil())
QStringList anEntryList;
try {
- SUIT_OverrideCursor aWaitCursor;
aMesh = myMeshArray[0]->GetMesh();
aMesh->SetParameters( aParameters.join(":").toLatin1().constData() );
SeparateCornersAndMedium = new QCheckBox(tr("SEPARATE_CORNERS_AND_MEDIUM"), NodeSpecWidget );
SeparateCornersAndMedium->setEnabled( false );
+ AvoidMakingHoles = new QCheckBox(tr("AVOID_MAKING_HOLES"), NodeSpecWidget );
+ AvoidMakingHoles->setChecked( false );
+
QGridLayout* NodeSpecLayout = new QGridLayout(NodeSpecWidget);
NodeSpecLayout->setSpacing(SPACING);
NodeSpecLayout->setMargin(0);
NodeSpecLayout->addWidget(TextLabelTolerance, 0, 0 );
NodeSpecLayout->addWidget(SpinBoxTolerance, 0, 1 );
NodeSpecLayout->addWidget(SeparateCornersAndMedium, 1, 0, 1, 2 );
+ NodeSpecLayout->addWidget(AvoidMakingHoles, 2, 0, 1, 2 );
/***************************************************************/
// Exclude groups
}
if( myAction == MERGE_NODES )
- aMeshEditor->MergeNodes (aGroupsOfElements.inout(), nodesToKeep);
+ aMeshEditor->MergeNodes( aGroupsOfElements.inout(), nodesToKeep, AvoidMakingHoles->isChecked() );
else
- aMeshEditor->MergeElements (aGroupsOfElements.inout());
+ aMeshEditor->MergeElements( aGroupsOfElements.inout() );
if ( myTypeId == TYPE_AUTO ) {
- if (myAction == MERGE_NODES )
+ if ( myAction == MERGE_NODES )
SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INFORMATION"),
tr("SMESH_MERGED_NODES").arg(QString::number(ListCoincident->count()).toLatin1().data()));
else
QWidget* NodeSpecWidget;
SMESHGUI_SpinBox* SpinBoxTolerance;
QCheckBox* SeparateCornersAndMedium;
+ QCheckBox* AvoidMakingHoles;
QGroupBox* GroupCoincident;
//QWidget* GroupCoincidentWidget;
OpShowScalarBar = 1022, // SHOW SCALAR BAR
OpSaveDistribution = 1030, // SAVE DISTRIBUTION
OpShowDistribution = 1031, // SHOW DISTRIBUTION
-#ifndef DISABLE_PLOT2DVIEWER
OpPlotDistribution = 1032, // PLOT DISTRIBUTION
-#endif
OpFileInformation = 1040, // POPUP MENU - FILE INFORMATION
// Import -------------------------//--------------------------------
OpImportDAT = 1100, // MENU FILE - IMPORT - DAT FILE
OpImportUNV = 1101, // MENU FILE - IMPORT - UNV FILE
OpImportMED = 1102, // MENU FILE - IMPORT - MED FILE
OpImportSTL = 1103, // MENU FILE - IMPORT - STL FILE
-#ifdef WITH_CGNS
OpImportCGNS = 1104, // MENU FILE - IMPORT - CGNS FILE
-#endif
OpImportSAUV = 1105, // MENU FILE - IMPORT - SAUV FILE
OpImportGMF = 1106, // MENU FILE - IMPORT - GMF FILE
+ OpPopupImportDAT = 1120, // POPUP MENU - IMPORT - DAT FILE
+ OpPopupImportUNV = 1121, // POPUP MENU - IMPORT - UNV FILE
+ OpPopupImportMED = 1122, // POPUP MENU - IMPORT - MED FILE
+ OpPopupImportSTL = 1123, // POPUP MENU - IMPORT - STL FILE
+ OpPopupImportCGNS = 1124, // POPUP MENU - IMPORT - CGNS FILE
+ OpPopupImportSAUV = 1125, // POPUP MENU - IMPORT - SAUV FILE
+ OpPopupImportGMF = 1126, // POPUP MENU - IMPORT - GMF FILE
// Export -------------------------//--------------------------------
OpExportDAT = 1200, // MENU FILE - EXPORT - DAT FILE
OpExportMED = 1201, // MENU FILE - EXPORT - MED FILE
OpExportUNV = 1202, // MENU FILE - EXPORT - UNV FILE
OpExportSTL = 1203, // MENU FILE - EXPORT - STL FILE
-#ifdef WITH_CGNS
OpExportCGNS = 1204, // MENU FILE - EXPORT - CGNS FILE
-#endif
OpExportSAUV = 1205, // MENU FILE - EXPORT - SAUV FILE
OpExportGMF = 1206, // MENU FILE - EXPORT - GMF FILE
OpPopupExportDAT = 1210, // POPUP MENU - EXPORT - DAT FILE
OpPopupExportMED = 1211, // POPUP MENU - EXPORT - MED FILE
OpPopupExportUNV = 1212, // POPUP MENU - EXPORT - UNV FILE
OpPopupExportSTL = 1213, // POPUP MENU - EXPORT - STL FILE
-#ifdef WITH_CGNS
OpPopupExportCGNS = 1214, // POPUP MENU - EXPORT - CGNS FILE
-#endif
OpPopupExportSAUV = 1215, // POPUP MENU - EXPORT - SAUV FILE
OpPopupExportGMF = 1216, // POPUP MENU - EXPORT - GMF FILE
// Mesh ---------------------------//--------------------------------
if ((anActor = CreateActor(aDocument,theEntry,true))) {
bool needFitAll = noSmeshActors(theWnd); // fit for the first object only
DisplayActor(theWnd,anActor);
+ anActor->SetVisibility(true);
aStudy->setVisibilityState(theEntry, Qtx::ShownState);
// FitAll(); - PAL16770(Display of a group performs an automatic fit all)
if (needFitAll) FitAll();
<source>SEPARATE_CORNERS_AND_MEDIUM</source>
<translation>No merge of corner and medium nodes of quadratic cells</translation>
</message>
+ <message>
+ <source>AVOID_MAKING_HOLES</source>
+ <translation>Avoid making holes</translation>
+ </message>
<message>
<source>KEEP_NODES</source>
<translation>Nodes to keep during the merge</translation>
SMESH_MAT2d.cxx
SMESH_FreeBorders.cxx
SMESH_ControlPnt.cxx
-)
+ SMESH_DeMerge.cxx
+ )
# --- rules ---
--- /dev/null
+// Copyright (C) 2007-2016 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, 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
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// File : SMESH_DeMerge.hxx
+// Created : Fri Mar 10 16:06:54 2017
+// Author : Edward AGAPOV (eap)
+
+// Implementation of SMESH_MeshAlgos::DeMerge()
+
+#include "SMESH_MeshAlgos.hxx"
+
+#include "SMDS_VolumeTool.hxx"
+#include "SMDS_MeshVolume.hxx"
+
+namespace
+{
+ bool isDegenFace(const std::vector< const SMDS_MeshNode* >& nodes)
+ {
+ // in a degenerated face each link sticks to another
+
+ typedef std::map< SMESH_TLink , int > TLink2Nb;
+ TLink2Nb link2nb;
+ for ( size_t iPrev = nodes.size() - 1, i = 0; i < nodes.size(); iPrev = i++ )
+ {
+ SMESH_TLink link( nodes[iPrev], nodes[i] );
+ TLink2Nb::iterator l2n = link2nb.insert( std::make_pair( link, 0 )).first;
+ l2n->second++;
+ }
+
+ if ( link2nb.size() == 1 )
+ return true;
+
+ for ( TLink2Nb::iterator l2n = link2nb.begin(); l2n != link2nb.end(); ++l2n )
+ if ( l2n->second == 1 )
+ return false;
+
+ return true;
+ }
+
+ void deMergeFace(const SMDS_MeshElement* face,
+ std::vector< const SMDS_MeshNode* >& newNodes,
+ std::vector< const SMDS_MeshNode* >& noMergeNodes)
+ {
+ if ( face->IsQuadratic() )
+ {
+ const int nbCorners = face->NbCornerNodes();
+ const int nbNodes = (int) newNodes.size();
+
+ // de-merge sticking medium nodes
+ for ( int i = 1; i < nbNodes; i += 2 ) // loop om medium nodes
+ {
+ int iPrev = ( i - 1 );
+ int iNext = ( i + 1 ) % nbNodes;
+ if ( newNodes[ iPrev ] == newNodes[ iNext ] )
+ {
+ if ( newNodes[ iPrev ] != newNodes[ i ] || nbCorners == 3 )
+ {
+ // corners stick but the medium does not, or a link of triangle collapses
+ noMergeNodes.push_back( face->GetNode( iPrev / 2 ));
+ noMergeNodes.push_back( face->GetNode( iNext / 2 ));
+ noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
+ }
+ }
+ else if ( newNodes[ i ] == newNodes[ iPrev ] )
+ {
+ // the medium node sticks to a neighbor corner one
+ noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
+ noMergeNodes.push_back( face->GetNode( iPrev / 2 ));
+ }
+ else if ( newNodes[ i ] == newNodes[ iNext ] )
+ {
+ // the medium node sticks to a neighbor corner one
+ noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
+ noMergeNodes.push_back( face->GetNode( iNext / 2 ));
+ }
+ else
+ {
+ // find if the medium sticks to any other node
+ std::vector<const SMDS_MeshNode*>::iterator pos;
+ pos = std::find( newNodes.begin(), newNodes.begin() + iPrev, newNodes[i] );
+ if ( pos == newNodes.begin() + iPrev )
+ pos = std::find( newNodes.begin() + i + 1, newNodes.end(), newNodes[i] );
+ if ( pos == newNodes.end() )
+ continue;
+
+ int iStick = std::distance( newNodes.begin(), pos );
+ if ( iStick % 2 == 0 )
+ {
+ // the medium sticks to a distant corner
+ noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
+ noMergeNodes.push_back( face->GetNode( iStick / 2 ));
+ }
+ else
+ {
+ // the medium sticks to a distant medium;
+ // it's OK if two links stick
+ int iPrev2 = ( iStick - 1 );
+ int iNext2 = ( iStick + 1 ) % nbNodes;
+ if (( newNodes[ iPrev ] == newNodes[ iPrev2 ] &&
+ newNodes[ iNext ] == newNodes[ iNext2 ] )
+ ||
+ ( newNodes[ iPrev ] == newNodes[ iNext2 ] &&
+ newNodes[ iNext ] == newNodes[ iPrev2 ] ))
+ ; // OK
+ else
+ {
+ noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
+ noMergeNodes.push_back( face->GetNode( nbCorners + iStick / 2 ));
+ }
+ }
+ }
+ }
+ }
+ } // deMergeFace()
+
+ bool isDegenVolume(const SMDS_VolumeTool& vt)
+ {
+ // TMP: it's necessary to use a topological check instead of a geometrical one
+ return vt.GetSize() < 1e-100;
+ }
+
+ void deMergeVolume(const SMDS_VolumeTool& vt,
+ std::vector< const SMDS_MeshNode* >& noMergeNodes)
+ {
+ // temporary de-merge all nodes
+ for ( int i = 0; i < vt.NbNodes(); ++i )
+ {
+ const SMDS_MeshNode* n = vt.GetNodes()[i];
+ if ( n != vt.Element()->GetNode( i ))
+ noMergeNodes.push_back( n );
+ }
+ }
+
+} // namespace
+
+//================================================================================
+/*!
+ * \brief Find nodes whose merge makes the element invalid. (Degenerated elem is OK)
+ * \param [in] elem - the element
+ * \param [in] newNodes - nodes of the element after the merge
+ * \param [out] noMergeNodes - nodes to undo merge
+ */
+//================================================================================
+
+void SMESH_MeshAlgos::DeMerge(const SMDS_MeshElement* elem,
+ std::vector< const SMDS_MeshNode* >& newNodes,
+ std::vector< const SMDS_MeshNode* >& noMergeNodes)
+{
+ switch ( elem->GetType() )
+ {
+ case SMDSAbs_Face:
+ {
+ if ( newNodes.size() <= 4 )
+ return; // degenerated
+
+ if ( elem->IsQuadratic() )
+ SMDS_MeshCell::applyInterlace // interlace medium and corner nodes
+ ( SMDS_MeshCell::interlacedSmdsOrder( elem->GetEntityType(), newNodes.size() ), newNodes );
+
+ if ( isDegenFace( newNodes ))
+ return;
+
+ deMergeFace( elem, newNodes, noMergeNodes );
+ }
+ break;
+
+ case SMDSAbs_Volume:
+ {
+ if ( newNodes.size() <= 4 )
+ return; // degenerated
+
+ SMDS_VolumeTool vt;
+ if ( !vt.Set( elem, /*skipCentral=*/true, &newNodes ))
+ return; // strange
+
+ if ( isDegenVolume( vt ))
+ return;
+
+ deMergeVolume( elem, noMergeNodes );
+ }
+ break;
+
+ case SMDSAbs_Edge:
+ {
+ if ( newNodes.size() == 3 )
+ if (( newNodes[2] == newNodes[0] && newNodes[2] != newNodes[1] ) ||
+ ( newNodes[2] == newNodes[1] && newNodes[2] != newNodes[0]))
+ {
+ // the medium node sticks to a corner
+ noMergeNodes.push_back( newNodes[2] );
+ noMergeNodes.push_back( newNodes[ newNodes[2] == newNodes[1] ]);
+ }
+ }
+ break;
+ default:;
+ }
+}
CoincidentFreeBorders & foundFreeBordes);
-} // SMESH_MeshAlgos
+ /*!
+ * \brief Find nodes whose merge makes the element invalid
+ *
+ * (Implemented in SMESH_DeMerge.cxx)
+ */
+ SMESHUtils_EXPORT
+ void DeMerge(const SMDS_MeshElement* elem,
+ std::vector< const SMDS_MeshNode* >& newNodes,
+ std::vector< const SMDS_MeshNode* >& noMergeNodes);
+
+} // namespace SMESH_MeshAlgos
#endif
if ( 0 < aSize && aSize < 100 ) // for comfortable testing ;)
std::sort( &aRes[0], &aRes[0]+aSize );
}
- MESSAGE("get list of IDs of a vague group");
return aRes._retn();
}
aGroupDS->SetColorGroup(color);
TPythonDump()<<SMESH::SMESH_GroupBase_var(_this())<<".SetColorNumber( "<<color<<" )";
}
- MESSAGE("set color number of a group");
return ;
}
//=======================================================================
void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfNodes,
- const SMESH::ListOfIDSources& NodesToKeep)
+ const SMESH::ListOfIDSources& NodesToKeep,
+ CORBA::Boolean AvoidMakingHoles)
throw (SALOME::SALOME_Exception)
{
SMESH_TRY;
aTPythonDump << aNodeGroup;
}
- getEditor().MergeNodes( aListOfListOfNodes );
+ getEditor().MergeNodes( aListOfListOfNodes, AvoidMakingHoles );
- aTPythonDump << "], " << NodesToKeep << ")";
+ aTPythonDump << "], " << NodesToKeep << ", " << AvoidMakingHoles << ")";
declareMeshModified( /*isReComputeSafe=*/false );
CORBA::Boolean SeparateCornersAndMedium)
throw (SALOME::SALOME_Exception);
void MergeNodes (const SMESH::array_of_long_array& GroupsOfNodes,
- const SMESH::ListOfIDSources& NodesToKeep )
+ const SMESH::ListOfIDSources& NodesToKeep,
+ CORBA::Boolean AvoidMakingHoles )
throw (SALOME::SALOME_Exception);
void FindEqualElements(SMESH::SMESH_IDSource_ptr Object,
SMESH::array_of_long_array_out GroupsOfElementsID)
SMESH_TRY;
// Read mesh with name = <theMeshName> into SMESH_Mesh
- _impl->STLToMesh( theFileName );
+ std::string name = _impl->STLToMesh( theFileName );
+ if ( !name.empty() )
+ {
+ SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
+ SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( study, _this() );
+ _gen_i->SetName( meshSO, name.c_str() );
+ }
SMESH_CATCH( SMESH::throwCorbaException );
TPythonDump() << SMESH::SMESH_Mesh_var(_this())
<< ".ExportSTL( r'" << file << "', " << isascii << " )";
+ CORBA::String_var name;
+ SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
+ SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( study, _this() );
+ if ( !so->_is_nil() )
+ name = so->GetName();
+
// Perform Export
- PrepareForWriting(file);
- _impl->ExportSTL(file, isascii);
+ PrepareForWriting( file );
+ _impl->ExportSTL( file, isascii, name.in() );
}
//================================================================================
PrepareForWriting(file);
+ CORBA::String_var name;
+ SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
+ SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( study, meshPart );
+ if ( !so->_is_nil() )
+ name = so->GetName();
+
SMESH_MeshPartDS partDS( meshPart );
- _impl->ExportSTL(file, isascii, &partDS);
+ _impl->ExportSTL( file, isascii, name.in(), &partDS );
TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportPartToSTL( "
<< meshPart<< ", r'" << file << "', " << isascii << ")";
# @param NodesToKeep nodes to keep in the mesh: a list of groups, sub-meshes or node IDs.
# If @a NodesToKeep does not include a node to keep for some group to merge,
# then the first node in the group is kept.
+ # @param AvoidMakingHoles prevent merging nodes which cause removal of elements becoming
+ # invalid
# @ingroup l2_modif_trsf
- def MergeNodes (self, GroupsOfNodes, NodesToKeep=[]):
+ def MergeNodes (self, GroupsOfNodes, NodesToKeep=[], AvoidMakingHoles=False):
# NodesToKeep are converted to SMESH_IDSource in meshEditor.MergeNodes()
- self.editor.MergeNodes(GroupsOfNodes,NodesToKeep)
+ self.editor.MergeNodes( GroupsOfNodes, NodesToKeep, AvoidMakingHoles )
## Find the elements built on the same nodes.
# @param MeshOrSubMeshOrGroup Mesh or SubMesh, or Group of elements for searching
def FindCoincidentNodesOnPart(self,*args): # a 3d arg added (SeparateCornerAndMediumNodes)
if len( args ) == 2: args += False,
return SMESH._objref_SMESH_MeshEditor.FindCoincidentNodesOnPart( self, *args )
- def MergeNodes(self,*args): # a 2nd arg added (NodesToKeep)
+ def MergeNodes(self,*args): # 2 args added (NodesToKeep,AvoidMakingHoles)
if len( args ) == 1:
- return SMESH._objref_SMESH_MeshEditor.MergeNodes( self, args[0], [] )
+ return SMESH._objref_SMESH_MeshEditor.MergeNodes( self, args[0], [], False )
NodesToKeep = args[1]
+ AvoidMakingHoles = args[2] if len( args ) == 3 else False
unRegister = genObjUnRegister()
if NodesToKeep:
if isinstance( NodesToKeep, list ) and isinstance( NodesToKeep[0], int ):
NodesToKeep = self.MakeIDSource( NodesToKeep, SMESH.NODE )
if not isinstance( NodesToKeep, list ):
NodesToKeep = [ NodesToKeep ]
- return SMESH._objref_SMESH_MeshEditor.MergeNodes( self, args[0], NodesToKeep )
+ return SMESH._objref_SMESH_MeshEditor.MergeNodes( self, args[0], NodesToKeep, AvoidMakingHoles )
pass
omniORB.registerObjref(SMESH._objref_SMESH_MeshEditor._NP_RepositoryId, meshEditor)
size_t iSD = 0;
for ( iSD = 0; iSD < _sdVec.size(); ++iSD ) // find next SOLID to compute
if ( _sdVec[iSD]._before.IsEmpty() &&
+ !_sdVec[iSD]._solid.IsNull() &&
_sdVec[iSD]._n2eMap.empty() )
break;
if ( ! makeLayer(_sdVec[iSD]) ) // create _LayerEdge's
return _error;
- if ( _sdVec[iSD]._n2eMap.size() == 0 )
+ if ( _sdVec[iSD]._n2eMap.size() == 0 ) // no layers in a SOLID
+ {
+ _sdVec[iSD]._solid.Nullify();
continue;
-
+ }
+
if ( ! inflate(_sdVec[iSD]) ) // increase length of _LayerEdge's
return _error;
minDist = Min( pSrc.SquareDistance( pTgtN ), minDist );
minDist = Min( pTgt.SquareDistance( pSrcN ), minDist );
double newMaxLen = edge->_maxLen + 0.5 * Sqrt( minDist );
- if ( edge->_nodes[0]->getshapeId() == neibor->_nodes[0]->getshapeId() )
+ //if ( edge->_nodes[0]->getshapeId() == neibor->_nodes[0]->getshapeId() ) viscous_layers_00/A3
{
newMaxLen *= edge->_lenFactor / neibor->_lenFactor;
}