From 4eb3d6212746a4224253188870504267877d2a08 Mon Sep 17 00:00:00 2001 From: prascle Date: Sun, 25 Jul 2010 08:13:16 +0000 Subject: [PATCH] smds_memimp_joints --- idl/SMESH_MeshEditor.idl | 13 ++ src/SMDS/SMDS_Downward.cxx | 92 +++++++++++++ src/SMDS/SMDS_Downward.hxx | 38 +++++- src/SMDS/SMDS_FaceOfEdges.hxx | 3 +- src/SMDS/SMDS_LinearEdge.hxx | 4 + src/SMDS/SMDS_Mesh.cxx | 92 +++++++------ src/SMDS/SMDS_Mesh.hxx | 6 +- src/SMDS/SMDS_Mesh0DElement.hxx | 1 + src/SMDS/SMDS_MeshCell.hxx | 3 + src/SMDS/SMDS_MeshIDFactory.cxx | 1 + src/SMDS/SMDS_MeshIDFactory.hxx | 1 + src/SMDS/SMDS_UnstructuredGrid.cxx | 107 ++++++++++++++- src/SMDS/SMDS_UnstructuredGrid.hxx | 12 +- src/SMDS/SMDS_VolumeOfFaces.hxx | 1 + src/SMDS/SMDS_VtkEdge.cxx | 7 + src/SMDS/SMDS_VtkEdge.hxx | 1 + src/SMDS/SMDS_VtkFace.cxx | 1 + src/SMDS/SMDS_VtkVolume.cxx | 2 +- src/SMESH/SMESH_MeshEditor.cxx | 211 ++++++++++++++++++++++++++++- src/SMESH/SMESH_MeshEditor.hxx | 3 + src/SMESHDS/SMESHDS_Mesh.cxx | 53 +++++++- src/SMESHDS/SMESHDS_Mesh.hxx | 4 + src/SMESH_I/SMESH_MeshEditor_i.cxx | 48 +++++++ src/SMESH_I/SMESH_MeshEditor_i.hxx | 14 ++ src/SMESH_SWIG/smeshDC.py | 11 ++ 25 files changed, 674 insertions(+), 55 deletions(-) diff --git a/idl/SMESH_MeshEditor.idl b/idl/SMESH_MeshEditor.idl index 983b2f486..5e8c8c5f3 100644 --- a/idl/SMESH_MeshEditor.idl +++ b/idl/SMESH_MeshEditor.idl @@ -869,6 +869,19 @@ module SMESH */ boolean Make2DMeshFrom3D(); + /*! + * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand. + * The list of groups must describe a partition of the mesh volumes. + * The nodes of the internal faces at the boundaries of the groups are doubled. + * In option, the internal faces are replaced by flat elements. + * Triangles are transformed in prisms, and quadrangles in hexahedrons. + * \param theDomains - list of groups of volumes + * \param createJointElems - if TRUE, create the elements + * \return TRUE if operation has been completed successfully, FALSE otherwise + */ + boolean DoubleNodesOnGroupBoundaries( in ListOfGroups theDomains, + in boolean createJointElems ); + }; }; diff --git a/src/SMDS/SMDS_Downward.cxx b/src/SMDS/SMDS_Downward.cxx index f3fbd0efc..6875aebd5 100644 --- a/src/SMDS/SMDS_Downward.cxx +++ b/src/SMDS/SMDS_Downward.cxx @@ -265,6 +265,12 @@ const unsigned char* SMDS_Down1D::getUpTypes(int cellId) return &_upCellTypes[_upCellIndex[cellId]]; } +void SMDS_Down1D::getNodeIds(int cellId, std::set& nodeSet) +{ + for (int i = 0; i < _nbDownCells; i++) + nodeSet.insert(_cellIds[_nbDownCells * cellId + i]); +} + int SMDS_Down1D::getNodeSet(int cellId, int* nodeSet) { for (int i = 0; i < _nbDownCells; i++) @@ -481,6 +487,16 @@ const unsigned char* SMDS_Down2D::getUpTypes(int cellId) return &_upCellTypes[2 * cellId]; } +void SMDS_Down2D::getNodeIds(int cellId, std::set& nodeSet) +{ + for (int i = 0; i < _nbDownCells; i++) + { + int downCellId = _cellIds[_nbDownCells * cellId + i]; + unsigned char cellType = _cellTypes[i]; + this->_grid->getDownArray(cellType)->getNodeIds(downCellId, nodeSet); + } +} + /*! Find in vtkUnstructuredGrid the volumes containing a face already stored in vtkUnstructuredGrid. * Search the volumes containing a face, to store the info in SMDS_Down2D for later uses * with SMDS_Down2D::getUpCells and SMDS_Down2D::getUpTypes. @@ -753,6 +769,16 @@ const unsigned char* SMDS_Down3D::getUpTypes(int cellId) return 0; } +void SMDS_Down3D::getNodeIds(int cellId, std::set& nodeSet) +{ + int vtkId = this->_vtkCellIds[cellId]; + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(vtkId, npts, nodes); + for (int i = 0; i < npts; i++) + nodeSet.insert(nodes[i]); +} + int SMDS_Down3D::FindFaceByNodes(int cellId, ElemByNodesType& faceByNodes) { int *faces = &_cellIds[_nbDownCells * cellId]; @@ -1074,6 +1100,37 @@ SMDS_DownTetra::~SMDS_DownTetra() { } +void SMDS_DownTetra::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + set setNodes; + setNodes.clear(); + for (int i = 0; i < orderedNodes.size(); i++) + setNodes.insert(orderedNodes[i]); + //MESSAGE("cellId = " << cellId); + + vtkIdType npts = 0; + vtkIdType *nodes; // will refer to the point id's of the volume + _grid->GetCellPoints(this->_vtkCellIds[cellId], npts, nodes); + + set tofind; + int ids[12] = { 0, 1, 2, 0, 1, 3, 0, 2, 3, 1, 2, 3 }; + for (int k = 0; k < 4; k++) + { + tofind.clear(); + for (int i = 0; i < 3; i++) + tofind.insert(nodes[ids[3 * k + i]]); + if (setNodes == tofind) + { + for (int i = 0; i < 3; i++) + orderedNodes[i] = nodes[ids[3 * k + i]]; + return; + } + } + MESSAGE("=== Problem volume " << _vtkCellIds[cellId] << " " << _grid->_mesh->fromVtkToSmds(_vtkCellIds[cellId])); + MESSAGE(orderedNodes[0] << " " << orderedNodes[1] << " " << orderedNodes[2]); + MESSAGE(nodes[0] << " " << nodes[1] << " " << nodes[2] << " " << nodes[3]); +} + void SMDS_DownTetra::addDownCell(int cellId, int lowCellId, unsigned char aType) { //ASSERT((cellId >=0)&& (cellId < _maxId)); @@ -1150,6 +1207,11 @@ SMDS_DownQuadTetra::~SMDS_DownQuadTetra() { } +void SMDS_DownQuadTetra::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + // TODO +} + void SMDS_DownQuadTetra::addDownCell(int cellId, int lowCellId, unsigned char aType) { //ASSERT((cellId >=0)&& (cellId < _maxId)); @@ -1241,6 +1303,11 @@ SMDS_DownPyramid::~SMDS_DownPyramid() { } +void SMDS_DownPyramid::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + // TODO +} + void SMDS_DownPyramid::addDownCell(int cellId, int lowCellId, unsigned char aType) { //ASSERT((cellId >=0) && (cellId < _maxId)); @@ -1340,6 +1407,11 @@ SMDS_DownQuadPyramid::~SMDS_DownQuadPyramid() { } +void SMDS_DownQuadPyramid::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + // TODO +} + void SMDS_DownQuadPyramid::addDownCell(int cellId, int lowCellId, unsigned char aType) { //ASSERT((cellId >=0) && (cellId < _maxId)); @@ -1456,6 +1528,11 @@ SMDS_DownPenta::~SMDS_DownPenta() { } +void SMDS_DownPenta::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + // TODO +} + void SMDS_DownPenta::addDownCell(int cellId, int lowCellId, unsigned char aType) { //ASSERT((cellId >=0) && (cellId < _maxId)); @@ -1559,6 +1636,11 @@ SMDS_DownQuadPenta::~SMDS_DownQuadPenta() { } +void SMDS_DownQuadPenta::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + // TODO +} + void SMDS_DownQuadPenta::addDownCell(int cellId, int lowCellId, unsigned char aType) { //ASSERT((cellId >=0) && (cellId < _maxId)); @@ -1682,6 +1764,11 @@ SMDS_DownHexa::~SMDS_DownHexa() { } +void SMDS_DownHexa::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + // TODO +} + void SMDS_DownHexa::addDownCell(int cellId, int lowCellId, unsigned char aType) { //ASSERT((cellId >=0)&& (cellId < _maxId)); @@ -1780,6 +1867,11 @@ SMDS_DownQuadHexa::~SMDS_DownQuadHexa() { } +void SMDS_DownQuadHexa::getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) +{ + // TODO +} + void SMDS_DownQuadHexa::addDownCell(int cellId, int lowCellId, unsigned char aType) { //ASSERT((cellId >=0)&& (cellId < _maxId)); diff --git a/src/SMDS/SMDS_Downward.hxx b/src/SMDS/SMDS_Downward.hxx index fd4eca020..d9b12a054 100644 --- a/src/SMDS/SMDS_Downward.hxx +++ b/src/SMDS/SMDS_Downward.hxx @@ -26,6 +26,28 @@ typedef struct int nbElems; } ListElemByNodesType; // TODO resize for polyhedrons +class DownIdType +{ +public: + DownIdType(int a, unsigned char b) : + cellId(a), cellType(b) + { + } + int cellId; + unsigned char cellType; +}; + +struct DownIdCompare +{ + bool operator ()(const DownIdType e1, const DownIdType e2) const + { + if (e1.cellId == e2.cellId) + return (e1.cellType < e2.cellType); + else + return (e1.cellId < e2.cellId); + } +}; + class SMDS_Downward { friend class SMDS_UnstructuredGrid; @@ -38,6 +60,7 @@ public: virtual int getNumberOfUpCells(int cellId) = 0; virtual const int* getUpCells(int cellId) = 0; virtual const unsigned char* getUpTypes(int cellId) = 0; + virtual void getNodeIds(int cellId, std::set& nodeSet) = 0; int getVtkCellId(int cellId) { return _vtkCellIds[cellId]; @@ -75,6 +98,7 @@ public: virtual int getNumberOfUpCells(int cellId); virtual const int* getUpCells(int cellId); virtual const unsigned char* getUpTypes(int cellId); + virtual void getNodeIds(int cellId, std::set& nodeSet); protected: SMDS_Down1D(SMDS_UnstructuredGrid *grid, int nbDownCells); ~SMDS_Down1D(); @@ -105,6 +129,7 @@ public: virtual int getNumberOfUpCells(int cellId); virtual const int* getUpCells(int cellId); virtual const unsigned char* getUpTypes(int cellId); + virtual void getNodeIds(int cellId, std::set& nodeSet); protected: SMDS_Down2D(SMDS_UnstructuredGrid *grid, int nbDownCells); ~SMDS_Down2D(); @@ -134,6 +159,8 @@ public: virtual int getNumberOfUpCells(int cellId); virtual const int* getUpCells(int cellId); virtual const unsigned char* getUpTypes(int cellId); + virtual void getNodeIds(int cellId, std::set& nodeSet); + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes) = 0; protected: SMDS_Down3D(SMDS_UnstructuredGrid *grid, int nbDownCells); ~SMDS_Down3D(); @@ -225,6 +252,7 @@ class SMDS_DownTetra: public SMDS_Down3D { friend class SMDS_UnstructuredGrid; public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); protected: SMDS_DownTetra(SMDS_UnstructuredGrid *grid); ~SMDS_DownTetra(); @@ -236,6 +264,7 @@ class SMDS_DownQuadTetra: public SMDS_Down3D { friend class SMDS_UnstructuredGrid; public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); protected: SMDS_DownQuadTetra(SMDS_UnstructuredGrid *grid); ~SMDS_DownQuadTetra(); @@ -247,6 +276,7 @@ class SMDS_DownPyramid: public SMDS_Down3D { friend class SMDS_UnstructuredGrid; public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); protected: SMDS_DownPyramid(SMDS_UnstructuredGrid *grid); ~SMDS_DownPyramid(); @@ -258,6 +288,7 @@ class SMDS_DownQuadPyramid: public SMDS_Down3D { friend class SMDS_UnstructuredGrid; public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); protected: SMDS_DownQuadPyramid(SMDS_UnstructuredGrid *grid); ~SMDS_DownQuadPyramid(); @@ -267,18 +298,21 @@ protected: class SMDS_DownPenta: public SMDS_Down3D { + friend class SMDS_UnstructuredGrid; public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); +protected: SMDS_DownPenta(SMDS_UnstructuredGrid *grid); ~SMDS_DownPenta(); virtual void addDownCell(int cellId, int lowCellId, unsigned char aType); virtual void computeFacesWithNodes(int cellId, ListElemByNodesType& facesWithNodes); -protected: }; class SMDS_DownQuadPenta: public SMDS_Down3D { friend class SMDS_UnstructuredGrid; public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); protected: SMDS_DownQuadPenta(SMDS_UnstructuredGrid *grid); ~SMDS_DownQuadPenta(); @@ -290,6 +324,7 @@ class SMDS_DownHexa: public SMDS_Down3D { friend class SMDS_UnstructuredGrid; public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); protected: SMDS_DownHexa(SMDS_UnstructuredGrid *grid); ~SMDS_DownHexa(); @@ -301,6 +336,7 @@ class SMDS_DownQuadHexa: public SMDS_Down3D { friend class SMDS_UnstructuredGrid; public: + virtual void getOrderedNodesOfFace(int cellId, std::vector& orderedNodes); protected: SMDS_DownQuadHexa(SMDS_UnstructuredGrid *grid); ~SMDS_DownQuadHexa(); diff --git a/src/SMDS/SMDS_FaceOfEdges.hxx b/src/SMDS/SMDS_FaceOfEdges.hxx index 91acdb17a..bb757e852 100644 --- a/src/SMDS/SMDS_FaceOfEdges.hxx +++ b/src/SMDS/SMDS_FaceOfEdges.hxx @@ -20,7 +20,7 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SMESH SMDS : implementaion of Salome mesh data structure +// SMESH SMDS : implementation of Salome mesh data structure // #ifndef _SMDS_FaceOfEdges_HeaderFile #define _SMDS_FaceOfEdges_HeaderFile @@ -48,6 +48,7 @@ class SMDS_EXPORT SMDS_FaceOfEdges:public SMDS_MeshFace SMDSAbs_ElementType GetType() const; virtual SMDSAbs_EntityType GetEntityType() const; + virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) {return false;}; int NbNodes() const; int NbEdges() const; int NbFaces() const; diff --git a/src/SMDS/SMDS_LinearEdge.hxx b/src/SMDS/SMDS_LinearEdge.hxx index f8c702506..e7c66d7cf 100644 --- a/src/SMDS/SMDS_LinearEdge.hxx +++ b/src/SMDS/SMDS_LinearEdge.hxx @@ -43,6 +43,10 @@ public: { return SMDSEntity_Edge; } + virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) + { + return false; + } int NbNodes() const; int NbEdges() const; friend bool operator<(const SMDS_LinearEdge& e1, const SMDS_LinearEdge& e2); diff --git a/src/SMDS/SMDS_Mesh.cxx b/src/SMDS/SMDS_Mesh.cxx index 2c2aa6ed6..79f41cbbc 100644 --- a/src/SMDS/SMDS_Mesh.cxx +++ b/src/SMDS/SMDS_Mesh.cxx @@ -209,6 +209,7 @@ SMDS_MeshNode * SMDS_Mesh::AddNodeWithID(double x, double y, double z, int ID) if(!node){ //if ( myNodes.Extent() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); //SMDS_MeshNode * node=new SMDS_MeshNode(ID, myMeshId, -1, x, y, z); + myNodeIDFactory->adjustMaxId(ID); SMDS_MeshNode * node = myNodePool->getNew(); node->init(ID, myMeshId, -1, x, y, z); if (ID >= myNodes.size()) @@ -1453,6 +1454,7 @@ bool SMDS_Mesh::ChangeElementNodes(const SMDS_MeshElement * element, const SMDS_MeshNode * nodes[], const int nbnodes) { + // TODO use polymorphism, check number of nodes and type are unchanged. MYASSERT(0); // REVOIR LES TYPES // keep current nodes of elem set oldNodes; @@ -1465,47 +1467,51 @@ bool SMDS_Mesh::ChangeElementNodes(const SMDS_MeshElement * element, // change nodes bool Ok = false; - SMDS_MeshElement* elem = const_cast(element); - switch ( elem->GetType() ) - { - case SMDSAbs_0DElement: { - if ( SMDS_Mesh0DElement* elem0d = dynamic_cast( elem )) - Ok = elem0d->ChangeNode( nodes[0] ); - break; - } - case SMDSAbs_Edge: { - if ( nbnodes == 2 ) { - if ( SMDS_VtkEdge* edge = dynamic_cast( elem )) - Ok = edge->ChangeNodes( nodes[0], nodes[1] ); - } - else if ( nbnodes == 3 ) { - if ( SMDS_QuadraticEdge* edge = dynamic_cast( elem )) - Ok = edge->ChangeNodes( nodes[0], nodes[1], nodes[2] ); - } - break; - } - case SMDSAbs_Face: { - if ( SMDS_FaceOfNodes* face = dynamic_cast( elem )) - Ok = face->ChangeNodes( nodes, nbnodes ); - else - if ( SMDS_QuadraticFaceOfNodes* QF = dynamic_cast( elem )) - Ok = QF->ChangeNodes( nodes, nbnodes ); - else - if (SMDS_PolygonalFaceOfNodes* face = dynamic_cast(elem)) - Ok = face->ChangeNodes(nodes, nbnodes); - break; - } - case SMDSAbs_Volume: { - if ( SMDS_VolumeOfNodes* vol = dynamic_cast( elem )) - Ok = vol->ChangeNodes( nodes, nbnodes ); - else - if ( SMDS_QuadraticVolumeOfNodes* QV = dynamic_cast( elem )) - Ok = QV->ChangeNodes( nodes, nbnodes ); - break; - } - default: - MESSAGE ( "WRONG ELEM TYPE"); - } + SMDS_MeshCell* cell = dynamic_cast((SMDS_MeshElement*) element); + if (cell) + Ok = cell->ChangeNodes(nodes, nbnodes); + +// SMDS_MeshElement* elem = const_cast(element); +// switch ( elem->GetType() ) +// { +// case SMDSAbs_0DElement: { +// if ( SMDS_Mesh0DElement* elem0d = dynamic_cast( elem )) +// Ok = elem0d->ChangeNode( nodes[0] ); +// break; +// } +// case SMDSAbs_Edge: { +// if ( nbnodes == 2 ) { +// if ( SMDS_VtkEdge* edge = dynamic_cast( elem )) +// Ok = edge->ChangeNodes( nodes[0], nodes[1] ); +// } +// else if ( nbnodes == 3 ) { +// if ( SMDS_QuadraticEdge* edge = dynamic_cast( elem )) +// Ok = edge->ChangeNodes( nodes[0], nodes[1], nodes[2] ); +// } +// break; +// } +// case SMDSAbs_Face: { +// if ( SMDS_FaceOfNodes* face = dynamic_cast( elem )) +// Ok = face->ChangeNodes( nodes, nbnodes ); +// else +// if ( SMDS_QuadraticFaceOfNodes* QF = dynamic_cast( elem )) +// Ok = QF->ChangeNodes( nodes, nbnodes ); +// else +// if (SMDS_PolygonalFaceOfNodes* face = dynamic_cast(elem)) +// Ok = face->ChangeNodes(nodes, nbnodes); +// break; +// } +// case SMDSAbs_Volume: { +// if ( SMDS_VolumeOfNodes* vol = dynamic_cast( elem )) +// Ok = vol->ChangeNodes( nodes, nbnodes ); +// else +// if ( SMDS_QuadraticVolumeOfNodes* QV = dynamic_cast( elem )) +// Ok = QV->ChangeNodes( nodes, nbnodes ); +// break; +// } +// default: +// MESSAGE ( "WRONG ELEM TYPE"); +// } if ( Ok ) { // update InverseElements @@ -1516,7 +1522,7 @@ bool SMDS_Mesh::ChangeElementNodes(const SMDS_MeshElement * element, it = oldNodes.find( nodes[i] ); if ( it == oldNodes.end() ) // new node - const_cast( nodes[i] )->AddInverseElement( elem ); + const_cast( nodes[i] )->AddInverseElement( cell ); else // remove from oldNodes a node that remains in elem oldNodes.erase( it ); @@ -1526,7 +1532,7 @@ bool SMDS_Mesh::ChangeElementNodes(const SMDS_MeshElement * element, { SMDS_MeshNode * n = static_cast (const_cast( *it )); - n->RemoveInverseElement( elem ); + n->RemoveInverseElement( cell ); } } diff --git a/src/SMDS/SMDS_Mesh.hxx b/src/SMDS/SMDS_Mesh.hxx index d827ab18e..83204682a 100644 --- a/src/SMDS/SMDS_Mesh.hxx +++ b/src/SMDS/SMDS_Mesh.hxx @@ -66,7 +66,7 @@ public: static std::vector _meshList; //! actual nodes coordinates, cells definition and reverse connectivity are stored in a vtkUnstructuredGrid - inline vtkUnstructuredGrid* getGrid() {return myGrid; }; + inline SMDS_UnstructuredGrid* getGrid() {return myGrid; }; inline int getMeshId() {return myMeshId; }; SMDS_NodeIteratorPtr nodesIterator(bool idInceasingOrder=false) const; @@ -573,7 +573,6 @@ public: void incrementCellsCapacity(int nbCells); void adjustStructure(); void dumpGrid(string ficdump="dumpGrid"); - static int chunkSize; protected: @@ -608,8 +607,9 @@ protected: inline void adjustmyCellsCapacity(int ID) { assert(ID >= 0); + myElementIDFactory->adjustMaxId(ID); if (ID >= myCells.size()) - myCells.resize(ID+SMDS_Mesh::chunkSize,0); + myCells.resize(ID+SMDS_Mesh::chunkSize,0); }; // Fields PRIVATE diff --git a/src/SMDS/SMDS_Mesh0DElement.hxx b/src/SMDS/SMDS_Mesh0DElement.hxx index 355986a4d..b13722291 100644 --- a/src/SMDS/SMDS_Mesh0DElement.hxx +++ b/src/SMDS/SMDS_Mesh0DElement.hxx @@ -35,6 +35,7 @@ class SMDS_EXPORT SMDS_Mesh0DElement: public SMDS_MeshCell public: SMDS_Mesh0DElement (const SMDS_MeshNode * node); bool ChangeNode (const SMDS_MeshNode * node); + virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) {return false;}; void Print (std::ostream & OS) const; SMDSAbs_ElementType GetType() const; diff --git a/src/SMDS/SMDS_MeshCell.hxx b/src/SMDS/SMDS_MeshCell.hxx index 96108c095..aa5ba12c9 100644 --- a/src/SMDS/SMDS_MeshCell.hxx +++ b/src/SMDS/SMDS_MeshCell.hxx @@ -12,6 +12,9 @@ class SMDS_EXPORT SMDS_MeshCell: public SMDS_MeshElement public: SMDS_MeshCell(); virtual ~SMDS_MeshCell(); + + virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes)= 0; + inline void setVtkId(int vtkId) { myVtkID = vtkId; diff --git a/src/SMDS/SMDS_MeshIDFactory.cxx b/src/SMDS/SMDS_MeshIDFactory.cxx index a1546e902..ccb2ad658 100644 --- a/src/SMDS/SMDS_MeshIDFactory.cxx +++ b/src/SMDS/SMDS_MeshIDFactory.cxx @@ -111,3 +111,4 @@ void SMDS_MeshIDFactory::emptyPool(int maxId) myMaxID = maxId-1; myPoolOfID.clear(); } + diff --git a/src/SMDS/SMDS_MeshIDFactory.hxx b/src/SMDS/SMDS_MeshIDFactory.hxx index 9f1393bd0..e936d0fed 100644 --- a/src/SMDS/SMDS_MeshIDFactory.hxx +++ b/src/SMDS/SMDS_MeshIDFactory.hxx @@ -45,6 +45,7 @@ public: SMDS_Mesh* GetMesh(); inline bool isPoolIdEmpty() { return myPoolOfID.empty(); }; void emptyPool(int maxId); + inline void adjustMaxId(int ID) { if (ID > myMaxID) myMaxID = ID;}; protected: SMDS_MeshIDFactory(); int myMaxID; diff --git a/src/SMDS/SMDS_UnstructuredGrid.cxx b/src/SMDS/SMDS_UnstructuredGrid.cxx index 35690ac53..1212276b8 100644 --- a/src/SMDS/SMDS_UnstructuredGrid.cxx +++ b/src/SMDS/SMDS_UnstructuredGrid.cxx @@ -303,9 +303,10 @@ void SMDS_UnstructuredGrid::setCellIdToDownId(int vtkCellId, int downId) * Downward connectivity is no more valid if vtkUnstructuredGrid is modified. * */ -void SMDS_UnstructuredGrid::BuildDownwardConnectivity() +void SMDS_UnstructuredGrid::BuildDownwardConnectivity(bool withEdges) { MESSAGE("SMDS_UnstructuredGrid::BuildDownwardConnectivity");CHRONO(2); + // TODO calcul partiel sans edges // --- erase previous data if any @@ -665,3 +666,107 @@ void SMDS_UnstructuredGrid::BuildDownwardConnectivity() }CHRONOSTOP(24);CHRONOSTOP(2); _counters->stats(); } + +/*! Get the neighbors of a cell. + * Only the neighbors having the dimension of the cell are taken into account + * (neighbors of a volume are the volumes sharing a face with this volume, + * neighbors of a face are the faces sharing an edge with this face...). + * @param neighborsVtkIds vector of neighbors vtk id's to fill (reserve enough space). + * @param downIds downward id's of cells of dimension n-1, to fill (reserve enough space). + * @param downTypes vtk types of cells of dimension n-1, to fill (reserve enough space). + * @param vtkId the vtk id of the cell + * @return number of neighbors + */ +int SMDS_UnstructuredGrid::GetNeighbors(int* neighborsVtkIds, int* downIds, unsigned char* downTypes, int vtkId) +{ + int vtkType = this->GetCellType(vtkId); + int cellDim = SMDS_Downward::getCellDimension(vtkType); + if (cellDim != 3) + return 0; // TODO voisins des faces ou edges + int cellId = this->_cellIdToDownId[vtkId]; + + int nbCells = _downArray[vtkType]->getNumberOfDownCells(cellId); + const int *downCells = _downArray[vtkType]->getDownCells(cellId); + const unsigned char* downTyp = _downArray[vtkType]->getDownTypes(cellId); + + // --- iteration on faces of the 3D cell. + + int nb = 0; + for (int i = 0; i < nbCells; i++) + { + int downId = downCells[i]; + int cellType = downTyp[i]; + int nbUp = _downArray[cellType]->getNumberOfUpCells(downId); + const int *upCells = _downArray[cellType]->getUpCells(downId); + const unsigned char* upTypes = _downArray[cellType]->getUpTypes(downId); + + // --- max 2 upCells, one is this cell, the other is a neighbor + + for (int j = 0; j < nbUp; j++) + { + if ((upCells[j] == cellId) && (upTypes[j] == vtkType)) + continue; + int vtkNeighbor = _downArray[upTypes[j]]->getVtkCellId(upCells[j]); + neighborsVtkIds[nb] = vtkNeighbor; + downIds[nb] = downId; + downTypes[nb] = cellType; + nb++; + } + if (nb >= NBMAXNEIGHBORS) + assert(0); + } + return nb; +} + +/*! get the node id's of a cell. + * The cell is defined by it's downward connectivity id and type. + * @param nodeSet set of of vtk node id's to fill. + * @param downId downward connectivity id of the cell. + * @param downType type of cell. + */ +void SMDS_UnstructuredGrid::GetNodeIds(std::set& nodeSet, int downId, unsigned char downType) +{ + _downArray[downType]->getNodeIds(downId, nodeSet); +} + +/*! change some nodes in cell without modifying type or internal connectivity. + * Nodes inverse connectivity is maintained up to date. + * @param vtkVolId vtk id of the cell + * @param localClonedNodeIds map old node id to new node id. + */ +void SMDS_UnstructuredGrid::ModifyCellNodes(int vtkVolId, std::map localClonedNodeIds) +{ + vtkIdType npts = 0; + vtkIdType *pts; // will refer to the point id's of the face + this->GetCellPoints(vtkVolId, npts, pts); + for (int i = 0; i < npts; i++) + { + if (localClonedNodeIds.count(pts[i])) + { + vtkIdType oldpt = pts[i]; + pts[i] = localClonedNodeIds[oldpt]; + //MESSAGE(oldpt << " --> " << pts[i]); + //this->RemoveReferenceToCell(oldpt, vtkVolId); + //this->AddReferenceToCell(pts[i], vtkVolId); + } + } +} + +/*! Create a volume (prism or hexahedron) by duplication of a face. + * the nodes of the new face are already created. + * @param vtkVolId vtk id of a volume containing the face, to get an orientation for the face. + * @param localClonedNodeIds map old node id to new node id. + * @return vtk id of the new volume. + */ +int SMDS_UnstructuredGrid::getOrderedNodesOfFace(int vtkVolId, std::vector& orderedNodes) +{ + int vtkType = this->GetCellType(vtkVolId); + int cellDim = SMDS_Downward::getCellDimension(vtkType); + if (cellDim != 3) + return 0; + SMDS_Down3D *downvol = static_cast (_downArray[vtkType]); + int downVolId = this->_cellIdToDownId[vtkVolId]; + downvol->getOrderedNodesOfFace(downVolId, orderedNodes); + return orderedNodes.size(); +} + diff --git a/src/SMDS/SMDS_UnstructuredGrid.hxx b/src/SMDS/SMDS_UnstructuredGrid.hxx index 30a074753..d204a5c89 100644 --- a/src/SMDS/SMDS_UnstructuredGrid.hxx +++ b/src/SMDS/SMDS_UnstructuredGrid.hxx @@ -9,10 +9,14 @@ #define _SMDS_UNSTRUCTUREDGRID_HXX #include +#include +#include #include #include "chrono.hxx" +#define NBMAXNEIGHBORS 10 + class SMDS_Downward; class SMDS_Mesh; @@ -29,7 +33,11 @@ public: int CellIdToDownId(int vtkCellId); void setCellIdToDownId(int vtkCellId, int downId); - void BuildDownwardConnectivity(); + void BuildDownwardConnectivity(bool withEdges); + int GetNeighbors(int* neighborsVtkIds, int* downIds, unsigned char* downTypes, int vtkId); + void GetNodeIds(std::set& nodeSet, int downId, unsigned char downType); + void ModifyCellNodes(int vtkVolId, std::map localClonedNodeIds); + int getOrderedNodesOfFace(int vtkVolId, std::vector& orderedNodes); vtkCellLinks* GetLinks() { return Links; @@ -39,6 +47,7 @@ public: return _downArray[vtkType]; } static SMDS_UnstructuredGrid* New(); + SMDS_Mesh *_mesh; protected: SMDS_UnstructuredGrid(); ~SMDS_UnstructuredGrid(); @@ -47,7 +56,6 @@ protected: vtkCellArray* newConnectivity, vtkIdTypeArray* newLocations, vtkIdType* pointsCell, int& alreadyCopied, int start, int end); - SMDS_Mesh *_mesh; std::vector _cellIdToDownId; //!< convert vtk Id to downward[vtkType] id, initialized with -1 std::vector _downTypes; std::vector _downArray; diff --git a/src/SMDS/SMDS_VolumeOfFaces.hxx b/src/SMDS/SMDS_VolumeOfFaces.hxx index 1b3c8374f..1b93c68a0 100644 --- a/src/SMDS/SMDS_VolumeOfFaces.hxx +++ b/src/SMDS/SMDS_VolumeOfFaces.hxx @@ -56,6 +56,7 @@ class SMDS_EXPORT SMDS_VolumeOfFaces:public SMDS_MeshVolume const SMDS_MeshFace * face6); virtual SMDSAbs_EntityType GetEntityType() const; + virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) {return false;}; void Print(std::ostream & OS) const; int NbFaces() const; diff --git a/src/SMDS/SMDS_VtkEdge.cxx b/src/SMDS/SMDS_VtkEdge.cxx index 34745b44f..923a6212b 100644 --- a/src/SMDS/SMDS_VtkEdge.cxx +++ b/src/SMDS/SMDS_VtkEdge.cxx @@ -37,6 +37,13 @@ void SMDS_VtkEdge::init(std::vector nodeIds, SMDS_Mesh* mesh) bool SMDS_VtkEdge::ChangeNodes(const SMDS_MeshNode * node1, const SMDS_MeshNode * node2) { + // TODO remove + return true; +} + +bool SMDS_VtkEdge::ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) +{ + // TODO return true; } diff --git a/src/SMDS/SMDS_VtkEdge.hxx b/src/SMDS/SMDS_VtkEdge.hxx index f37721141..b68b904f7 100644 --- a/src/SMDS/SMDS_VtkEdge.hxx +++ b/src/SMDS/SMDS_VtkEdge.hxx @@ -16,6 +16,7 @@ public: ~SMDS_VtkEdge(); void init(std::vector nodeIds, SMDS_Mesh* mesh); bool ChangeNodes(const SMDS_MeshNode * node1, const SMDS_MeshNode * node2); + virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes); void Print(std::ostream & OS) const; int NbNodes() const; diff --git a/src/SMDS/SMDS_VtkFace.cxx b/src/SMDS/SMDS_VtkFace.cxx index ade2f5ce0..763219c39 100644 --- a/src/SMDS/SMDS_VtkFace.cxx +++ b/src/SMDS/SMDS_VtkFace.cxx @@ -51,6 +51,7 @@ void SMDS_VtkFace::init(std::vector nodeIds, SMDS_Mesh* mesh) bool SMDS_VtkFace::ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) { + // TODO return true; } diff --git a/src/SMDS/SMDS_VtkVolume.cxx b/src/SMDS/SMDS_VtkVolume.cxx index c8865d6ba..f333a8267 100644 --- a/src/SMDS/SMDS_VtkVolume.cxx +++ b/src/SMDS/SMDS_VtkVolume.cxx @@ -61,7 +61,7 @@ void SMDS_VtkVolume::init(std::vector nodeIds, SMDS_Mesh* mesh) bool SMDS_VtkVolume::ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) { - // utilise dans SMDS_Mesh + // TODO utilise dans SMDS_Mesh return true; } diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index 2a52ec831..ac727041e 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -36,6 +36,7 @@ #include "SMDS_QuadraticFaceOfNodes.hxx" #include "SMDS_MeshGroup.hxx" #include "SMDS_LinearEdge.hxx" +#include "SMDS_Downward.hxx" #include "SMESHDS_Group.hxx" #include "SMESHDS_Mesh.hxx" @@ -798,7 +799,7 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1, return false; //MESSAGE( endl << tr1 << tr2 ); - + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 ); myLastCreatedElems.Append(tr1); GetMeshDS()->RemoveElement( tr2 ); @@ -844,6 +845,7 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1, aNodes[6] = N2[3]; aNodes[7] = N1[5]; + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 ); myLastCreatedElems.Append(tr1); GetMeshDS()->RemoveElement( tr2 ); @@ -1017,11 +1019,13 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, if ( aBadRate1 <= aBadRate2 ) { // tr1 + tr2 is better + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( elem, aNodes, 3 ); newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] ); } else { // tr3 + tr4 is better + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( elem, &aNodes[1], 3 ); newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] ); } @@ -1097,6 +1101,7 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1], aNodes[7], aNodes[4], newN ); } + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( elem, N, 6 ); } // quadratic case @@ -1729,10 +1734,12 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, int aShapeId = FindShape( elem ); const SMDS_MeshElement* newElem = 0; if ( the13Diag ) { + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( elem, aNodes, 3 ); newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] ); } else { + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( elem, &aNodes[1], 3 ); newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] ); } @@ -1818,6 +1825,7 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, aNodes[7], aNodes[4], newN ); } myLastCreatedElems.Append(newElem); + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( elem, N, 6 ); // put a new triangle on the same shape and add to the same groups if ( aShapeId ) @@ -2119,11 +2127,13 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, mapLi_listEl.erase( *link12 ); if(tr1->NbNodes()==3) { if( tr1->GetID() < tr2->GetID() ) { + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( tr1, n12, 4 ); myLastCreatedElems.Append(tr1); aMesh->RemoveElement( tr2 ); } else { + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( tr2, n12, 4 ); myLastCreatedElems.Append(tr2); aMesh->RemoveElement( tr1); @@ -2146,11 +2156,13 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, aNodes[6] = N2[3]; aNodes[7] = N1[5]; if( tr1->GetID() < tr2->GetID() ) { + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 ); myLastCreatedElems.Append(tr1); GetMeshDS()->RemoveElement( tr2 ); } else { + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 ); myLastCreatedElems.Append(tr2); GetMeshDS()->RemoveElement( tr1 ); @@ -2164,11 +2176,13 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, mapLi_listEl.erase( *link13 ); if(tr1->NbNodes()==3) { if( tr1->GetID() < tr2->GetID() ) { + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( tr1, n13, 4 ); myLastCreatedElems.Append(tr1); aMesh->RemoveElement( tr3 ); } else { + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( tr3, n13, 4 ); myLastCreatedElems.Append(tr3); aMesh->RemoveElement( tr1 ); @@ -2191,11 +2205,13 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, aNodes[6] = N2[3]; aNodes[7] = N1[5]; if( tr1->GetID() < tr2->GetID() ) { + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 ); myLastCreatedElems.Append(tr1); GetMeshDS()->RemoveElement( tr3 ); } else { + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 ); myLastCreatedElems.Append(tr3); GetMeshDS()->RemoveElement( tr1 ); @@ -3872,6 +3888,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, if ( !f ) myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] )); else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( f, nodes, nbn ); break; } @@ -3880,6 +3897,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, if ( !f ) myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] )); else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( f, nodes, nbn ); break; } @@ -3900,6 +3918,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, tmpnodes[3] = nodes[1]; tmpnodes[4] = nodes[3]; tmpnodes[5] = nodes[5]; + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( f, tmpnodes, nbn ); } } @@ -3920,6 +3939,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, tmpnodes[5] = nodes[3]; tmpnodes[6] = nodes[5]; tmpnodes[7] = nodes[7]; + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( f, tmpnodes, nbn ); } } @@ -3930,6 +3950,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, if ( !f ) myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes)); else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( f, nodes, nbn ); } } @@ -8645,6 +8666,7 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace, newNodes[ 1 ] = linkNodes[ i2 ]; newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ]; newNodes[ 3 ] = nodes[ i4 ]; + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 ); } // end if(!theFace->IsQuadratic()) else { // theFace is quadratic @@ -9740,6 +9762,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, // elemIDsToRemove.push_back( e->GetID() ); // else if ( nbReplaced ) + // TODO problem ChangeElementNodes : not the same number of nodes, not the same type aMesh->ChangeElementNodes( e, & nodes[0], nbNodes ); } } @@ -10234,6 +10257,192 @@ bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems, return DoubleNodes( theElems, theNodesNot, anAffected ); } +/*! + * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand. + * The list of groups must describe a partition of the mesh volumes. + * The nodes of the internal faces at the boundaries of the groups are doubled. + * In option, the internal faces are replaced by flat elements. + * Triangles are transformed in prisms, and quadrangles in hexahedrons. + * @param theElems - list of groups of volumes, where a group of volume is a set of + * SMDS_MeshElements sorted by Id. + * @param createJointElems - if TRUE, create the elements + * @return TRUE if operation has been completed successfully, FALSE otherwise + */ +bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector& theElems, + bool createJointElems) +{ + MESSAGE("------------------------------------------------------"); + MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries"); + MESSAGE("------------------------------------------------------"); + + SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS(); + meshDS->BuildDownWardConnectivity(false); + SMDS_UnstructuredGrid *grid = meshDS->getGrid(); + + // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes + // build the list of nodes shared by 2 or more domains, with their domain indexes + + std::map, DownIdCompare> faceDomains; // 2x(id domain --> id volume) + std::map > nodeDomains; //oldId -> (domainId -> newId) + faceDomains.clear(); + nodeDomains.clear(); + std::map emptyMap; + emptyMap.clear(); + + for (int idom = 0; idom < theElems.size(); idom++) + { + + // --- build a map (face to duplicate --> volume to modify) + // with all the faces shared by 2 domains (group of elements) + // and corresponding volume of this domain, for each shared face. + // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain. + + const TIDSortedElemSet& domain = theElems[idom]; + TIDSortedElemSet::const_iterator elemItr = domain.begin(); + for (; elemItr != domain.end(); ++elemItr) + { + SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr; + if (!anElem) + continue; + int vtkId = meshDS->fromSmdsToVtk(anElem->getId()); + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId); + for (int n = 0; n < nbNeighbors; n++) + { + int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]); + const SMDS_MeshElement* elem = meshDS->FindElement(smdsId); + if (! domain.count(elem)) // neighbor is in another domain : face is shared + { + DownIdType face(downIds[n], downTypes[n]); + if (!faceDomains.count(face)) + faceDomains[face] = emptyMap; // create an empty entry for face + if (!faceDomains[face].count(idom)) + { + faceDomains[face][idom] = vtkId; // volume associated to face in this domain + } + } + } + } + } + + MESSAGE("Number of shared faces " << faceDomains.size()); + + // --- for each shared face, get the nodes + // for each node, for each domain of the face, create a clone of the node + + std::map, DownIdCompare>::iterator itface = faceDomains.begin(); + for( ; itface != faceDomains.end();++itface ) + { + DownIdType face = itface->first; + std::map domvol = itface->second; + std::set oldNodes; + oldNodes.clear(); + grid->GetNodeIds(oldNodes, face.cellId, face.cellType); + std::set::iterator itn = oldNodes.begin(); + for (;itn != oldNodes.end(); ++itn) + { + int oldId = *itn; + if (!nodeDomains.count(oldId)) + nodeDomains[oldId] = emptyMap; // create an empty entry for node + std::map::iterator itdom = domvol.begin(); + for(; itdom != domvol.end(); ++itdom) + { + int idom = itdom->first; + if ( nodeDomains[oldId].empty() ) + nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain + else + { + double *coords = grid->GetPoint(oldId); + SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]); + int newId = newNode->GetID(); + nodeDomains[oldId][idom] = newId; // cloned node for other domains + } + } + } + } + + // --- iterate on shared faces (volumes to modify, face to extrude) + // get node id's of the face (id SMDS = id VTK) + // create flat element with old and new nodes if requested + + if (createJointElems) + { + itface = faceDomains.begin(); + for( ; itface != faceDomains.end();++itface ) + { + DownIdType face = itface->first; + std::set oldNodes; + std::set::iterator itn; + oldNodes.clear(); + grid->GetNodeIds(oldNodes, face.cellId, face.cellType); + std::map localClonedNodeIds; + + std::map domvol = itface->second; + std::map::iterator itdom = domvol.begin(); + int dom1 = itdom->first; + int vtkVolId = itdom->second; + itdom++; + int dom2 = itdom->first; + + localClonedNodeIds.clear(); + for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn) + { + int oldId = *itn; + int refid = oldId; + if (nodeDomains[oldId].count(dom1)) + refid = nodeDomains[oldId][dom1]; + else + MESSAGE("--- problem domain node " << dom1 << " " << oldId); + int newid = oldId; + if (nodeDomains[oldId].count(dom2)) + newid = nodeDomains[oldId][dom2]; + else + MESSAGE("--- problem domain node " << dom2 << " " << oldId); + localClonedNodeIds[oldId] = newid; + } + int smdsId = meshDS->fromVtkToSmds(vtkVolId); + meshDS->extrudeVolumeFromFace(smdsId, localClonedNodeIds); + } + } + + // --- iterate on shared faces (volumes to modify, face to extrude) + // get node id's of the face (id SMDS = id VTK) + // replace old nodes by new nodes in volumes, and update inverse connectivity + + itface = faceDomains.begin(); + for( ; itface != faceDomains.end();++itface ) + { + DownIdType face = itface->first; + std::set oldNodes; + std::set::iterator itn; + oldNodes.clear(); + grid->GetNodeIds(oldNodes, face.cellId, face.cellType); + std::map localClonedNodeIds; + + std::map domvol = itface->second; + std::map::iterator itdom = domvol.begin(); + for(; itdom != domvol.end(); ++itdom) + { + int idom = itdom->first; + int vtkVolId = itdom->second; + localClonedNodeIds.clear(); + for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn) + { + int oldId = *itn; + if (nodeDomains[oldId].count(idom)) + localClonedNodeIds[oldId] = nodeDomains[oldId][idom]; + } + int smdsId = meshDS->fromVtkToSmds(vtkVolId); + meshDS->ModifyCellNodes(smdsId, localClonedNodeIds); + } + } + grid->BuildLinks(); + + // TODO replace also old nodes by new nodes in faces and edges +} + //================================================================================ /*! * \brief Generated skin mesh (containing 2D cells) from 3D mesh diff --git a/src/SMESH/SMESH_MeshEditor.hxx b/src/SMESH/SMESH_MeshEditor.hxx index d9f4b5d28..cef86b4af 100644 --- a/src/SMESH/SMESH_MeshEditor.hxx +++ b/src/SMESH/SMESH_MeshEditor.hxx @@ -627,6 +627,9 @@ public: const TIDSortedElemSet& theNodesNot, const TopoDS_Shape& theShape ); + bool DoubleNodesOnGroupBoundaries( const std::vector& theElems, + bool createJointElems); + /*! * \brief Generated skin mesh (containing 2D cells) from 3D mesh * The created 2D mesh elements based on nodes of free faces of boundary volumes diff --git a/src/SMESHDS/SMESHDS_Mesh.cxx b/src/SMESHDS/SMESHDS_Mesh.cxx index a7afa4c9f..0afc862cd 100644 --- a/src/SMESHDS/SMESHDS_Mesh.cxx +++ b/src/SMESHDS/SMESHDS_Mesh.cxx @@ -33,6 +33,7 @@ #include "SMDS_EdgePosition.hxx" #include "SMDS_FacePosition.hxx" #include "SMDS_SpacePosition.hxx" +#include "SMDS_Downward.hxx" #include "SMESHDS_GroupOnGeom.hxx" #include @@ -1914,8 +1915,6 @@ void SMESHDS_Mesh::compactMesh() myVtkIndex.swap(newVtkToSmds); MESSAGE("myCells.size()=" << myCells.size() << " myIDElements.size()=" << myIDElements.size() << " myVtkIndex.size()=" << myVtkIndex.size() ); - myGrid->BuildDownwardConnectivity(); - // ---TODO: myNodes, myElements in submeshes // map::iterator it = myShapeIndexToSubMesh.begin(); @@ -1926,3 +1925,53 @@ void SMESHDS_Mesh::compactMesh() } +void SMESHDS_Mesh::BuildDownWardConnectivity(bool withEdges) +{ + myGrid->BuildDownwardConnectivity(withEdges); +} + +/*! change some nodes in cell without modifying type or internal connectivity. + * Nodes inverse connectivity is maintained up to date. + * @param smdsVolId smds id of the cell. + * @param localClonedNodeIds map old node id to new node id. + * @return ok if success. + */ +bool SMESHDS_Mesh::ModifyCellNodes(int smdsVolId, std::map localClonedNodeIds) +{ + int vtkVolId = this->fromSmdsToVtk(smdsVolId); + myGrid->ModifyCellNodes(vtkVolId, localClonedNodeIds); + return true; +} + +/*! Create a volume (prism or hexahedron) by duplication of a face. + * the nodes of the new face are already created. + * @param vtkVolId vtk id of a volume containing the face, to get an orientation for the face. + * @param localClonedNodeIds map old node id to new node id. The old nodes define the face in the volume. + * @return ok if success. + */ +bool SMESHDS_Mesh::extrudeVolumeFromFace(int smdsVolId, std::map localClonedNodeIds) +{ + int vtkVolId = this->fromSmdsToVtk(smdsVolId); + //MESSAGE(smdsVolId << " " << vtkVolId); + vector orderedNodes; + orderedNodes.clear(); + map::iterator it = localClonedNodeIds.begin(); + for (; it != localClonedNodeIds.end(); ++it) + orderedNodes.push_back(it->first); + + int nbNodes = myGrid->getOrderedNodesOfFace(vtkVolId, orderedNodes); + if (nbNodes == 3) + { + int newVtkVolId =myElementIDFactory->GetFreeID(); + SMDS_MeshVolume *vol = this->AddVolumeWithID(orderedNodes[0], + orderedNodes[1], + orderedNodes[2], + localClonedNodeIds[orderedNodes[0]], + localClonedNodeIds[orderedNodes[1]], + localClonedNodeIds[orderedNodes[2]], + newVtkVolId); + } + + // TODO update subshape list of elements and nodes + return true; +} diff --git a/src/SMESHDS/SMESHDS_Mesh.hxx b/src/SMESHDS/SMESHDS_Mesh.hxx index b5ecf2988..70af413ab 100644 --- a/src/SMESHDS/SMESHDS_Mesh.hxx +++ b/src/SMESHDS/SMESHDS_Mesh.hxx @@ -56,6 +56,7 @@ #include "SMESHDS_DataMapOfShape.hxx" class SMESHDS_GroupBase; +class DownIdType; class SMESHDS_EXPORT SMESHDS_Mesh:public SMDS_Mesh{ public: @@ -397,6 +398,8 @@ public: bool ChangePolyhedronNodes(const SMDS_MeshElement * elem, std::vector nodes, std::vector quantities); + bool ModifyCellNodes(int smdsVolId, std::map localClonedNodeIds); + bool extrudeVolumeFromFace(int smdsVolId, std::map localClonedNodeIds); void Renumber (const bool isNodes, const int startID=1, const int deltaID=1); void SetNodeInVolume(SMDS_MeshNode * aNode, const TopoDS_Shell & S); @@ -440,6 +443,7 @@ public: bool IsGroupOfSubShapes (const TopoDS_Shape& aSubShape) const; void compactMesh(); + void BuildDownWardConnectivity(bool withEdges); ~SMESHDS_Mesh(); diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index 0ccfca681..f573ba167 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -4766,3 +4766,51 @@ CORBA::Boolean SMESH_MeshEditor_i::Make2DMeshFrom3D() TPythonDump() << "isDone = " << this << ".Make2DMeshFrom3D()"; return aResult; } + +//================================================================================ +/*! + * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand. + * The list of groups must describe a partition of the mesh volumes. + * The nodes of the internal faces at the boundaries of the groups are doubled. + * In option, the internal faces are replaced by flat elements. + * Triangles are transformed in prisms, and quadrangles in hexahedrons. + * @param theDomains - list of groups of volumes + * @param createJointElems - if TRUE, create the elements + * @return TRUE if operation has been completed successfully, FALSE otherwise + */ +//================================================================================ + +CORBA::Boolean SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::ListOfGroups& theDomains, + CORBA::Boolean createJointElems ) +{ + initData(); + + ::SMESH_MeshEditor aMeshEditor( myMesh ); + + SMESHDS_Mesh* aMeshDS = GetMeshDS(); + + vector domains; + domains.clear(); + + for ( int i = 0, n = theDomains.length(); i < n; i++ ) + { + SMESH::SMESH_GroupBase_var aGrp = theDomains[ i ]; + if ( !CORBA::is_nil( aGrp ) && ( aGrp->GetType() != SMESH::NODE ) ) + { + TIDSortedElemSet domain; + domain.clear(); + domains.push_back(domain); + SMESH::long_array_var anIDs = aGrp->GetIDs(); + arrayToSet( anIDs, aMeshDS, domains[ i ], SMDSAbs_All ); + } + } + + bool aResult = aMeshEditor.DoubleNodesOnGroupBoundaries( domains, createJointElems ); + + storeResult( aMeshEditor) ; + + // Update Python script + TPythonDump() << "isDone = " << this << ".DoubleNodesOnGroupBoundaries( " << &theDomains + << ", " << createJointElems << " )"; + return aResult; +} diff --git a/src/SMESH_I/SMESH_MeshEditor_i.hxx b/src/SMESH_I/SMESH_MeshEditor_i.hxx index 046573b17..cac924066 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.hxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.hxx @@ -647,6 +647,20 @@ public: */ CORBA::Boolean Make2DMeshFrom3D(); + /*! + * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand. + * The list of groups must describe a partition of the mesh volumes. + * The nodes of the internal faces at the boundaries of the groups are doubled. + * In option, the internal faces are replaced by flat elements. + * Triangles are transformed in prisms, and quadrangles in hexahedrons. + * @param theDomains - list of groups of volumes + * @param createJointElems - if TRUE, create the elements + * @return TRUE if operation has been completed successfully, FALSE otherwise + */ + CORBA::Boolean DoubleNodesOnGroupBoundaries( const SMESH::ListOfGroups& theDomains, + CORBA::Boolean createJointElems ); + + private: //!< private methods SMESHDS_Mesh * GetMeshDS() { return myMesh->GetMeshDS(); } diff --git a/src/SMESH_SWIG/smeshDC.py b/src/SMESH_SWIG/smeshDC.py index 5e9233005..96c77da34 100644 --- a/src/SMESH_SWIG/smeshDC.py +++ b/src/SMESH_SWIG/smeshDC.py @@ -3719,6 +3719,17 @@ class Mesh: # @ingroup l2_modif_edit def DoubleNodeElemGroupsInRegion(self, theElems, theNodesNot, theShape): return self.editor.DoubleNodeElemGroupsInRegion(theElems, theNodesNot, theShape) + + ## Double nodes on shared faces between groups of volumes and create flat elements on demand. + # The list of groups must describe a partition of the mesh volumes. + # The nodes of the internal faces at the boundaries of the groups are doubled. + # In option, the internal faces are replaced by flat elements. + # Triangles are transformed in prisms, and quadrangles in hexahedrons. + # @param theDomains - list of groups of volumes + # @param createJointElems - if TRUE, create the elements + # @return TRUE if operation has been completed successfully, FALSE otherwise + def DoubleNodesOnGroupBoundaries(self, theDomains, createJointElems ): + return self.editor.DoubleNodesOnGroupBoundaries( theDomains, createJointElems ) ## The mother class to define algorithm, it is not recommended to use it directly. #