diff --git a/doc/salome/gui/SMESH/images/mergenodes.png b/doc/salome/gui/SMESH/images/mergenodes.png
index 5b34361cb..fc75f70dd 100644
Binary files a/doc/salome/gui/SMESH/images/mergenodes.png and b/doc/salome/gui/SMESH/images/mergenodes.png differ
diff --git a/doc/salome/gui/SMESH/images/mergenodes_auto.png b/doc/salome/gui/SMESH/images/mergenodes_auto.png
index 4f177f605..e27046908 100644
Binary files a/doc/salome/gui/SMESH/images/mergenodes_auto.png and b/doc/salome/gui/SMESH/images/mergenodes_auto.png differ
diff --git a/doc/salome/gui/SMESH/input/merging_nodes.doc b/doc/salome/gui/SMESH/input/merging_nodes.doc
index 8aff9aa09..872f9eeed 100644
--- a/doc/salome/gui/SMESH/input/merging_nodes.doc
+++ b/doc/salome/gui/SMESH/input/merging_nodes.doc
@@ -26,6 +26,9 @@ merging.
cells 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.
+
Activation of Avoid making holes check-box prevents merging
+ nodes that make elements invalid (but not degenerated) and hence
+ removed. Thus, no holes in place of removed elements appear.
Exclude groups from detection group allows to ignore the
nodes which belong to the specified mesh groups. This control is
active provided that the mesh includes groups.
diff --git a/idl/SMESH_MeshEditor.idl b/idl/SMESH_MeshEditor.idl
index 577e39c58..ea19b5ebe 100644
--- a/idl/SMESH_MeshEditor.idl
+++ b/idl/SMESH_MeshEditor.idl
@@ -689,7 +689,8 @@ module SMESH
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);
/*!
diff --git a/src/DriverSTL/DriverSTL_R_SMDS_Mesh.cxx b/src/DriverSTL/DriverSTL_R_SMDS_Mesh.cxx
index 9a531668c..ae7e48cca 100644
--- a/src/DriverSTL/DriverSTL_R_SMDS_Mesh.cxx
+++ b/src/DriverSTL/DriverSTL_R_SMDS_Mesh.cxx
@@ -69,7 +69,7 @@ namespace
};
typedef NCollection_DataMap 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;
@@ -150,11 +150,12 @@ Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::Perform()
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;
@@ -205,30 +206,48 @@ static SMDS_MeshNode* readNode(SMESH_File& theFile,
//=======================================================================
//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( 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;
@@ -236,8 +255,8 @@ Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readAscii(SMESH_File& theFile) const
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]);
@@ -278,7 +297,7 @@ Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readBinary(SMESH_File& file) const
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)");
@@ -288,6 +307,19 @@ Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readBinary(SMESH_File& file) const
// 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( 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;
diff --git a/src/DriverSTL/DriverSTL_R_SMDS_Mesh.h b/src/DriverSTL/DriverSTL_R_SMDS_Mesh.h
index 5459b5181..d30366bfb 100644
--- a/src/DriverSTL/DriverSTL_R_SMDS_Mesh.h
+++ b/src/DriverSTL/DriverSTL_R_SMDS_Mesh.h
@@ -35,16 +35,18 @@ class MESHDRIVERSTL_EXPORT DriverSTL_R_SMDS_Mesh: public Driver_SMDS_Mesh
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
diff --git a/src/DriverSTL/DriverSTL_W_SMDS_Mesh.cxx b/src/DriverSTL/DriverSTL_W_SMDS_Mesh.cxx
index cb42a321b..333c72d96 100644
--- a/src/DriverSTL/DriverSTL_W_SMDS_Mesh.cxx
+++ b/src/DriverSTL/DriverSTL_W_SMDS_Mesh.cxx
@@ -176,7 +176,7 @@ static void writeFloat( const Standard_ShortReal& theVal, SMESH_File& ofile)
{
union {
Standard_ShortReal f;
- char c[4];
+ char c[4];
} u;
u.f = theVal;
@@ -485,7 +485,8 @@ Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeAscii() const
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];
@@ -520,7 +521,8 @@ Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeAscii() const
" endfacet\n", 21 );
}
}
- aFile.writeRaw ("endsolid\n" , 9 );
+ buf = "endsolid " + myName + "\n";
+ aFile.writeRaw( buf.c_str(), buf.size() );
return aResult;
}
@@ -554,6 +556,11 @@ Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeBinary() const
}
}
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
diff --git a/src/DriverSTL/DriverSTL_W_SMDS_Mesh.h b/src/DriverSTL/DriverSTL_W_SMDS_Mesh.h
index efc027be1..66c4741bf 100644
--- a/src/DriverSTL/DriverSTL_W_SMDS_Mesh.h
+++ b/src/DriverSTL/DriverSTL_W_SMDS_Mesh.h
@@ -45,6 +45,7 @@ class MESHDRIVERSTL_EXPORT DriverSTL_W_SMDS_Mesh: public Driver_SMDS_Mesh
~DriverSTL_W_SMDS_Mesh();
virtual Status Perform();
void SetIsAscii( const bool theIsAscii = false );
+ void SetName( const std::string name ) { myName = name; }
private:
// PRIVATE METHODS
@@ -56,7 +57,8 @@ class MESHDRIVERSTL_EXPORT DriverSTL_W_SMDS_Mesh: public Driver_SMDS_Mesh
private:
// PRIVATE FIELDS
- bool myIsAscii;
+ bool myIsAscii;
+ std::string myName;
int myNbVolumeTrias;
std::vector myVolumeFacets; // tmp faces
};
diff --git a/src/SMDS/SMDS_VolumeTool.cxx b/src/SMDS/SMDS_VolumeTool.cxx
index d7dd7f826..f7857c3eb 100644
--- a/src/SMDS/SMDS_VolumeTool.cxx
+++ b/src/SMDS/SMDS_VolumeTool.cxx
@@ -471,8 +471,9 @@ SMDS_VolumeTool::~SMDS_VolumeTool()
//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* otherNodes)
{
// reset fields
myVolume = 0;
@@ -510,11 +511,22 @@ bool SMDS_VolumeTool::Set (const SMDS_MeshElement* theVolume,
}
// set nodes
- int iNode = 0;
myVolumeNodes.resize( myVolume->NbNodes() );
- SMDS_ElemIteratorPtr nodeIt = myVolume->nodesIterator();
- while ( nodeIt->more() )
- myVolumeNodes[ iNode++ ] = static_cast( 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( nodeIt->next() );
+ }
// check validity
if ( !setFace(0) )
diff --git a/src/SMDS/SMDS_VolumeTool.hxx b/src/SMDS/SMDS_VolumeTool.hxx
index b42a0ae07..5c2c882f6 100644
--- a/src/SMDS/SMDS_VolumeTool.hxx
+++ b/src/SMDS/SMDS_VolumeTool.hxx
@@ -58,15 +58,17 @@ class SMDS_EXPORT SMDS_VolumeTool
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* nodes = NULL);
// 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
@@ -91,10 +93,10 @@ class SMDS_EXPORT SMDS_VolumeTool
// 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;
diff --git a/src/SMESH/SMESH_Mesh.cxx b/src/SMESH/SMESH_Mesh.cxx
index 98725ba12..893a28aba 100644
--- a/src/SMESH/SMESH_Mesh.cxx
+++ b/src/SMESH/SMESH_Mesh.cxx
@@ -559,7 +559,7 @@ int SMESH_Mesh::MEDToMesh(const char* theFileName, const char* theMeshName)
//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"));
@@ -571,7 +571,7 @@ int SMESH_Mesh::STLToMesh(const char* theFileName)
myReader.SetMeshId(-1);
myReader.Perform();
- return 1;
+ return myReader.GetName();
}
//================================================================================
@@ -1560,6 +1560,7 @@ void SMESH_Mesh::ExportUNV(const char * file,
void SMESH_Mesh::ExportSTL(const char * file,
const bool isascii,
+ const char * name,
const SMESHDS_Mesh* meshPart) throw(SALOME_Exception)
{
Unexpect aCatch(SalomeException);
@@ -1568,6 +1569,7 @@ void SMESH_Mesh::ExportSTL(const char * file,
myWriter.SetIsAscii( isascii );
myWriter.SetMesh( meshPart ? (SMESHDS_Mesh*) meshPart : _myMeshDS);
myWriter.SetMeshId(_id);
+ if ( name ) myWriter.SetName( name );
myWriter.Perform();
}
diff --git a/src/SMESH/SMESH_Mesh.hxx b/src/SMESH/SMESH_Mesh.hxx
index 1fd14f397..a8ec5dfae 100644
--- a/src/SMESH/SMESH_Mesh.hxx
+++ b/src/SMESH/SMESH_Mesh.hxx
@@ -121,7 +121,7 @@ class SMESH_EXPORT SMESH_Mesh
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);
@@ -263,6 +263,7 @@ class SMESH_EXPORT SMESH_Mesh
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,
diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx
index f4dd0d7db..38b2eeb9f 100644
--- a/src/SMESH/SMESH_MeshEditor.cxx
+++ b/src/SMESH/SMESH_MeshEditor.cxx
@@ -6095,7 +6095,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2],
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;
@@ -6140,7 +6140,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2],
}
list 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
@@ -6183,7 +6183,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2],
return EXTR_BAD_PATH_SHAPE;
}
- return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
+ return makeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
theHasRefPoint, theRefPoint, theMakeGroups);
}
@@ -6322,7 +6322,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2],
TopoDS_Edge e = BRepBuilderAPI_MakeEdge( p1, p2 );
list 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();
@@ -6380,7 +6380,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2],
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;
@@ -6439,7 +6439,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2],
}
list 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
@@ -6475,17 +6475,17 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2],
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& aPrms,
+SMESH_MeshEditor::makeEdgePathPoints(std::list& aPrms,
const TopoDS_Edge& aTrackEdge,
bool FirstIsStart,
list& LPP)
@@ -6536,11 +6536,11 @@ SMESH_MeshEditor::MakeEdgePathPoints(std::list& aPrms,
//=======================================================================
-//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& fullList,
const bool theHasAngles,
list& theAngles,
@@ -6553,7 +6553,7 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets
// Angles
if( theHasAngles && !theAngles.empty() && theLinearVariation )
- LinearAngleVariation(aNbTP-1, theAngles);
+ linearAngleVariation(aNbTP-1, theAngles);
// fill vector of path points with angles
vector aPPs;
@@ -6746,11 +6746,11 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets
//=======================================================================
-//function : LinearAngleVariation
+//function : linearAngleVariation
//purpose : spread values over nbSteps
//=======================================================================
-void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
+void SMESH_MeshEditor::linearAngleVariation(const int nbSteps,
list& Angles)
{
int nbAngles = Angles.size();
@@ -7258,7 +7258,7 @@ void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
}
else
while ( nIt->more() )
- theNodes.insert( theNodes.end(),nIt->next() );
+ theNodes.insert( theNodes.end(), nIt->next() );
}
else if ( theSeparateCornersAndMedium ) // separate corners from medium nodes
{
@@ -7351,11 +7351,12 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes,
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
- SMESHDS_Mesh* aMesh = GetMeshDS();
+ SMESHDS_Mesh* mesh = GetMeshDS();
TNodeNodeMap nodeNodeMap; // node to replace - new node
set elems; // all elements with changed nodes
list< int > rmElemIds, rmNodeIds;
+ vector< ElemFeatures > newElemDefs;
// Fill nodeNodeMap and elems
@@ -7369,17 +7370,6 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes,
{
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();
@@ -7387,471 +7377,550 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes,
}
}
}
- // Change element nodes or remove an element
- set nodeSet;
- vector< const SMDS_MeshNode*> curNodes, uniqueNodes;
- vector 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 pbElems;
+ set::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( 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::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() )
+ for ( size_t i = 0; i < newElemDefs.size(); ++i )
{
- const SMDS_MeshNode* n = static_cast( itN->next() );
-
- TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
- if ( nnIt != nodeNodeMap.end() ) { // n sticks
- n = (*nnIt).second;
- { ////////// BUG 0020185: begin
- bool stopRecur = false;
- set 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
- }
- curNodes[ iCur ] = n;
- bool isUnique = nodeSet.insert( n ).second;
- if ( isUnique )
- uniqueNodes[ iUnique++ ] = n;
- else
- iRepl[ nbRepl++ ] = iCur;
- iCur++;
- }
-
- // Analyse element topology after replacement
-
- bool isOk = true;
- int nbUniqueNodes = nodeSet.size();
- if ( nbNodes != nbUniqueNodes ) // some nodes stick
- {
- if ( elem->IsPoly() ) // Polygons and Polyhedral volumes
+ if ( i > 0 || !mesh->ChangeElementNodes( elem, &
+ newElemDefs[i].myNodes[0],
+ newElemDefs[i].myNodes.size() ))
{
- if ( elem->GetType() == SMDSAbs_Face ) // Polygon
+ if ( i == 0 )
{
- 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 polygons_nodes;
- vector quantities;
- int nbNew = SimplifyFace( curNodes, polygons_nodes, quantities );
- if (nbNew > 0)
- {
- vector 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 ));
-
- SMDS_MeshElement* newElem = AddElement( face_nodes, elemType.SetID(-1));
- if ( aShapeId )
- aMesh->SetMeshElementOnShape(newElem, aShapeId);
- }
- }
- rmElemIds.push_back(elem->GetID());
-
- } // Polygon
-
- else if ( elem->GetType() == SMDSAbs_Volume ) // Polyhedral volume
+ newElemDefs[i].SetID( elem->GetID() );
+ mesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
+ if ( !keepElem ) rmElemIds.pop_back();
+ }
+ else
{
- 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( elem );
- if ( aPolyedre )
- {
- int nbFaces = aPolyedre->NbFaces();
-
- vector poly_nodes;
- vector quantities;
- vector faceNodes;
-
- for (int iface = 1; iface <= nbFaces; iface++)
- {
- int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
- faceNodes.resize( nbFaceNodes );
- for (int inode = 1; inode <= nbFaceNodes; inode++)
- {
- const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
- TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
- if ( nnIt != nodeNodeMap.end() ) // faceNode sticks
- faceNode = (*nnIt).second;
- faceNodes[inode - 1] = faceNode;
- }
- SimplifyFace(faceNodes, poly_nodes, quantities);
- }
-
- if ( quantities.size() > 3 ) {
- // TODO: remove coincident faces
- }
-
- 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() );
- }
- }
+ newElemDefs[i].SetID( -1 );
}
- else {
- }
-
- continue;
- } // poly element
-
- // 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
- {
- 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] )))
- {
- isOk = true;
- }
- break;
- }
- case SMDSEntity_Penta: ///////////////////////////////////// PENTAHEDRON
- {
- 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] )
- {
- uniqueNodes[ 0 ] = curNodes[ 0 ];
- uniqueNodes[ 1 ] = curNodes[ 2 ];
- uniqueNodes[ 2 ] = curNodes[ 5 ];
- uniqueNodes[ 3 ] = curNodes[ 3 ];
- uniqueNodes[ 4 ] = curNodes[ 1 ];
- isOk = true;
- }
- 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 ];
- isOk = true;
- }
- }
- break;
- }
- case SMDSEntity_Hexa:
- {
- //////////////////////////////////// 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;
- }
- }
- }
- 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 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;
- }
- }
- 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;
- }
- break;
- }
- }
- }
-
- if ( !isOk && nbUniqueNodes > 4 ) {
- ////////////////// HEXAHEDRON ---> polyhedron
- hexa.SetExternalNormal();
- vector poly_nodes; poly_nodes.reserve( 6 * 4 );
- vector quantities; quantities.reserve( 6 );
- for ( int iFace = 0; iFace < 6; iFace++ )
- {
- const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
- if ( curNodes[ind[0]] == curNodes[ind[2]] ||
- curNodes[ind[1]] == curNodes[ind[3]] )
- {
- quantities.clear();
- break; // opposite nodes stick
- }
- nodeSet.clear();
- for ( iCur = 0; iCur < 4; iCur++ )
- {
- if ( nodeSet.insert( curNodes[ind[ iCur ]] ).second )
- poly_nodes.push_back( curNodes[ind[ iCur ]]);
- }
- if ( nodeSet.size() < 3 )
- poly_nodes.resize( poly_nodes.size() - nodeSet.size() );
- else
- quantities.push_back( nodeSet.size() );
- }
- if ( quantities.size() >= 4 )
- {
- const SMDS_MeshElement* newElem = aMesh->AddPolyhedralVolume( poly_nodes, quantities );
- myLastCreatedElems.Append( newElem );
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- rmElemIds.push_back( elem->GetID() );
- }
- }
- break;
- } // case HEXAHEDRON
-
- default:
- isOk = false;
- } // switch ( nbNodes )
-
- } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
-
- if ( isOk ) // a non-poly elem remains valid after sticking nodes
- {
- 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 );
+ SMDS_MeshElement* newElem = this->AddElement( newElemDefs[i].myNodes, newElemDefs[i] );
if ( sm && newElem )
sm->AddElement( newElem );
if ( elem != newElem )
- ReplaceElemInGroups( elem, newElem, aMesh );
+ ReplaceElemInGroups( elem, newElem, mesh );
}
}
- else {
- // Remove invalid regular element or invalid polygon
- rmElemIds.push_back( elem->GetID() );
- }
-
- } // loop on elements
+ }
// Remove bad elements, then equal nodes (order important)
-
Remove( rmElemIds, false );
Remove( rmNodeIds, true );
return;
}
+//=======================================================================
+//function : applyMerge
+//purpose : Compute new connectivity of an element after merging nodes
+// \param [in] elems - the element
+// \param [out] newElemDefs - definition(s) of result element(s)
+// \param [inout] nodeNodeMap - nodes to merge
+// \param [in] avoidMakingHoles - if true and and the element becomes invalid
+// after merging (but not degenerated), removes nodes causing
+// the invalidity from \a nodeNodeMap.
+// \return bool - true if the element should be removed
+//=======================================================================
+
+bool SMESH_MeshEditor::applyMerge( const SMDS_MeshElement* elem,
+ vector< ElemFeatures >& newElemDefs,
+ TNodeNodeMap& nodeNodeMap,
+ const bool avoidMakingHoles )
+{
+ bool toRemove = false; // to remove elem
+ int nbResElems = 1; // nb new elements
+
+ newElemDefs.resize(nbResElems);
+ newElemDefs[0].Init( elem );
+ newElemDefs[0].myNodes.clear();
+
+ set nodeSet;
+ vector< const SMDS_MeshNode*> curNodes;
+ vector< const SMDS_MeshNode*> & uniqueNodes = newElemDefs[0].myNodes;
+ vector iRepl;
+
+ const int nbNodes = elem->NbNodes();
+ SMDSAbs_EntityType entity = elem->GetEntityType();
+
+ curNodes.resize( nbNodes );
+ uniqueNodes.resize( nbNodes );
+ iRepl.resize( nbNodes );
+ int iUnique = 0, iCur = 0, nbRepl = 0;
+
+ // Get new seq of nodes
+
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() )
+ {
+ const SMDS_MeshNode* n = static_cast( itN->next() );
+
+ 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 polygons_nodes;
+ vector quantities;
+ nbResElems = SimplifyFace( curNodes, polygons_nodes, quantities );
+ newElemDefs.resize( nbResElems );
+ for ( int inode = 0, iface = 0; iface < nbResElems; iface++ )
+ {
+ ElemFeatures* elemType = & newElemDefs[iface];
+ if ( iface ) elemType->Init( elem );
+
+ vector& face_nodes = elemType->myNodes;
+ int nbNewNodes = quantities[iface];
+ face_nodes.assign( polygons_nodes.begin() + inode,
+ polygons_nodes.begin() + inode + nbNewNodes );
+ inode += nbNewNodes;
+ if ( isQuad ) // check if a result elem is a valid quadratic polygon
+ {
+ bool isValid = ( nbNewNodes % 2 == 0 );
+ for ( int i = 0; i < nbNewNodes && isValid; ++i )
+ isValid = ( elem->IsMediumNode( face_nodes[i]) == bool( i % 2 ));
+ elemType->SetQuad( isValid );
+ if ( isValid ) // put medium nodes after corners
+ SMDS_MeshCell::applyInterlaceRev
+ ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon,
+ nbNewNodes ), face_nodes );
+ }
+ elemType->SetPoly(( nbNewNodes / ( elemType->myIsQuad + 1 ) > 4 ));
+ }
+ nbUniqueNodes = newElemDefs[0].myNodes.size();
+ break;
+ } // Polygon
+
+ case SMDSEntity_Polyhedra: // Polyhedral volume
+ {
+ if ( nbUniqueNodes >= 4 )
+ {
+ // each face has to be analyzed in order to check volume validity
+ if ( const SMDS_VtkVolume* aPolyedre = dynamic_cast( elem ))
+ {
+ int nbFaces = aPolyedre->NbFaces();
+
+ vector& poly_nodes = newElemDefs[0].myNodes;
+ vector & quantities = newElemDefs[0].myPolyhedQuantities;
+ vector faceNodes;
+ poly_nodes.clear();
+ quantities.clear();
+
+ for (int iface = 1; iface <= nbFaces; iface++)
+ {
+ int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
+ faceNodes.resize( nbFaceNodes );
+ for (int inode = 1; inode <= nbFaceNodes; inode++)
+ {
+ const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
+ TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
+ if ( nnIt != nodeNodeMap.end() ) // faceNode sticks
+ faceNode = (*nnIt).second;
+ faceNodes[inode - 1] = faceNode;
+ }
+ SimplifyFace(faceNodes, poly_nodes, quantities);
+ }
+
+ if ( quantities.size() > 3 )
+ {
+ // TODO: remove coincident faces
+ nbResElems = 1;
+ nbUniqueNodes = newElemDefs[0].myNodes.size();
+ }
+ }
+ }
+ }
+ break;
+
+ // 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] )))
+ {
+ 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;
+ }
+ }
+ 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 == 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 indB;
+ for ( iCur = 0; iCur < 4; iCur++ )
+ if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
+ indB.push_back( ind[iCur] );
+ if ( !hexa.IsForward() )
+ std::swap( indB[0], indB[2] );
+ for ( iCur = 0; iCur < 3; iCur++ )
+ uniqueNodes[ iCur ] = curNodes[indB[iCur]];
+ // set nodes of the top triangle
+ const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
+ for ( iCur = 0; iCur < 3; ++iCur )
+ for ( int j = 0; j < 4; ++j )
+ if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
+ {
+ uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
+ break;
+ }
+ toRemove = false;
+ break;
+ }
+ }
+ else if (nbUniqueNodes == 5 && nbRepl == 3 ) {
+ //////////////////// HEXAHEDRON ---> pyramid
+ for ( int iFace = 0; iFace < 6; iFace++ ) {
+ const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
+ if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
+ curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
+ curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
+ // one face turns into a point ...
+ int iOppFace = hexa.GetOppFaceIndex( iFace );
+ ind = hexa.GetFaceNodesIndices( iOppFace );
+ uniqueNodes.clear();
+ for ( iCur = 0; iCur < 4; iCur++ ) {
+ if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
+ break;
+ else
+ uniqueNodes.push_back( curNodes[ind[ iCur ]]);
+ }
+ if ( uniqueNodes.size() == 4 ) {
+ // ... and the opposite one is a quadrangle
+ // set a top node
+ const int* indTop = hexa.GetFaceNodesIndices( iFace );
+ uniqueNodes.push_back( curNodes[indTop[ 0 ]]);
+ toRemove = false;
+ }
+ break;
+ }
+ }
+ }
+
+ if ( toRemove && nbUniqueNodes > 4 ) {
+ ////////////////// HEXAHEDRON ---> polyhedron
+ hexa.SetExternalNormal();
+ vector& poly_nodes = newElemDefs[0].myNodes;
+ vector & quantities = newElemDefs[0].myPolyhedQuantities;
+ poly_nodes.reserve( 6 * 4 ); poly_nodes.clear();
+ quantities.reserve( 6 ); quantities.clear();
+ for ( int iFace = 0; iFace < 6; iFace++ )
+ {
+ const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
+ if ( curNodes[ind[0]] == curNodes[ind[2]] ||
+ curNodes[ind[1]] == curNodes[ind[3]] )
+ {
+ quantities.clear();
+ break; // opposite nodes stick
+ }
+ nodeSet.clear();
+ for ( iCur = 0; iCur < 4; iCur++ )
+ {
+ if ( nodeSet.insert( curNodes[ind[ iCur ]] ).second )
+ poly_nodes.push_back( curNodes[ind[ iCur ]]);
+ }
+ if ( nodeSet.size() < 3 )
+ poly_nodes.resize( poly_nodes.size() - nodeSet.size() );
+ else
+ quantities.push_back( nodeSet.size() );
+ }
+ if ( quantities.size() >= 4 )
+ {
+ nbResElems = 1;
+ nbUniqueNodes = poly_nodes.size();
+ newElemDefs[0].SetPoly(true);
+ }
+ }
+ break;
+ } // case HEXAHEDRON
+
+ default:
+ toRemove = true;
+
+ } // switch ( entity )
+
+ if ( toRemove && nbResElems == 0 && avoidMakingHoles )
+ {
+ // 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
+
+ uniqueNodes.resize( nbUniqueNodes );
+
+ if ( !toRemove && nbResElems == 0 )
+ nbResElems = 1;
+
+ newElemDefs.resize( nbResElems );
+
+ return !toRemove;
+}
+
// ========================================================
// class : SortableElement
diff --git a/src/SMESH/SMESH_MeshEditor.hxx b/src/SMESH/SMESH_MeshEditor.hxx
index fd0418c6a..663b6ae16 100644
--- a/src/SMESH/SMESH_MeshEditor.hxx
+++ b/src/SMESH/SMESH_MeshEditor.hxx
@@ -83,11 +83,12 @@ public:
// --------------------------------------------------------------------------------
struct ElemFeatures //!< Features of element to create
{
- SMDSAbs_ElementType myType;
- bool myIsPoly, myIsQuad;
- int myID;
- double myBallDiameter;
- std::vector myPolyhedQuantities;
+ SMDSAbs_ElementType myType;
+ bool myIsPoly, myIsQuad;
+ int myID;
+ double myBallDiameter;
+ std::vector myPolyhedQuantities;
+ std::vector 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) {}
@@ -750,6 +751,20 @@ public:
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
@@ -782,11 +797,11 @@ public:
double Angle ()const { return myAngle; }
double Parameter ()const { return myPrm; }
};
- Extrusion_Error MakeEdgePathPoints(std::list& aPrms,
+ Extrusion_Error makeEdgePathPoints(std::list& aPrms,
const TopoDS_Edge& aTrackEdge,
bool aFirstIsStart,
std::list& aLPP);
- Extrusion_Error MakeExtrElements(TIDSortedElemSet theElements[2],
+ Extrusion_Error makeExtrElements(TIDSortedElemSet theElements[2],
std::list& theFullList,
const bool theHasAngles,
std::list& theAngles,
@@ -794,7 +809,7 @@ public:
const bool theHasRefPoint,
const gp_Pnt& theRefPoint,
const bool theMakeGroups);
- static void LinearAngleVariation(const int NbSteps,
+ static void linearAngleVariation(const int NbSteps,
std::list& theAngles);
bool doubleNodes( SMESHDS_Mesh* theMeshDS,
diff --git a/src/SMESHGUI/SMESHGUI.cxx b/src/SMESHGUI/SMESHGUI.cxx
index 41d4c42bd..1f3435241 100644
--- a/src/SMESHGUI/SMESHGUI.cxx
+++ b/src/SMESHGUI/SMESHGUI.cxx
@@ -215,29 +215,34 @@ namespace
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)" );
}
@@ -283,6 +288,7 @@ namespace
try {
switch ( theCommandID ) {
case SMESHOp::OpImportDAT:
+ case SMESHOp::OpPopupImportDAT:
{
// DAT format (currently unsupported)
errors.append( QString( "%1 :\n\t%2" ).arg( filename ).
@@ -290,6 +296,7 @@ namespace
break;
}
case SMESHOp::OpImportUNV:
+ case SMESHOp::OpPopupImportUNV:
{
// UNV format
aMeshes->length( 1 );
@@ -300,6 +307,7 @@ namespace
break;
}
case SMESHOp::OpImportMED:
+ case SMESHOp::OpPopupImportMED:
{
// MED format
SMESH::DriverMED_ReadStatus res;
@@ -311,6 +319,7 @@ namespace
break;
}
case SMESHOp::OpImportSTL:
+ case SMESHOp::OpPopupImportSTL:
{
// STL format
aMeshes->length( 1 );
@@ -321,8 +330,8 @@ namespace
}
break;
}
- #ifdef WITH_CGNS
case SMESHOp::OpImportCGNS:
+ case SMESHOp::OpPopupImportCGNS:
{
// CGNS format
SMESH::DriverMED_ReadStatus res;
@@ -333,8 +342,8 @@ namespace
}
break;
}
- #endif
case SMESHOp::OpImportSAUV:
+ case SMESHOp::OpPopupImportSAUV:
{
// SAUV format
SMESH::DriverMED_ReadStatus res;
@@ -346,6 +355,7 @@ namespace
break;
}
case SMESHOp::OpImportGMF:
+ case SMESHOp::OpPopupImportGMF:
{
// GMF format
SMESH::ComputeError_var res;
@@ -433,12 +443,8 @@ namespace
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 ||
@@ -2451,11 +2457,16 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
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);
@@ -2484,18 +2495,14 @@ bool SMESHGUI::OnGUIEvent( int 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:
{
@@ -2671,9 +2678,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
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())
@@ -3821,13 +3826,21 @@ void SMESHGUI::initialize( CAM_Application* app )
//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" );
@@ -4364,6 +4377,7 @@ void SMESHGUI::initialize( CAM_Application* app )
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 ) ).
@@ -4442,6 +4456,17 @@ void SMESHGUI::initialize( CAM_Application* app )
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
diff --git a/src/SMESHGUI/SMESHGUI_MergeDlg.cxx b/src/SMESHGUI/SMESHGUI_MergeDlg.cxx
index e5dcf5d12..2aba558af 100644
--- a/src/SMESHGUI/SMESHGUI_MergeDlg.cxx
+++ b/src/SMESHGUI/SMESHGUI_MergeDlg.cxx
@@ -191,6 +191,9 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
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);
@@ -198,6 +201,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
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
@@ -585,12 +589,12 @@ bool SMESHGUI_MergeDlg::ClickOnApply()
}
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
diff --git a/src/SMESHGUI/SMESHGUI_MergeDlg.h b/src/SMESHGUI/SMESHGUI_MergeDlg.h
index 5e827abc8..6b087b631 100644
--- a/src/SMESHGUI/SMESHGUI_MergeDlg.h
+++ b/src/SMESHGUI/SMESHGUI_MergeDlg.h
@@ -130,6 +130,7 @@ private:
QWidget* NodeSpecWidget;
SMESHGUI_SpinBox* SpinBoxTolerance;
QCheckBox* SeparateCornersAndMedium;
+ QCheckBox* AvoidMakingHoles;
QGroupBox* GroupCoincident;
//QWidget* GroupCoincidentWidget;
diff --git a/src/SMESHGUI/SMESHGUI_Operations.h b/src/SMESHGUI/SMESHGUI_Operations.h
index df810f7df..89f53472b 100644
--- a/src/SMESHGUI/SMESHGUI_Operations.h
+++ b/src/SMESHGUI/SMESHGUI_Operations.h
@@ -32,37 +32,36 @@ namespace SMESHOp {
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 ---------------------------//--------------------------------
diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts
index bbbccbcfd..2a0601830 100644
--- a/src/SMESHGUI/SMESH_msg_en.ts
+++ b/src/SMESHGUI/SMESH_msg_en.ts
@@ -5322,6 +5322,10 @@ Please select a group and try again
SEPARATE_CORNERS_AND_MEDIUMNo merge of corner and medium nodes of quadratic cells
+
+ AVOID_MAKING_HOLES
+ Avoid making holes
+ KEEP_NODESNodes to keep during the merge
diff --git a/src/SMESHUtils/CMakeLists.txt b/src/SMESHUtils/CMakeLists.txt
index c21a8a6d5..3641d913c 100644
--- a/src/SMESHUtils/CMakeLists.txt
+++ b/src/SMESHUtils/CMakeLists.txt
@@ -83,7 +83,8 @@ SET(SMESHUtils_SOURCES
SMESH_MAT2d.cxx
SMESH_FreeBorders.cxx
SMESH_ControlPnt.cxx
-)
+ SMESH_DeMerge.cxx
+ )
# --- rules ---
diff --git a/src/SMESHUtils/SMESH_DeMerge.cxx b/src/SMESHUtils/SMESH_DeMerge.cxx
new file mode 100644
index 000000000..427ce5270
--- /dev/null
+++ b/src/SMESHUtils/SMESH_DeMerge.cxx
@@ -0,0 +1,215 @@
+// 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::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:;
+ }
+}
diff --git a/src/SMESHUtils/SMESH_MeshAlgos.hxx b/src/SMESHUtils/SMESH_MeshAlgos.hxx
index b6c3661b0..1114bfe02 100644
--- a/src/SMESHUtils/SMESH_MeshAlgos.hxx
+++ b/src/SMESHUtils/SMESH_MeshAlgos.hxx
@@ -206,6 +206,16 @@ namespace SMESH_MeshAlgos
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
diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx
index 990af7876..c0248c87e 100644
--- a/src/SMESH_I/SMESH_MeshEditor_i.cxx
+++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx
@@ -4159,7 +4159,8 @@ FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr theObject,
//=======================================================================
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;
@@ -4203,7 +4204,7 @@ void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfN
aTPythonDump << aNodeGroup;
}
- getEditor().MergeNodes( aListOfListOfNodes );
+ getEditor().MergeNodes( aListOfListOfNodes, AvoidMakingHoles );
aTPythonDump << "], " << NodesToKeep << ")";
diff --git a/src/SMESH_I/SMESH_MeshEditor_i.hxx b/src/SMESH_I/SMESH_MeshEditor_i.hxx
index b7022a968..74eaa36ad 100644
--- a/src/SMESH_I/SMESH_MeshEditor_i.hxx
+++ b/src/SMESH_I/SMESH_MeshEditor_i.hxx
@@ -495,7 +495,8 @@ public:
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)
diff --git a/src/SMESH_I/SMESH_Mesh_i.cxx b/src/SMESH_I/SMESH_Mesh_i.cxx
index 887014be0..a075dadce 100644
--- a/src/SMESH_I/SMESH_Mesh_i.cxx
+++ b/src/SMESH_I/SMESH_Mesh_i.cxx
@@ -496,7 +496,13 @@ int SMESH_Mesh_i::ImportSTLFile( const char* theFileName )
SMESH_TRY;
// Read mesh with name = 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 );
@@ -3144,9 +3150,15 @@ void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii)
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() );
}
//================================================================================
@@ -3595,8 +3607,14 @@ void SMESH_Mesh_i::ExportPartToSTL(::SMESH::SMESH_IDSource_ptr meshPart,
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 << ")";
diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py
index 5b94cd28d..d87d0d553 100644
--- a/src/SMESH_SWIG/smeshBuilder.py
+++ b/src/SMESH_SWIG/smeshBuilder.py
@@ -4566,10 +4566,12 @@ class Mesh:
# @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
@@ -5125,17 +5127,18 @@ class meshEditor(SMESH._objref_SMESH_MeshEditor):
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)