From 7aaccdc952f94271216de8286fdaa189728454aa Mon Sep 17 00:00:00 2001 From: Christophe Geuzaine <cgeuzaine@ulg.ac.be> Date: Sun, 28 Aug 2016 14:32:37 +0000 Subject: [PATCH] faster removeDuplicateMeshVertices (single search per vertex + direct element modification) --- Common/CommandLine.cpp | 2 +- Geo/GModel.cpp | 90 +++++++++++++++++------------------------- Geo/MHexahedron.h | 5 ++- Geo/MLine.h | 2 + Geo/MPrism.h | 5 ++- Geo/MPyramid.h | 6 +-- Geo/MQuadrangle.h | 20 +++++----- Geo/MTetrahedron.h | 2 + Geo/MTriangle.h | 12 +++--- Geo/MVertexRTree.h | 15 +++---- doc/VERSIONS.txt | 3 +- 11 files changed, 79 insertions(+), 83 deletions(-) diff --git a/Common/CommandLine.cpp b/Common/CommandLine.cpp index 79e5e7c4ff..0083b29fec 100644 --- a/Common/CommandLine.cpp +++ b/Common/CommandLine.cpp @@ -660,7 +660,7 @@ void GetOptions(int argc, char *argv[]) #endif // convert mesh to latest binary format if(GModel::current()->getMeshStatus() > 0){ - CTX::instance()->mesh.mshFileVersion = 2.0; + CTX::instance()->mesh.mshFileVersion = 3.0; CTX::instance()->mesh.binary = 1; CreateOutputFile(fileName, FORMAT_MSH); } diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp index 8a55ab05be..04cd1e475c 100644 --- a/Geo/GModel.cpp +++ b/Geo/GModel.cpp @@ -1721,79 +1721,59 @@ int GModel::removeDuplicateMeshVertices(double tolerance) std::vector<GEntity*> entities; getEntities(entities); - - std::vector<MVertex*> vertices; + std::map<int, MVertex*> vertices; + MVertexRTree pos(eps); + std::map<MVertex*,MVertex*> newVertex; for(unsigned int i = 0; i < entities.size(); i++){ - for(unsigned int j = 0; j < entities[i]->mesh_vertices.size(); j++){ - MVertex *v = entities[i]->mesh_vertices[j]; - vertices.push_back(new MVertex(v->x(), v->y(), v->z())); + GEntity* ge = entities[i]; + for(unsigned int j = 0; j < ge->mesh_vertices.size(); j++){ + MVertex *v = ge->mesh_vertices[j]; + MVertex *v2 = pos.insert(v); + if(v2){ + newVertex[v] = v2; // v should be removed + vertices[v2->getNum()] = v2; + } + else{ + vertices[v->getNum()] = v; + } } } - MVertexRTree pos(eps); - int num = pos.insert(vertices); + int num = (int)newVertex.size(); Msg::Info("Found %d duplicate vertices ", num); if(!num){ - for(unsigned int i = 0; i < vertices.size(); i++) - delete vertices[i]; Msg::Info("No duplicate vertices found"); return 0; } - std::map<MVertex*,MVertex*> newVertex; - std::map<int, std::vector<MElement*> > elements[11]; for(unsigned int i = 0; i < entities.size(); i++){ - for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++){ - MElement *e = entities[i]->getMeshElement(j); - std::vector<MVertex*> verts; + GEntity* ge = entities[i]; + // clear list of vertices owned by entity + ge->mesh_vertices.clear(); + // replace vertices in element + for(unsigned int j = 0; j < ge->getNumMeshElements(); j++){ + MElement *e = ge->getMeshElement(j); for(int k = 0; k < e->getNumVertices(); k++){ - MVertex *v = e->getVertex(k); - MVertex *v2 = pos.find(v->x(), v->y(), v->z()); - if(v2) { - verts.push_back(v2); - newVertex[v] = v2; - } + std::map<MVertex*, MVertex*>::iterator it = newVertex.find(e->getVertex(k)); + if(it != newVertex.end()) + e->setVertex(k, it->second); } - if((int)verts.size() == e->getNumVertices()){ - MElementFactory factory; - MElement *e2 = factory.create(e->getTypeForMSH(), verts, e->getNum(), - e->getPartition()); - switch(e2->getType()){ - case TYPE_PNT: elements[0][entities[i]->tag()].push_back(e2); break; - case TYPE_LIN: elements[1][entities[i]->tag()].push_back(e2); break; - case TYPE_TRI: elements[2][entities[i]->tag()].push_back(e2); break; - case TYPE_QUA: elements[3][entities[i]->tag()].push_back(e2); break; - case TYPE_TET: elements[4][entities[i]->tag()].push_back(e2); break; - case TYPE_HEX: elements[5][entities[i]->tag()].push_back(e2); break; - case TYPE_PRI: elements[6][entities[i]->tag()].push_back(e2); break; - case TYPE_PYR: elements[7][entities[i]->tag()].push_back(e2); break; - case TYPE_TRIH: elements[8][entities[i]->tag()].push_back(e2); break; - case TYPE_POLYG: elements[9][entities[i]->tag()].push_back(e2); break; - case TYPE_POLYH: elements[10][entities[i]->tag()].push_back(e2); break; - } - } - else - Msg::Error("Could not recreate element %d", e->getNum()); } - } - - // replace vertices in the periodic copies - for(unsigned int i = 0; i < entities.size(); i++){ - GEntity* ge = entities[i]; + // replace vertices in periodic copies std::map<MVertex*,MVertex*>& corrVtcs = ge->correspondingVertices; std::map<MVertex*,MVertex*>::iterator cIter; - for (cIter=newVertex.begin();cIter!=newVertex.end();++cIter) { + for (cIter = newVertex.begin(); cIter != newVertex.end(); ++cIter) { MVertex* oldTgt = cIter->first; MVertex* newTgt = cIter->second; - std::map<MVertex*,MVertex*>::iterator cvIter = corrVtcs.find(oldTgt); + std::map<MVertex*, MVertex*>::iterator cvIter = corrVtcs.find(oldTgt); if (cvIter != corrVtcs.end()) { MVertex* src = cvIter->second; corrVtcs.erase(cvIter); corrVtcs[newTgt] = src; } } - for (cIter=corrVtcs.begin();cIter!=corrVtcs.end();++cIter) { + for (cIter = corrVtcs.begin(); cIter != corrVtcs.end(); ++cIter) { MVertex* oldSrc = cIter->second; std::map<MVertex*,MVertex*>::iterator nIter = newVertex.find(oldSrc); if (nIter != newVertex.end()) { @@ -1804,14 +1784,18 @@ int GModel::removeDuplicateMeshVertices(double tolerance) } } - for(unsigned int i = 0; i < entities.size(); i++) - entities[i]->deleteMesh(); - - for(int i = 0; i < (int)(sizeof(elements) / sizeof(elements[0])); i++) - _storeElementsInEntities(elements[i]); + destroyMeshCaches(); _associateEntityWithMeshVertices(); _storeVerticesInEntities(vertices); + // delete unused vertices + std::vector<MVertex*> to_delete; + for(std::map<MVertex *, MVertex*>::iterator it = newVertex.begin(); + it != newVertex.end(); it++) + to_delete.push_back(it->first); + for(unsigned int i = 0; i < to_delete.size(); i++) + delete to_delete[i]; + if(num) Msg::Info("Removed %d duplicate mesh %s", num, num > 1 ? "vertices" : "vertex"); diff --git a/Geo/MHexahedron.h b/Geo/MHexahedron.h index c410956441..7caea46813 100644 --- a/Geo/MHexahedron.h +++ b/Geo/MHexahedron.h @@ -243,6 +243,7 @@ class MHexahedron20 : public MHexahedron { virtual int getNumVertices() const { return 20; } virtual MVertex *getVertex(int num){ return num < 8 ? _v[num] : _vs[num - 8]; } virtual const MVertex *getVertex(int num) const { return num < 8 ? _v[num] : _vs[num - 8]; } + virtual void setVertex(int num, MVertex *v){ if(num < 8) _v[num] = v; else _vs[num - 8] = v; } virtual MVertex *getVertexUNV(int num) { static const int map[20] = {0, 8, 1, 11, 2, 13, 3, 9, 10, 12, @@ -371,7 +372,7 @@ class MHexahedron27 : public MHexahedron { virtual int getNumVertices() const { return 27; } virtual MVertex *getVertex(int num){ return num < 8 ? _v[num] : _vs[num - 8]; } virtual const MVertex *getVertex(int num) const { return num < 8 ? _v[num] : _vs[num - 8]; } - + virtual void setVertex(int num, MVertex *v){ if(num < 8) _v[num] = v; else _vs[num - 8] = v; } virtual MVertex *getVertexINP(int num) { static const int map[27] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 13, 9, 16, 18, 19, @@ -502,7 +503,7 @@ class MHexahedronN : public MHexahedron { virtual int getNumVertices() const { return 8 + _vs.size(); } virtual MVertex *getVertex(int num){ return num < 8 ? _v[num] : _vs[num - 8]; } virtual const MVertex *getVertex(int num) const { return num < 8 ? _v[num] : _vs[num - 8]; } - + virtual void setVertex(int num, MVertex *v){ if(num < 8) _v[num] = v; else _vs[num - 8] = v; } virtual int getNumEdgeVertices() const { return 12 * (_order - 1); } virtual int getNumFaceVertices() const { diff --git a/Geo/MLine.h b/Geo/MLine.h index 0e26cab51e..ad7a9a5722 100644 --- a/Geo/MLine.h +++ b/Geo/MLine.h @@ -126,6 +126,7 @@ class MLine3 : public MLine { virtual int getNumVertices() const { return 3; } virtual MVertex *getVertex(int num){ return num < 2 ? _v[num] : _vs[num - 2]; } virtual const MVertex *getVertex(int num) const{ return num < 2 ? _v[num] : _vs[num - 2]; } + virtual void setVertex(int num, MVertex *v){ if(num < 2) _v[num] = v; else _vs[num - 2] = v; } virtual MVertex *getVertexUNV(int num) { static const int map[3] = {0, 2, 1}; @@ -183,6 +184,7 @@ class MLineN : public MLine { virtual int getNumVertices() const { return _vs.size() + 2; } virtual MVertex *getVertex(int num){ return num < 2 ? _v[num] : _vs[num - 2]; } virtual const MVertex *getVertex(int num) const{ return num < 2 ? _v[num] : _vs[num - 2]; } + virtual void setVertex(int num, MVertex *v){ if(num < 2) _v[num] = v; else _vs[num - 2] = v; } virtual int getNumEdgeVertices() const { return _vs.size(); } virtual int getNumEdgesRep(bool curved); virtual void getEdgeRep(bool curved, int num, double *x, double *y, double *z, SVector3 *n); diff --git a/Geo/MPrism.h b/Geo/MPrism.h index 1ecc03c95f..1d4bbf29f1 100644 --- a/Geo/MPrism.h +++ b/Geo/MPrism.h @@ -242,6 +242,7 @@ class MPrism15 : public MPrism { virtual int getNumVertices() const { return 15; } virtual MVertex *getVertex(int num){ return num < 6 ? _v[num] : _vs[num - 6]; } virtual const MVertex *getVertex(int num) const { return num < 6 ? _v[num] : _vs[num - 6]; } + virtual void setVertex(int num, MVertex *v){ if(num < 6) _v[num] = v; else _vs[num - 6] = v; } virtual MVertex *getVertexUNV(int num) { static const int map[15] = {0, 6, 1, 9, 2, 7, 8, 10, 11, 3, 12, 4, 14, 5, 13}; @@ -346,6 +347,7 @@ class MPrism18 : public MPrism { virtual int getNumVertices() const { return 18; } virtual MVertex *getVertex(int num){ return num < 6 ? _v[num] : _vs[num - 6]; } virtual const MVertex *getVertex(int num) const{ return num < 6 ? _v[num] : _vs[num - 6]; } + virtual void setVertex(int num, MVertex *v){ if(num < 6) _v[num] = v; else _vs[num - 6] = v; } virtual int getNumEdgeVertices() const { return 9; } virtual int getNumFaceVertices() const { return 3; } virtual int getNumEdgesRep(bool curved); @@ -422,7 +424,8 @@ class MPrismN : public MPrism { virtual int getPolynomialOrder() const { return _order; } virtual int getNumVertices() const { return 6+_vs.size(); } virtual MVertex *getVertex(int num){ return num < 6 ? _v[num] : _vs[num-6]; } - virtual const MVertex *getVertex(int num) const{ return num < 6 ? _v[num] : _vs[num-6]; } + virtual const MVertex *getVertex(int num) const{ return num < 6 ? _v[num] : _vs[num - 6]; } + virtual void setVertex(int num, MVertex *v){ if(num < 6) _v[num] = v; else _vs[num - 6] = v; } virtual int getNumEdgeVertices() const { return 9*(_order-1); } virtual int getNumFaceVertices() const { diff --git a/Geo/MPyramid.h b/Geo/MPyramid.h index 05903346f3..57508dbf8d 100644 --- a/Geo/MPyramid.h +++ b/Geo/MPyramid.h @@ -243,10 +243,8 @@ class MPyramidN : public MPyramid { virtual int getPolynomialOrder() const { return _order; } virtual int getNumVertices() const { return 5 + _vs.size(); } virtual MVertex *getVertex(int num){ return num < 5 ? _v[num] : _vs[num - 5]; } - virtual const MVertex *getVertex(int num) const - { - return num < 5 ? _v[num] : _vs[num - 5]; - } + virtual const MVertex *getVertex(int num) const { return num < 5 ? _v[num] : _vs[num - 5]; } + virtual void setVertex(int num, MVertex *v){ if(num < 5) _v[num] = v; else _vs[num - 5] = v; } virtual int getNumEdgeVertices() const { return 8 * (_order - 1); } virtual int getNumFaceVertices() const { diff --git a/Geo/MQuadrangle.h b/Geo/MQuadrangle.h index f81b261147..4a522f28cd 100644 --- a/Geo/MQuadrangle.h +++ b/Geo/MQuadrangle.h @@ -139,10 +139,10 @@ class MQuadrangle : public MElement { MVertex *tmp = _v[1]; _v[1] = _v[3]; _v[3] = tmp; } // reorient the quadrangle to conform with other face - // orientation computed with MFace based on this face with respect to other + // orientation computed with MFace based on this face with respect to other // in computeCorrespondence virtual void reorient(int rotation, bool swap); - + virtual bool isInside(double u, double v, double w) const { double tol = _isInsideTolerance; @@ -205,6 +205,7 @@ class MQuadrangle8 : public MQuadrangle { virtual int getNumVertices() const { return 8; } virtual MVertex *getVertex(int num){ return num < 4 ? _v[num] : _vs[num - 4]; } virtual const MVertex *getVertex(int num) const { return num < 4 ? _v[num] : _vs[num - 4]; } + virtual void setVertex(int num, MVertex *v){ if(num < 4) _v[num] = v; else _vs[num - 4] = v; } virtual MVertex *getVertexUNV(int num) { static const int map[8] = {0, 4, 1, 5, 2, 6, 3, 7}; @@ -250,10 +251,10 @@ class MQuadrangle8 : public MQuadrangle { } // reorient the quadrangle to conform with other face - // orientation computed with MFace based on this face with respect to other + // orientation computed with MFace based on this face with respect to other // in computeCorrespondence virtual void reorient(int rotation, bool swap); - + virtual void getNode(int num, double &u, double &v, double &w) const { num < 4 ? MQuadrangle::getNode(num, u, v, w) : MElement::getNode(num, u, v, w); @@ -298,6 +299,7 @@ class MQuadrangle9 : public MQuadrangle { virtual int getNumVertices() const { return 9; } virtual MVertex *getVertex(int num){ return num < 4 ? _v[num] : _vs[num - 4]; } virtual const MVertex *getVertex(int num) const { return num < 4 ? _v[num] : _vs[num - 4]; } + virtual void setVertex(int num, MVertex *v){ if(num < 4) _v[num] = v; else _vs[num - 4] = v; } virtual MVertex *getVertexDIFF(int num) { static const int map[9] = {0, 2, 8, 6, 1, 5, 7, 3, 4}; @@ -339,10 +341,10 @@ class MQuadrangle9 : public MQuadrangle { } // reorient the quadrangle to conform with other face - // orientation computed with MFace based on this face with respect to other + // orientation computed with MFace based on this face with respect to other // in computeCorrespondence virtual void reorient(int rotation, bool swap); - + virtual void getNode(int num, double &u, double &v, double &w) const { num < 4 ? MQuadrangle::getNode(num, u, v, w) : MElement::getNode(num, u, v, w); @@ -461,12 +463,12 @@ class MQuadrangleN : public MQuadrangle { inv.insert(inv.begin(), _vs.rbegin(), _vs.rend()); _vs = inv; } - + // reorient the quadrangle to conform with other face - // orientation computed with MFace based on this face with respect to other + // orientation computed with MFace based on this face with respect to other // in computeCorrespondence virtual void reorient(int rotation, bool swap); - + virtual void getNode(int num, double &u, double &v, double &w) const { num < 4 ? MQuadrangle::getNode(num, u, v, w) : MElement::getNode(num, u, v, w); diff --git a/Geo/MTetrahedron.h b/Geo/MTetrahedron.h index ec41b1a8cf..66b56bd0e6 100644 --- a/Geo/MTetrahedron.h +++ b/Geo/MTetrahedron.h @@ -229,6 +229,7 @@ class MTetrahedron10 : public MTetrahedron { virtual int getNumVertices() const { return 10; } virtual MVertex *getVertex(int num){ return num < 4 ? _v[num] : _vs[num - 4]; } virtual const MVertex *getVertex(int num) const { return num < 4 ? _v[num] : _vs[num - 4]; } + virtual void setVertex(int num, MVertex *v){ if(num < 4) _v[num] = v; else _vs[num - 4] = v; } virtual MVertex *getVertexUNV(int num) { static const int map[10] = {0, 4, 1, 5, 2, 6, 7, 9, 8, 3}; @@ -336,6 +337,7 @@ class MTetrahedronN : public MTetrahedron { virtual int getNumVertices() const { return 4 + _vs.size(); } virtual MVertex *getVertex(int num){ return num < 4 ? _v[num] : _vs[num - 4]; } virtual const MVertex *getVertex(int num) const{ return num < 4 ? _v[num] : _vs[num - 4]; } + virtual void setVertex(int num, MVertex *v){ if(num < 4) _v[num] = v; else _vs[num - 4] = v; } virtual int getNumEdgeVertices() const { return 6 * (_order - 1); } virtual int getNumFaceVertices() const { diff --git a/Geo/MTriangle.h b/Geo/MTriangle.h index d0318b44c7..f053a68d22 100644 --- a/Geo/MTriangle.h +++ b/Geo/MTriangle.h @@ -125,12 +125,12 @@ class MTriangle : public MElement { { MVertex *tmp = _v[1]; _v[1] = _v[2]; _v[2] = tmp; } - + // reorient the triangle to conform with other face - // orientation computed with MFace based on this face with respect to other + // orientation computed with MFace based on this face with respect to other // in computeCorrespondence virtual void reorient(int rotation, bool swap); - + virtual void getNode(int num, double &u, double &v, double &w) const { w = 0.; @@ -200,6 +200,7 @@ class MTriangle6 : public MTriangle { virtual int getNumVertices() const { return 6; } virtual MVertex *getVertex(int num){ return num < 3 ? _v[num] : _vs[num - 3]; } virtual const MVertex *getVertex(int num) const { return num < 3 ? _v[num] : _vs[num - 3]; } + virtual void setVertex(int num, MVertex *v){ if(num < 3) _v[num] = v; else _vs[num - 3] = v; } virtual MVertex *getVertexUNV(int num) { static const int map[6] = {0, 3, 1, 4, 2, 5}; @@ -244,7 +245,7 @@ class MTriangle6 : public MTriangle { num < 3 ? MTriangle::getNode(num, u, v, w) : MElement::getNode(num, u, v, w); } // reorient the triangle to conform with other face - // orientation computed with MFace based on this face with respect to other + // orientation computed with MFace based on this face with respect to other // in computeCorrespondence virtual void reorient(int rotation, bool swap); }; @@ -287,6 +288,7 @@ class MTriangleN : public MTriangle { virtual int getNumVertices() const { return 3 + _vs.size(); } virtual MVertex *getVertex(int num){ return num < 3 ? _v[num] : _vs[num - 3]; } virtual const MVertex *getVertex(int num) const { return num < 3 ? _v[num] : _vs[num - 3]; } + virtual void setVertex(int num, MVertex *v){ if(num < 3) _v[num] = v; else _vs[num - 3] = v; } virtual int getNumFaceVertices() const { if (getIsAssimilatedSerendipity()) @@ -355,7 +357,7 @@ class MTriangleN : public MTriangle { num < 3 ? MTriangle::getNode(num, u, v, w) : MElement::getNode(num, u, v, w); } // reorient the triangle to conform with other face - // orientation computed with MFace based on this face with respect to other + // orientation computed with MFace based on this face with respect to other // in computeCorrespondence virtual void reorient(int rotation, bool swap); }; diff --git a/Geo/MVertexRTree.h b/Geo/MVertexRTree.h index 166eef90cb..effa3ca7d6 100644 --- a/Geo/MVertexRTree.h +++ b/Geo/MVertexRTree.h @@ -34,7 +34,7 @@ class MVertexRTree{ _rtree->RemoveAll(); delete _rtree; } - int insert(MVertex *v, bool warnIfExists=false) + MVertex *insert(MVertex *v, bool warnIfExists=false) { MVertex *out; double _min[3] = {v->x() - _tol, v->y() - _tol, v->z() - _tol}; @@ -43,18 +43,19 @@ class MVertexRTree{ _rtree->Insert(_min, _max, v); return 0; } - else if(warnIfExists){ - Msg::Warning("Vertex %d (%.16g, %.16g, %.16g) already exists in the " - "mesh with tolerance %g", v->getNum(), - v->x(), v->y(), v->z(), _tol); + else{ + if(warnIfExists) + Msg::Warning("Vertex %d (%.16g, %.16g, %.16g) already exists in the " + "mesh with tolerance %g", v->getNum(), + v->x(), v->y(), v->z(), _tol); + return out; } - return 1; // one vertex not inserted } int insert(std::vector<MVertex*> &v, bool warnIfExists=false) { int num = 0; for(unsigned int i = 0; i < v.size(); i++) - num += insert(v[i], warnIfExists); + num += (insert(v[i], warnIfExists) ? 1 : 0); return num; // number of vertices not inserted } MVertex *find(double x, double y, double z) diff --git a/doc/VERSIONS.txt b/doc/VERSIONS.txt index c9c52ca789..dfad83e3dc 100644 --- a/doc/VERSIONS.txt +++ b/doc/VERSIONS.txt @@ -1,5 +1,6 @@ 2.13.3: new Tochnog file format export; added ability to remove last command in -scripts generated interactively. +scripts generated interactively; small ONELAB usability improvements; faster +"Coherence Mesh". 2.13.2 (August 18, 2016)): small improvements (scale labels, periodic and high-order meshes) and bug fixes. -- GitLab