diff --git a/contrib/MeshOptimizer/MeshOptCommon.cpp b/contrib/MeshOptimizer/MeshOptCommon.cpp index d32a9528fb6e99e92d3822755f843c505256b598..d0a1cbfde62ee05f59ad7ebdb1eb273029cc8cf6 100644 --- a/contrib/MeshOptimizer/MeshOptCommon.cpp +++ b/contrib/MeshOptimizer/MeshOptCommon.cpp @@ -50,7 +50,7 @@ bool testSegSphereIntersect(SPoint3 A, SPoint3 B, const SPoint3& P, const double // For A, separation if projection Q of P on (AB) lies outside the sphere const SVector3 AB(A, B); const double d = ab - aa, e = dot(AB, AB); - const SVector3 PQ = PA * e - d * AB; + const SVector3 PQ = PA * e - d * AB; if (dot(PQ, PQ) > rr * e * e) return false; // Return true (intersection) if no separation at all @@ -81,12 +81,12 @@ bool testTriSphereIntersect(SPoint3 A, SPoint3 B, SPoint3 C, const SPoint3& P, c const SVector3 BC(B, C); const double d1 = ab - aa, d2 = bc - bb, d3 = ac - cc; const double e1 = dot(AB, AB), e2 = dot(BC, BC), e3 = dot(AC, AC); - const SVector3 PQ1 = PA * e1 - d1 * AB; // Q1 projection of P on line (AB) - const SVector3 PQ2 = PB * e2 - d2 * BC; // Q2 projection of P on line (BC) - const SVector3 PQ3 = PC * e3 + d3 * AC; // Q3 projection of P on line (AC) - const SVector3 PQC = PC * e1 - PQ1; - const SVector3 PQA = PA * e2 - PQ2; - const SVector3 PQB = PB * e3 - PQ3; + const SVector3 PQ1 = PA * e1 - d1 * AB; // Q1 projection of P on line (AB) + const SVector3 PQ2 = PB * e2 - d2 * BC; // Q2 projection of P on line (BC) + const SVector3 PQ3 = PC * e3 + d3 * AC; // Q3 projection of P on line (AC) + const SVector3 PQC = PC * e1 - PQ1; + const SVector3 PQA = PA * e2 - PQ2; + const SVector3 PQB = PB * e3 - PQ3; if ((dot(PQ1, PQ1) > rr * e1 * e1) & (dot(PQ1, PQC) > 0)) return false; // For A, separation if Q lies outside the sphere and if P and C if ((dot(PQ2, PQ2) > rr * e2 * e2) & (dot(PQ2, PQA) > 0)) return false; // are on opposite sides of plane through AB with normal PQ if ((dot(PQ3, PQ3) > rr * e3 * e3) & (dot(PQ3, PQB) > 0)) return false; // Same for other two vertices @@ -103,31 +103,30 @@ bool testTriSphereIntersect(SPoint3 A, SPoint3 B, SPoint3 C, const SPoint3& P, c bool MeshOptPatchDef::testElInDist(const SPoint3 &P, double limDist, MElement *el) const { - const double sampleLen = 0.5*limDist; // Distance between sample points const double limDistSq = limDist*limDist; if (el->getDim() == 2) { // 2D? for (int iEd = 0; iEd < el->getNumEdges(); iEd++) { // Loop over edges of element - MEdge ed = el->getEdge(iEd); - const SPoint3 A = ed.getVertex(0)->point(); - const SPoint3 B = ed.getVertex(1)->point(); - if (testSegSphereIntersect(A, B, P, limDistSq)) { - return true; - } + std::vector<MVertex*> edgeVert; + el->getEdgeVertices(iEd, edgeVert); + const SPoint3 A = edgeVert[0]->point(); + const SPoint3 B = edgeVert[1]->point(); + if (testSegSphereIntersect(A, B, P, limDistSq)) return true; } } else { // 3D for (int iFace = 0; iFace < el->getNumFaces(); iFace++) { // Loop over faces of element - MFace face = el->getFace(iFace); - const SPoint3 A = face.getVertex(0)->point(); - const SPoint3 B = face.getVertex(1)->point(); - const SPoint3 C = face.getVertex(2)->point(); - if (face.getNumVertices() == 3) - return testTriSphereIntersect(A, B, C, P, limDistSq); + std::vector<MVertex*> faceVert; + el->getFaceVertices(iFace, faceVert); + const SPoint3 A = faceVert[0]->point(); + const SPoint3 B = faceVert[1]->point(); + const SPoint3 C = faceVert[2]->point(); + if (faceVert.size() == 3) + if (testTriSphereIntersect(A, B, C, P, limDistSq)) return true; else { - const SPoint3 D = face.getVertex(3)->point(); - return (testTriSphereIntersect(A, B, C, P, limDistSq) || - testTriSphereIntersect(A, C, D, P, limDistSq)); + const SPoint3 D = faceVert[3]->point(); + if (testTriSphereIntersect(A, B, C, P, limDistSq) || + testTriSphereIntersect(A, C, D, P, limDistSq)) return true; } } } diff --git a/contrib/MeshOptimizer/MeshOptimizer.cpp b/contrib/MeshOptimizer/MeshOptimizer.cpp index ac1a3e0f799797cc309c9f3681bac5ac4584ebca..9694635bb647b9a2051b4df2ada3eb33c43f36d0 100644 --- a/contrib/MeshOptimizer/MeshOptimizer.cpp +++ b/contrib/MeshOptimizer/MeshOptimizer.cpp @@ -49,14 +49,27 @@ #if defined(HAVE_BFGS) -static std::set<MVertex *> getAllBndVertices - (std::set<MElement*> &elements, - const std::map<MVertex*, std::vector<MElement*> > &vertex2elements) +typedef std::vector<MElement*> elVec; +typedef elVec::const_iterator elVecConstIter; +typedef std::set<MElement*> elSet; +typedef elSet::iterator elSetIter; +typedef std::set<MVertex*> vertSet; +typedef std::map<MElement*, GEntity*> elEntMap; + +typedef std::map<MVertex*, elVec> vertElVecMap; +typedef std::map<MElement*, elSet> elElSetMap; +typedef std::pair<elSet, vertSet> elSetVertSetPair; + + +namespace { + + +vertSet getAllBndVertices(elSet &elements, const vertElVecMap &vertex2elements) { - std::set<MVertex*> bnd; - for (std::set<MElement*>::iterator itE = elements.begin(); itE != elements.end(); ++itE) { + vertSet bnd; + for (elSetIter itE = elements.begin(); itE != elements.end(); ++itE) { for (int i = 0; i < (*itE)->getNumPrimaryVertices(); ++i) { - const std::vector<MElement*> &neighbours = vertex2elements.find + const elVec &neighbours = vertex2elements.find ((*itE)->getVertex(i))->second; for (size_t k = 0; k < neighbours.size(); ++k) { if (elements.find(neighbours[k]) == elements.end()) { @@ -71,31 +84,48 @@ static std::set<MVertex *> getAllBndVertices } -static std::set<MElement*> getSurroundingPatch(MElement *el, const MeshOptPatchDef *patchDef, - double limDist, int maxLayers, - const std::map<MVertex*, std::vector<MElement*> > &vertex2elements) +// Get neighbours of element (computes and store them only if needed) +void getElementNeighbours(MElement *el, const vertElVecMap &v2e, + elElSetMap &e2e, elSet &neighbours) +{ + elElSetMap::iterator it = e2e.find(el); + if (it == e2e.end()) { // If not in e2e, compute and store + neighbours.clear(); + for (int i = 0; i < el->getNumPrimaryVertices(); ++i) { + const elVec &adjEl = v2e.find(el->getVertex(i))->second; + for(elVecConstIter itA = adjEl.begin(); itA != adjEl.end(); itA++) + if (*itA != el) neighbours.insert(*itA); + } + e2e.insert(std::pair<MElement*, elSet>(el, neighbours)); + } + else neighbours = it->second; +} + + +elSet getSurroundingPatch(MElement *el, const MeshOptPatchDef *patchDef, + double limDist, int maxLayers, + const vertElVecMap &vertex2elements, + elElSetMap &element2elements) { const SPoint3 pnt = el->barycenter(true); - std::set<MElement*> patch; - std::list<MElement*> currentLayer, lastLayer; + elSet patch, currentLayer, lastLayer, excluded; patch.insert(el); - lastLayer.push_back(el); + lastLayer.insert(el); for (int d = 0; d < maxLayers; ++d) { currentLayer.clear(); - for (std::list<MElement*>::iterator it = lastLayer.begin(); - it != lastLayer.end(); ++it) { - for (int i = 0; i < (*it)->getNumPrimaryVertices(); ++i) { - const std::vector<MElement*> &neighbours = vertex2elements.find - ((*it)->getVertex(i))->second; - for (std::vector<MElement*>::const_iterator itN = neighbours.begin(); - itN != neighbours.end(); ++itN) { - if (patch.find(*itN) == patch.end()) { - const int elIn = patchDef->inPatch(pnt, limDist, *itN); - if ((elIn > 0) || ((d < patchDef->minLayers) && (elIn == 0))) - if (patch.insert(*itN).second) currentLayer.push_back(*itN); // Assume that if an el is too far, its neighbours are too far as well + for (elSetIter it = lastLayer.begin(); it != lastLayer.end(); ++it) { // Loop over elements in last layer + elSet neighbours; + getElementNeighbours(*it, vertex2elements, element2elements, neighbours); + for (elSetIter itN = neighbours.begin(); itN != neighbours.end(); ++itN) { // Loop over neighbours + if ((lastLayer.find(*itN) == lastLayer.end()) && // If neighbour already in last layer... + (excluded.find(*itN) == excluded.end())) { // ... or marked as excluded, skip + const int elIn = patchDef->inPatch(pnt, limDist, *itN); // Test if element in patch according to user-defined criteria + if ((elIn > 0) || ((d < patchDef->minLayers) && (elIn == 0))) { + if (patch.insert(*itN).second) currentLayer.insert(*itN); // If element in, insert in patch and in current layer... } + else excluded.insert(*itN); // ... otherwise, mark as excluded } } } @@ -106,22 +136,23 @@ static std::set<MElement*> getSurroundingPatch(MElement *el, const MeshOptPatchD } -static void addPatchChaintoGroup(std::set<int> &group, - const std::vector<std::set<int> > &groupConnect, - std::vector<bool> &todoPB, int iB) +void addPatchChaintoGroup(std::set<int> &group, + const std::vector<std::set<int> > &groupConnect, + std::vector<bool> &todoPB, int iB) { if (todoPB[iB]) { todoPB[iB] = false; group.insert(iB); const std::set<int> &connect = groupConnect[iB]; - for (std::set<int>::const_iterator itBC = connect.begin(); itBC != connect.end(); ++itBC) + for (std::set<int>::const_iterator itBC = connect.begin(); + itBC != connect.end(); ++itBC) addPatchChaintoGroup(group, groupConnect, todoPB, *itBC); } } -static void calcVertex2Elements(int dim, GEntity *entity, - std::map<MVertex*, std::vector<MElement *> > &vertex2elements) +void calcVertex2Elements(int dim, GEntity *entity, + vertElVecMap &vertex2elements) { for (size_t i = 0; i < entity->getNumMeshElements(); ++i) { MElement *element = entity->getMeshElement(i); @@ -132,7 +163,7 @@ static void calcVertex2Elements(int dim, GEntity *entity, } -static void calcElement2Entity(GEntity *entity, std::map<MElement*,GEntity*> &element2entity) +void calcElement2Entity(GEntity *entity, elEntMap &element2entity) { for (size_t i = 0; i < entity->getNumMeshElements(); ++i) { MElement *element = entity->getMeshElement(i); @@ -141,21 +172,23 @@ static void calcElement2Entity(GEntity *entity, std::map<MElement*,GEntity*> &el } -static std::vector<std::pair<std::set<MElement*>, std::set<MVertex*> > > getConnectedPatches - (const std::map<MVertex*, std::vector<MElement *> > &vertex2elements, - const std::set<MElement*> &badElements, const MeshOptParameters &par) +std::vector<elSetVertSetPair> getConnectedPatches(const vertElVecMap &vertex2elements, + const elSet &badElements, + const MeshOptParameters &par) { - Msg::Info("Starting patch generation from %i bad elements...", badElements.size()); + elElSetMap element2elements; // Element to element connectivity, built progressively + // Contruct primary patches Msg::Info("Constructing %i primary patches", badElements.size()); - std::vector<std::set<MElement*> > primPatches; + std::vector<elSet > primPatches; primPatches.reserve(badElements.size()); - for (std::set<MElement*>::const_iterator it = badElements.begin(); it != badElements.end(); ++it) { + for (elSet::const_iterator it = badElements.begin(); it != badElements.end(); ++it) { const double limDist = par.patchDef->maxDistance(*it); primPatches.push_back(getSurroundingPatch(*it, par.patchDef, limDist, - par.patchDef->maxLayers, vertex2elements)); + par.patchDef->maxLayers, + vertex2elements, element2elements)); } // Compute patch connectivity @@ -163,8 +196,8 @@ static std::vector<std::pair<std::set<MElement*>, std::set<MVertex*> > > getConn std::map<MElement*, std::set<int> > tags; std::vector<std::set<int> > patchConnect(primPatches.size()); for (int iB = 0; iB < primPatches.size(); ++iB) { - std::set<MElement*> &patch = primPatches[iB]; - for(std::set<MElement*>::iterator itEl = patch.begin(); itEl != patch.end(); ++itEl) { + elSet &patch = primPatches[iB]; + for(elSetIter itEl = patch.begin(); itEl != patch.end(); ++itEl) { std::set<int> &patchInd = tags[*itEl]; if (!patchInd.empty() && (badElements.find(*itEl) != badElements.end() || !par.patchDef->weakMerge)) { @@ -189,23 +222,22 @@ static std::vector<std::pair<std::set<MElement*>, std::set<MVertex*> > > getConn // Merge primary patches according to groups Msg::Info("Merging primary patches into %i patches...", groups.size()); - std::list<std::set<MElement*> > patches; + std::list<elSet > patches; for (std::list<std::set<int> >::iterator itG = groups.begin(); itG != groups.end(); ++itG) { - patches.push_back(std::set<MElement*>()); + patches.push_back(elSet()); for (std::set<int>::iterator itB = itG->begin(); itB != itG->end(); ++itB) { - std::set<MElement*> primPatch = primPatches[*itB]; + elSet primPatch = primPatches[*itB]; patches.back().insert(primPatch.begin(), primPatch.end()); } } // Store and compute patch boundaries Msg::Info("Computing boundaries for %i patches...", patches.size()); - std::vector<std::pair<std::set<MElement *>, std::set<MVertex*> > > result; - for (std::list<std::set<MElement*> >::iterator itB = patches.begin(); + std::vector<elSetVertSetPair > result; + for (std::list<elSet >::iterator itB = patches.begin(); itB != patches.end(); ++itB) - result.push_back(std::pair<std::set<MElement*>, std::set<MVertex*> > - (*itB, getAllBndVertices(*itB, vertex2elements))); + result.push_back(elSetVertSetPair(*itB, getAllBndVertices(*itB, vertex2elements))); Msg::Info("Generated %i patches", patches.size()); @@ -213,15 +245,14 @@ static std::vector<std::pair<std::set<MElement*>, std::set<MVertex*> > > getConn } -static void optimizeConnectedPatches - (const std::map<MVertex*, std::vector<MElement *> > &vertex2elements, - const std::map<MElement*,GEntity*> &element2entity, - std::set<MElement*> &badasses, MeshOptParameters &par) +void optimizeConnectedPatches(const vertElVecMap &vertex2elements, + const elEntMap &element2entity, + elSet &badasses, MeshOptParameters &par) { par.success = 1; - std::vector<std::pair<std::set<MElement*>, std::set<MVertex*> > > toOptimize = - getConnectedPatches(vertex2elements, badasses, par); + std::vector<elSetVertSetPair> toOptimize = getConnectedPatches(vertex2elements, + badasses, par); for (int iPatch = 0; iPatch < toOptimize.size(); ++iPatch) { @@ -229,8 +260,7 @@ static void optimizeConnectedPatches if (par.verbose > 1) Msg::Info("Optimizing patch %i/%i composed of %i elements", iPatch, toOptimize.size()-1, toOptimize[iPatch].first.size()); - MeshOpt opt(element2entity, toOptimize[iPatch].first, - toOptimize[iPatch].second, par); + MeshOpt opt(element2entity, toOptimize[iPatch].first, toOptimize[iPatch].second, par); if (par.verbose > 3) { std::ostringstream ossI1; ossI1 << "initial_patch-" << iPatch << ".msh"; @@ -257,16 +287,15 @@ static void optimizeConnectedPatches //#pragma omp critical par.success = std::min(par.success, success); } - } -static MElement *getWorstElement(std::set<MElement*> &badElts, const MeshOptParameters &par) +MElement *getWorstElement(elSet &badElts, const MeshOptParameters &par) { double worst = 1.e300; MElement *worstEl = 0; - for (std::set<MElement*>::iterator it=badElts.begin(); it!=badElts.end(); it++) { + for (elSetIter it=badElts.begin(); it!=badElts.end(); it++) { const double val = par.patchDef->elBadness(*it); if (val < worst) { worst = val; @@ -278,16 +307,17 @@ static MElement *getWorstElement(std::set<MElement*> &badElts, const MeshOptPara } -static void optimizeOneByOne - (const std::map<MVertex*, std::vector<MElement *> > &vertex2elements, - const std::map<MElement*,GEntity*> &element2entity, - std::set<MElement*> badElts, MeshOptParameters &par) +void optimizeOneByOne(const vertElVecMap &vertex2elements, + const elEntMap &element2entity, + elSet badElts, MeshOptParameters &par) { par.success = 1; const int initNumBadElts = badElts.size(); if (par.verbose > 0) Msg::Info("%d bad elements, starting to iterate...", initNumBadElts); + elElSetMap element2elements; // Element to element connectivity, built progressively + // Loop over bad elements for (int iBadEl=0; iBadEl<initNumBadElts; iBadEl++) { @@ -307,10 +337,10 @@ static void optimizeOneByOne // Set up patch const double limDist = par.patchDef->maxDistance(worstEl); - std::set<MElement*> toOptimizePrim = getSurroundingPatch(worstEl, par.patchDef, limDist, - maxLayers, vertex2elements); - std::set<MVertex*> toFix = getAllBndVertices(toOptimizePrim, vertex2elements); - std::set<MElement*> toOptimize; + elSet toOptimizePrim = getSurroundingPatch(worstEl, par.patchDef, limDist, + maxLayers, vertex2elements, element2elements); + vertSet toFix = getAllBndVertices(toOptimizePrim, vertex2elements); + elSet toOptimize; std::set_difference(toOptimizePrim.begin(),toOptimizePrim.end(), badElts.begin(),badElts.end(), std::inserter(toOptimize, toOptimize.end())); @@ -369,10 +399,13 @@ static void optimizeOneByOne } par.success = std::min(par.success, success); - } } + +} + + #endif @@ -386,9 +419,9 @@ void meshOptimizer(GModel *gm, MeshOptParameters &par) std::vector<GEntity*> entities; gm->getEntities(entities); - std::map<MVertex*, std::vector<MElement *> > vertex2elements; - std::map<MElement*,GEntity*> element2entity; - std::set<MElement*> badElts; + vertElVecMap vertex2elements; + elEntMap element2entity; + elSet badElts; for (int iEnt = 0; iEnt < entities.size(); ++iEnt) { GEntity* &entity = entities[iEnt]; if (entity->dim() != par.dim || @@ -396,15 +429,9 @@ void meshOptimizer(GModel *gm, MeshOptParameters &par) Msg::Info("Computing connectivity and bad elements for entity %d...", entity->tag()); calcVertex2Elements(par.dim,entity,vertex2elements); - for (int iEl = 0; iEl < entity->getNumMeshElements();iEl++) { // Detect bad elements + for (int iEl = 0; iEl < entity->getNumMeshElements();iEl++) { // Detect bad elements double jmin, jmax; MElement *el = entity->getMeshElement(iEl); -// if (el->getDim() == par.dim) { -// if (par.patchJac.test) { -// el->scaledJacRange(jmin, jmax); -// if (jmin < par.patchJac.min || jmax > par.patchJac.max) badElts.insert(el); -// } -// } if ((el->getDim() == par.dim) && (par.patchDef->elBadness(el) < 0.)) badElts.insert(el); } } @@ -428,9 +455,7 @@ void meshOptimizer(GModel *gm, MeshOptParameters &par) Msg::StatusBar(true, "Done optimizing mesh (%g s)", par.CPU); } - #else Msg::Error("Mesh optimizer requires BFGS"); #endif - }