diff --git a/Fltk/classificationEditor.cpp b/Fltk/classificationEditor.cpp index 4a1249c7b3ec44e68728e7544b94c8bae00e80a7..d9ea4825c6beb185133665d5c6fa0f4692ae5c84 100644 --- a/Fltk/classificationEditor.cpp +++ b/Fltk/classificationEditor.cpp @@ -19,88 +19,6 @@ #include "discreteEdge.h" #include "discreteFace.h" -struct compareMLinePtr { - bool operator () (MLine *l1, MLine *l2) const - { - static Less_Edge le; - return le(l1->getEdge(0), l2->getEdge(0)); - } -}; - -static void recurClassify(MTri3 *t, GFace *gf, - std::map<MLine*, GEdge*, compareMLinePtr> &lines, - std::map<MTriangle*, GFace*> &reverse) -{ - if(!t->isDeleted()){ - gf->triangles.push_back(t->tri()); - reverse[t->tri()] = gf; - t->setDeleted(true); - for(int i = 0; i < 3; i++){ - MTri3 *tn = t->getNeigh(i); - if(tn){ - edgeXface exf(t, i); - MLine ml(exf.v[0], exf.v[1]); - std::map<MLine*, GEdge*, compareMLinePtr>::iterator it = lines.find(&ml); - if(it == lines.end()) - recurClassify(tn, gf, lines, reverse); - } - } - } -} - -static GEdge *getNewModelEdge(GFace *gf1, GFace *gf2, - std::map<std::pair<int, int>, GEdge*> &newEdges) -{ - int t1 = gf1 ? gf1->tag() : -1; - int t2 = gf2 ? gf2->tag() : -1; - int i1 = std::min(t1, t2); - int i2 = std::max(t1, t2); - - if(i1 == i2) return 0; - - std::map<std::pair<int, int>, GEdge*>::iterator it = - newEdges.find(std::make_pair<int, int>(i1, i2)); - if(it == newEdges.end()){ - discreteEdge *ge = new discreteEdge - (GModel::current(), GModel::current()->getMaxElementaryNumber(1) + 1, 0, 0); - GModel::current()->add(ge); - newEdges[std::make_pair<int, int>(i1, i2)] = ge; - return ge; - } - else - return it->second; -} - -static void recurClassifyEdges(MTri3 *t, - std::map<MTriangle*, GFace*> &reverse, - std::map<MLine*, GEdge*, compareMLinePtr> &lines, - std::set<MLine*> &touched, - std::map<std::pair<int, int>, GEdge*> &newEdges) -{ - if(!t->isDeleted()){ - t->setDeleted(true); - GFace *gf1 = reverse[t->tri()]; - for(int i = 0; i < 3; i++){ - GFace *gf2 = 0; - MTri3 *tn = t->getNeigh(i); - if(tn) - gf2 = reverse[tn->tri()]; - edgeXface exf(t, i); - MLine ml(exf.v[0], exf.v[1]); - std::map<MLine*, GEdge*, compareMLinePtr>::iterator it = lines.find(&ml); - if(it != lines.end()){ - if(touched.find(it->first) == touched.end()){ - GEdge *ge = getNewModelEdge(gf1, gf2, newEdges); - if(ge) ge->lines.push_back(it->first); - touched.insert(it->first); - } - } - if(tn) - recurClassifyEdges(tn, reverse, lines, touched, newEdges); - } - } -} - static void NoElementsSelectedMode(classificationEditor *e) { e->buttons[CLASS_BUTTON_SELECT_ELEMENTS]->activate(); @@ -372,118 +290,8 @@ static void select_surfaces_cb(Fl_Widget *w, void *data) static void classify_cb(Fl_Widget *w, void *data) { classificationEditor *e = (classificationEditor*)data; - std::map<MLine*, GEdge*, compareMLinePtr> lines; - for(GModel::eiter it = GModel::current()->firstEdge(); - it != GModel::current()->lastEdge(); ++it){ - for(unsigned int i = 0; i < (*it)->lines.size();i++) - lines[(*it)->lines[i]] = *it; - } - - std::list<MTri3*> tris; - { - std::set<GFace*>::iterator it = e->faces.begin(); - while(it != e->faces.end()){ - GFace *gf = *it; - for(unsigned int i = 0; i < gf->triangles.size(); i++) - tris.push_back(new MTri3(gf->triangles[i], 0)); - gf->triangles.clear(); - ++it; - } - } - if(tris.empty()) return; - - connectTriangles(tris); - - std::map<MTriangle*, GFace*> reverse; - // color all triangles - std::list<MTri3*> ::iterator it = tris.begin(); - while(it != tris.end()){ - if(!(*it)->isDeleted()){ - discreteFace *gf = new discreteFace - (GModel::current(), GModel::current()->getMaxElementaryNumber(2) + 1); - recurClassify(*it, gf, lines, reverse); - GModel::current()->add(gf); - } - ++it; - } - - // color some lines - it = tris.begin(); - while(it != tris.end()){ - (*it)->setDeleted(false); - ++it; - } - - it = tris.begin(); - - // classify edges that are bound by different GFaces - std::map<std::pair<int, int>, GEdge*> newEdges; - std::set<MLine*> touched; - recurClassifyEdges(*it, reverse, lines, touched, newEdges); - - // check if new edges should not be splitted - // splitted if composed of several open or closed edges - for (std::map<std::pair<int, int>, GEdge*>::iterator it = newEdges.begin(); - it != newEdges.end() ; ++it){ - std::list<MLine*> segments; - for(unsigned int i = 0; i < it->second->lines.size(); i++) - segments.push_back(it->second->lines[i]); - while (!segments.empty()) { - std::vector<MLine*> myLines; - std::list<MLine*>::iterator it = segments.begin(); - MVertex *vB = (*it)->getVertex(0); - MVertex *vE = (*it)->getVertex(1); - myLines.push_back(*it); - segments.erase(it); - it++; - for (int i = 0; i < 2; i++) { - for (std::list<MLine*>::iterator it = segments.begin(); - it != segments.end(); ++it){ - MVertex *v1 = (*it)->getVertex(0); - MVertex *v2 = (*it)->getVertex(1); - std::list<MLine*>::iterator itp; - if (v1 == vE){ - myLines.push_back(*it); - itp = it; - it++; - segments.erase(itp); - vE = v2; - i = -1; - } - else if ( v2 == vE){ - myLines.push_back(*it); - itp = it; - it++; - segments.erase(itp); - vE = v1; - i = -1; - } - if (it == segments.end()) break; - } - if (vB == vE) break; - if (segments.empty()) break; - MVertex *temp = vB; - vB = vE; - vE = temp; - } - GEdge *newGe = new discreteEdge - (GModel::current(), GModel::current()->getMaxElementaryNumber(1) + 1, 0, 0); - newGe->lines.insert(newGe->lines.end(), myLines.begin(), myLines.end()); - GModel::current()->add(newGe); - } - } - - for (std::map<std::pair<int, int>, GEdge*>::iterator it = newEdges.begin(); - it != newEdges.end(); ++it){ - GEdge *ge = it->second; - GModel::current()->remove(ge); - } - - while(it != tris.end()){ - delete *it; - ++it; - } - + // classify faces with respect to coloured edges + GModel::current()->classifyFaces(e->faces); // remove selected, but do not delete its elements if(e->selected){ GModel::current()->remove(e->selected); diff --git a/Fltk/statisticsWindow.cpp b/Fltk/statisticsWindow.cpp index 546439453fe39fb445b54e0462a8b4a431a86ce2..576202d9ad0153764115415d27ec73efab7bc4e9 100644 --- a/Fltk/statisticsWindow.cpp +++ b/Fltk/statisticsWindow.cpp @@ -16,6 +16,7 @@ #include "Generator.h" #include "Context.h" #include "OS.h" +#include "Field.h" void statistics_cb(Fl_Widget *w, void *data) { @@ -204,15 +205,19 @@ void statisticsWindow::compute(bool elementQuality) // meanAngle = meanAngle / count; // printf("Angles = min=%g av=%g \n", minAngle, meanAngle); //hack emi - + /* //Emi hack - MESH DEGREE VERTICES std::vector<GEntity*> entities; + std::set<MEdge, Less_Edge> edges; GModel::current()->getEntities(entities); std::map<MVertex*, int > vert2Deg; for(unsigned int i = 0; i < entities.size(); i++){ if(entities[i]->dim() < 2) continue; for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++){ MElement *e = entities[i]->getMeshElement(j); + for(unsigned int k = 0; k < e->getNumEdges(); k++){ + edges.insert(e->getEdge(k)); + } for(unsigned int k = 0; k < e->getNumVertices(); k++){ MVertex *v = e->getVertex(k); if (v->onWhat()->dim() < 2) continue; @@ -243,6 +248,27 @@ void statisticsWindow::compute(bool elementQuality) printf("Stats degree vertices: dMin=%d , dMax=%d, d4=%g \n", dMin, dMax, (double)d4/nbElems); //end emi hack + FieldManager *fields = GModel::current()->getFields(); + Field *f = fields->get(fields->background_field); + if(fields->background_field > 0){ + std::set<MEdge, Less_Edge>::iterator it = edges.begin(); + double sum = 0; + for (; it !=edges.end();++it){ + MVertex *v0 = it->getVertex(0); + MVertex *v1 = it->getVertex(1); + double l = sqrt((v0->x()-v1->x())*(v0->x()-v1->x())+ + (v0->y()-v1->y())*(v0->y()-v1->y())+ + (v0->z()-v1->z())*(v0->z()-v1->z())); + double lf = (*f)(0.5*(v0->x()+v1->x()), 0.5*(v0->y()+v1->y()),0.5*(v0->z()+v1->z()),v0->onWhat()); + double e = (l>lf) ? lf/l : l/lf; + sum += e - 1.0; + } + double tau = exp ((1./edges.size()) * sum); + printf("nedegs = %d tau = %g\n",edges.size(),tau); + } + */ + + int num = 0; static double s[50]; static char label[50][256]; diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp index a6c8b05cb93d7fa789c5f33c8eba92616f255b88..4197747934f6fc2eb03e126659200f241e523da1 100644 --- a/Geo/GModel.cpp +++ b/Geo/GModel.cpp @@ -35,6 +35,7 @@ #include "MVertexPositionSet.h" #include "OpenFile.h" #include "CreateFile.h" +#include "meshGFaceOptimize.h" #if defined(HAVE_MESH) #include "Field.h" @@ -1993,6 +1994,339 @@ void GModel::insertRegion(GRegion *r) regions.insert(r); } +// given a set of mesh edges, build GFaces that separate those +// edges. + +struct compareMLinePtr { + bool operator () (MLine *l1, MLine *l2) const + { + static Less_Edge le; + return le(l1->getEdge(0), l2->getEdge(0)); + } +}; + + +static GEdge *getNewModelEdge(GFace *gf1, GFace *gf2, + std::map<std::pair<int, int>, GEdge*> &newEdges) +{ + int t1 = gf1 ? gf1->tag() : -1; + int t2 = gf2 ? gf2->tag() : -1; + int i1 = std::min(t1, t2); + int i2 = std::max(t1, t2); + + if(i1 == i2) return 0; + + std::map<std::pair<int, int>, GEdge*>::iterator it = + newEdges.find(std::make_pair<int, int>(i1, i2)); + if(it == newEdges.end()){ + discreteEdge *ge = new discreteEdge + (GModel::current(), GModel::current()->getMaxElementaryNumber(1) + 1, 0, 0); + GModel::current()->add(ge); + newEdges[std::make_pair<int, int>(i1, i2)] = ge; + return ge; + } + else + return it->second; +} + +static void recurClassifyEdges(MTri3 *t, + std::map<MTriangle*, GFace*> &reverse, + std::map<MLine*, GEdge*, compareMLinePtr> &lines, + std::set<MLine*> &touched, + std::set<MTri3*> &trisTouched, + std::map<std::pair<int, int>, GEdge*> &newEdges) +{ + if(!t->isDeleted()){ + trisTouched.erase(t); + t->setDeleted(true); + GFace *gf1 = reverse[t->tri()]; + for(int i = 0; i < 3; i++){ + GFace *gf2 = 0; + MTri3 *tn = t->getNeigh(i); + if(tn) + gf2 = reverse[tn->tri()]; + edgeXface exf(t, i); + MLine ml(exf.v[0], exf.v[1]); + std::map<MLine*, GEdge*, compareMLinePtr>::iterator it = lines.find(&ml); + if(it != lines.end()){ + if(touched.find(it->first) == touched.end()){ + GEdge *ge = getNewModelEdge(gf1, gf2, newEdges); + if(ge) ge->lines.push_back(it->first); + touched.insert(it->first); + } + } + if(tn) + recurClassifyEdges(tn, reverse, lines, touched, trisTouched,newEdges); + } + } +} + +static void recurClassify(MTri3 *t, GFace *gf, + std::map<MLine*, GEdge*, compareMLinePtr> &lines, + std::map<MTriangle*, GFace*> &reverse) +{ + if(!t->isDeleted()){ + gf->triangles.push_back(t->tri()); + reverse[t->tri()] = gf; + t->setDeleted(true); + for(int i = 0; i < 3; i++){ + MTri3 *tn = t->getNeigh(i); + if(tn){ + edgeXface exf(t, i); + MLine ml(exf.v[0], exf.v[1]); + std::map<MLine*, GEdge*, compareMLinePtr>::iterator it = lines.find(&ml); + if(it == lines.end()) + recurClassify(tn, gf, lines, reverse); + } + } + } +} + +void GModel::detectEdges(double _tresholdAngle) { + e2t_cont adj; + std::vector<MTriangle*> elements; + std::vector<edge_angle> edges_detected, edges_lonly; + for(GModel::fiter it = GModel::current()->firstFace(); + it != GModel::current()->lastFace(); ++it) + elements.insert(elements.end(), (*it)->triangles.begin(), + (*it)->triangles.end()); + buildEdgeToTriangle(elements, adj); + buildListOfEdgeAngle(adj, edges_detected, edges_lonly); + GEdge *selected = new discreteEdge + (this, getMaxElementaryNumber(1) + 1, 0, 0); + add(selected); + + for(unsigned int i = 0; i < edges_detected.size(); i++){ + edge_angle ea = edges_detected[i]; + if(ea.angle <= _tresholdAngle) break; + selected->lines.push_back(new MLine(ea.v1, ea.v2)); + } + + for(unsigned int i = 0 ; i < edges_lonly.size(); i++){ + edge_angle ea = edges_lonly[i]; + selected->lines.push_back(new MLine(ea.v1, ea.v2)); + } + std::set<GFace*> _temp; + _temp.insert(faces.begin(),faces.end()); + classifyFaces(_temp); + remove(selected); + // delete selected; +} + +void GModel::classifyFaces(std::set<GFace*> &_faces) { + + std::map<MLine*, GEdge*, compareMLinePtr> lines; + + for(GModel::eiter it = GModel::current()->firstEdge(); + it != GModel::current()->lastEdge(); ++it){ + for(unsigned int i = 0; i < (*it)->lines.size();i++) + lines[(*it)->lines[i]] = *it; + } + + std::map<MTriangle*, GFace*> reverse_old; + std::list<MTri3*> tris; + { + std::set<GFace*>::iterator it = _faces.begin(); + while(it != _faces.end()){ + GFace *gf = *it; + for(unsigned int i = 0; i < gf->triangles.size(); i++){ + tris.push_back(new MTri3(gf->triangles[i], 0)); + reverse_old[gf->triangles[i]] = gf; + } + gf->triangles.clear(); + gf->mesh_vertices.clear(); + ++it; + } + } + if(tris.empty()) return; + + connectTriangles(tris); + + std::map<MTriangle*, GFace*> reverse; + std::multimap<GFace*, GFace*> replacedBy; + // color all triangles + std::list<MTri3*> ::iterator it = tris.begin(); + std::list<GFace*> newf; + while(it != tris.end()){ + if(!(*it)->isDeleted()){ + discreteFace *gf = new discreteFace + (GModel::current(), GModel::current()->getMaxElementaryNumber(2) + 1); + recurClassify(*it, gf, lines, reverse); + GModel::current()->add(gf); + newf.push_back(gf); + + for (int i=0;i<gf->triangles.size();i++){ + replacedBy.insert(std::make_pair(reverse_old[gf->triangles[i]],gf)); + } + } + ++it; + } + + // now we have all faces coloured. If some regions were existing, replace + // their faces by the new ones + + for (riter rit = firstRegion(); rit != lastRegion(); ++rit){ + std::list<GFace *> _xfaces = (*rit)->faces(); + std::set<GFace *> _newFaces; + for (std::list<GFace *>::iterator itf = _xfaces.begin(); itf != _xfaces.end(); ++itf){ + std::multimap<GFace*, GFace*>::iterator itLow = replacedBy.lower_bound(*itf); + std::multimap<GFace*, GFace*>::iterator itUp = replacedBy.upper_bound(*itf); + for (; itLow != itUp; ++itLow) + _newFaces.insert(itLow->second); + } + std::list<GFace *> _temp; + _temp.insert(_temp.begin(),_newFaces.begin(),_newFaces.end()); + (*rit)->set(_temp); + } + + // color some lines + it = tris.begin(); + while(it != tris.end()){ + (*it)->setDeleted(false); + ++it; + } + + // classify edges that are bound by different GFaces + std::map<std::pair<int, int>, GEdge*> newEdges; + std::set<MLine*> touched; + std::set<MTri3*> trisTouched; + // bug fix : multiply connected domains + + trisTouched.insert(tris.begin(),tris.end()); + while(!trisTouched.empty()) + recurClassifyEdges(*trisTouched.begin(), reverse, lines, touched, trisTouched,newEdges); + + // printf("%d new edges\n",newEdges.size()); + + std::map<discreteFace*,std::vector<int> > newFaceTopology; + + // check if new edges should not be splitted + // splitted if composed of several open or closed edges + + std::map<MVertex*,GVertex*> modelVertices; + + for (std::map<std::pair<int, int>, GEdge*>::iterator ite = newEdges.begin(); + ite != newEdges.end() ; ++ite){ + std::list<MLine*> allSegments; + for(unsigned int i = 0; i < ite->second->lines.size(); i++) + allSegments.push_back(ite->second->lines[i]); + + while (!allSegments.empty()) { + std::list<MLine*> segmentsForThisDiscreteEdge; + MVertex *vB = (*allSegments.begin())->getVertex(0); + MVertex *vE = (*allSegments.begin())->getVertex(1); + segmentsForThisDiscreteEdge.push_back(*allSegments.begin()); + allSegments.erase(allSegments.begin()); + while(1){ + bool found = false; + for (std::list<MLine*>::iterator it = allSegments.begin();it != allSegments.end(); ++it){ + MVertex *v1 = (*it)->getVertex(0); + MVertex *v2 = (*it)->getVertex(1); + if (v1 == vE || v2 == vE){ + segmentsForThisDiscreteEdge.push_back(*it); + if (v2 == vE)(*it)->revert(); + vE = (v1 == vE) ? v2 : v1; + found = true; + allSegments.erase(it); + break; + } + if (v1 == vB || v2 == vB){ + segmentsForThisDiscreteEdge.push_front(*it); + if (v1 == vB)(*it)->revert(); + vB = (v1 == vB) ? v2 : v1; + found = true; + allSegments.erase(it); + break; + } + } + if (vE == vB)break; + if (!found)break; + } + + std::map<MVertex*,GVertex*>::iterator itMV = modelVertices.find(vB); + if (itMV == modelVertices.end()){ + GVertex *newGv = new discreteVertex(GModel::current(), + GModel::current()->getMaxElementaryNumber(0) + 1); + newGv->mesh_vertices.push_back(vB); + vB->setEntity(newGv); + newGv->points.push_back(new MPoint(vB)); + GModel::current()->add(newGv); + modelVertices[vB] = newGv; + } + itMV = modelVertices.find(vE); + if (itMV == modelVertices.end()){ + GVertex *newGv = new discreteVertex(GModel::current(), + GModel::current()->getMaxElementaryNumber(0) + 1); + newGv->mesh_vertices.push_back(vE); + newGv->points.push_back(new MPoint(vE)); + vE->setEntity(newGv); + GModel::current()->add(newGv); + modelVertices[vE] = newGv; + } + + GEdge *newGe = new discreteEdge + (GModel::current(), GModel::current()->getMaxElementaryNumber(1) + 1, modelVertices[vB], modelVertices[vE]); + newGe->lines.insert(newGe->lines.end(), segmentsForThisDiscreteEdge.begin(), segmentsForThisDiscreteEdge.end()); + + // printf("discrete edge %d\n",newGe->tag()); + for (std::list<MLine*>::iterator itL = segmentsForThisDiscreteEdge.begin(); + itL != segmentsForThisDiscreteEdge.end(); ++itL){ + if((*itL)->getVertex(0)->onWhat()->dim() != 0){ + newGe->mesh_vertices.push_back((*itL)->getVertex(0)); + (*itL)->getVertex(0)->setEntity(newGe); + } + // printf("%d %d \n",(*itL)->getVertex(0)->getNum(),(*itL)->getVertex(1)->getNum()); + } + + GModel::current()->add(newGe); + discreteFace *gf1 = dynamic_cast<discreteFace*> (GModel::current()->getFaceByTag(ite->first.first)); + discreteFace *gf2 = dynamic_cast<discreteFace*> (GModel::current()->getFaceByTag(ite->first.second)); + if (gf1)newFaceTopology[gf1].push_back(newGe->tag()); + if (gf2)newFaceTopology[gf2].push_back(newGe->tag()); + } + } + + std::map<discreteFace*,std::vector<int> >::iterator itFT = newFaceTopology.begin(); + for (;itFT != newFaceTopology.end();++itFT){ + itFT->first->setBoundEdges(itFT->second); + } + + + for (std::map<std::pair<int, int>, GEdge*>::iterator it = newEdges.begin(); + it != newEdges.end(); ++it){ + GEdge *ge = it->second; + GModel::current()->remove(ge); + // delete ge; + } + + it = tris.begin(); + while(it != tris.end()){ + delete *it; + ++it; + } + + // delete empty mesh faces and reclasssify + std::set<GFace*, GEntityLessThan> fac = faces; + for (fiter fit = fac.begin() ; fit !=fac.end() ; ++fit){ + std::set<MVertex *> _verts; + (*fit)->mesh_vertices.clear(); + for (int i=0;i<(*fit)->triangles.size();i++){ + for (int j=0;j<3;j++){ + if ((*fit)->triangles[i]->getVertex(j)->onWhat()->dim() > 1){ + (*fit)->triangles[i]->getVertex(j)->setEntity(*fit); + _verts.insert((*fit)->triangles[i]->getVertex(j)); + } + } + } + if ((*fit)->triangles.size()) + (*fit)->mesh_vertices.insert((*fit)->mesh_vertices.begin(),_verts.begin(),_verts.end()); + else + remove(*fit); + } +} + + + #include "Bindings.h" void GModel::registerBindings(binding *b) @@ -2155,6 +2489,10 @@ void GModel::registerBindings(binding *b) cm->setDescription("build the topology for a given mesh."); cm->setArgNames(NULL); + cm = cb->addMethod("detectEdges", &GModel::detectEdges); + cm->setDescription(" use an angle threshold to tag edges."); + cm->setArgNames("angle",NULL); + cm = cb->addMethod("createBoundaryLayer", &GModel::createBoundaryLayer); cm->setDescription("create a boundary layer using a given field for the " "extrusion height."); diff --git a/Geo/GModel.h b/Geo/GModel.h index 8a1297ea358f7e0bda994fcde11720086cfb54d0..1b491bfd78adb10da6c3b04b8b66b9a723f57d48 100644 --- a/Geo/GModel.h +++ b/Geo/GModel.h @@ -362,6 +362,11 @@ class GModel // mesh the model int mesh(int dimension); + // reclassify a mesh i.e. use an angle threshold to tag edges faces and regions + void detectEdges(double _tresholdAngle); + void classifyFaces(std::set<GFace*> &_faces); + + // glue entities in the model (assume a tolerance eps and merge // vertices that are too close, then merge edges, faces and // regions). Warning: the gluer changes the geometric model, so that diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp index e6d1f18a8b6fb37a644c17dae326b315a8cbde96..1477f38978b16d8ba0a13b538886f42700714c4a 100644 --- a/Geo/GModelIO_Mesh.cpp +++ b/Geo/GModelIO_Mesh.cpp @@ -1077,9 +1077,14 @@ int GModel::readSTL(const std::string &name, double tolerance) } Msg::Info("%d facets in solid %d", points[i].size() / 3, i); // create face - GFace *face = new discreteFace(this, getMaxElementaryNumber(2) + 1); + GFace *face = new discreteFace(this, getMaxElementaryNumber(2) + 1); + GRegion *region = new GRegion(this, getMaxElementaryNumber(3) + 1); faces.push_back(face); add(face); + add(region); + std::list<GFace*> _temp; + _temp.push_back(face); + region->set(_temp); } // create triangles using unique vertices @@ -1091,6 +1096,8 @@ int GModel::readSTL(const std::string &name, double tolerance) points[i][j].z())); MVertexPositionSet pos(vertices); + std::set<MFace,Less_Face> unique; + int nbDuplic = 0; for(unsigned int i = 0; i < points.size(); i ++){ for(unsigned int j = 0; j < points[i].size(); j += 3){ MVertex *v[3]; @@ -1100,9 +1107,17 @@ int GModel::readSTL(const std::string &name, double tolerance) double z = points[i][j + k].z(); v[k] = pos.find(x, y, z, eps); } - faces[i]->triangles.push_back(new MTriangle(v[0], v[1], v[2])); + MFace mf (v[0],v[1],v[2]); + if (unique.find(mf) == unique.end()){ + faces[i]->triangles.push_back(new MTriangle(v[0], v[1], v[2])); + unique.insert(mf); + } + else{ + nbDuplic++; + } } } + if (nbDuplic) Msg::Warning("%d Duplicate triangle in STL file read",nbDuplic); _associateEntityWithMeshVertices(); _storeVerticesInEntities(vertices); // will delete unused vertices diff --git a/Geo/GModelIO_OCC.cpp b/Geo/GModelIO_OCC.cpp index 8e1d5eb302ade22fe2f925cbf3e0ec0096843da2..cc14fe9075a5159cf0e3791f88dca14511db0e55 100644 --- a/Geo/GModelIO_OCC.cpp +++ b/Geo/GModelIO_OCC.cpp @@ -501,6 +501,7 @@ GRegion* OCC_Internals::addRegionToModel(GModel *model, TopoDS_Solid region){ void OCC_Internals::buildGModel(GModel *model) { + // building geom vertices int nvertices = vmap.Extent(); for(int i = 1; i <= nvertices; i++){ @@ -508,6 +509,7 @@ void OCC_Internals::buildGModel(GModel *model) if (!getOCCVertexByNativePtr(model,TopoDS::Vertex(vmap(i)))) model->add(new OCCVertex(model,num , TopoDS::Vertex(vmap(i)))); } + // building geom edges int nedges = emap.Extent(); for(int i = 1; i <= nedges; i++){ @@ -517,6 +519,7 @@ void OCC_Internals::buildGModel(GModel *model) if (!getOCCEdgeByNativePtr(model,TopoDS::Edge(emap(i)))) model->add(new OCCEdge(model, TopoDS::Edge(emap(i)), num, model->getVertexByTag(i1), model->getVertexByTag(i2))); } + // building geom faces int nfaces = fmap.Extent(); for(int i = 1; i <= nfaces; i++){ diff --git a/Geo/GRegion.cpp b/Geo/GRegion.cpp index 3741d99f2aabe20a8021da33942e45b6ec5d74f8..fa43377ae45a9a9e73005682f3c9b30954bdd9f2 100644 --- a/Geo/GRegion.cpp +++ b/Geo/GRegion.cpp @@ -299,6 +299,90 @@ void GRegion::replaceFaces (std::list<GFace*> &new_faces) l_dirs = newdirs; } +double GRegion::computeSolidProperties (std::vector<double> cg, + std::vector<double> inertia){ + std::list<GFace*>::iterator it = l_faces.begin(); + std::list<int>::iterator itdir = l_dirs.begin(); + double volumex = 0; + double volumey = 0; + double volumez = 0; + double surface = 0; + cg[0] = cg[1] = cg[2] = 0.0; + for ( ; it != l_faces.end(); ++it,++itdir){ + printf("face %d dir %d %d elements\n",(*it)->tag(),*itdir,(*it)->triangles.size()); + for (int i=0;i<(*it)->triangles.size();++i){ + MTriangle *e = (*it)->triangles[i]; + // MElement *e = (*it)->getMeshElement(i); + int npt; + IntPt *pts; + e->getIntegrationPoints (2*(e->getPolynomialOrder()-1)+3, &npt, &pts); + for (int j=0;j<npt;j++){ + SPoint3 pt; + // compute x,y,z of the integration point + e->pnt(pts[j].pt[0],pts[j].pt[1],pts[j].pt[2],pt); + double jac[3][3]; + // compute normal + double detJ = e->getJacobian(pts[j].pt[0],pts[j].pt[1],pts[j].pt[2],jac); + SVector3 n (jac[2][0],jac[2][1],jac[2][2]); + n.normalize(); + n *= (double)*itdir; + surface += detJ*pts[j].weight; + volumex += detJ*n.x()*pt.x()*pts[j].weight; + volumey += detJ*n.y()*pt.y()*pts[j].weight; + volumez += detJ*n.z()*pt.z()*pts[j].weight; + cg[0] += detJ*n.x()*(pt.x()*pt.x())*pts[j].weight*0.5; + cg[1] += detJ*n.y()*(pt.y()*pt.y())*pts[j].weight*0.5; + cg[2] += detJ*n.z()*(pt.z()*pt.z())*pts[j].weight*0.5; + } + } + } + + printf("%g -- %g %g %g\n",surface,volumex,volumey,volumez); + + double volume = volumex; + + cg[0]/=volume; + cg[1]/=volume; + cg[2]/=volume; + + it = l_faces.begin(); + itdir = l_dirs.begin(); + inertia[0] = + inertia[1] = + inertia[2] = + inertia[3] = + inertia[4] = + inertia[5] = 0.0; + + for ( ; it != l_faces.end(); ++it,++itdir){ + for (int i=0;i<(*it)->getNumMeshElements();++i){ + MElement *e = (*it)->getMeshElement(i); + int npt; + IntPt *pts; + e->getIntegrationPoints (2*(e->getPolynomialOrder()-1)+3, &npt, &pts); + for (int j=0;j<npt;j++){ + SPoint3 pt; + // compute x,y,z of the integration point + e->pnt(pts[j].pt[0],pts[j].pt[1],pts[j].pt[2],pt); + double jac[3][3]; + // compute normal + double detJ = e->getJacobian(pts[j].pt[0],pts[j].pt[1],pts[j].pt[2],jac); + SVector3 n (jac[2][0],jac[2][1],jac[2][2]); + n *= (double)*itdir; + inertia[0] += pts[j].weight*detJ*n.x()*(pt.x()-cg[0])*(pt.x()-cg[0])*(pt.x()-cg[0])/3.0; + inertia[1] += pts[j].weight*detJ*n.y()*(pt.y()-cg[1])*(pt.y()-cg[1])*(pt.y()-cg[1])/3.0; + inertia[2] += pts[j].weight*detJ*n.z()*(pt.z()-cg[2])*(pt.z()-cg[2])*(pt.z()-cg[2])/3.0; + inertia[3] += pts[j].weight*detJ*n.x()*(pt.y()-cg[1])*(pt.x()-cg[0])*(pt.x()-cg[0])/3.0; + inertia[4] += pts[j].weight*detJ*n.x()*(pt.z()-cg[2])*(pt.x()-cg[0])*(pt.x()-cg[0])/3.0; + inertia[5] += pts[j].weight*detJ*n.y()*(pt.z()-cg[2])*(pt.y()-cg[1])*(pt.y()-cg[1])/3.0; + } + } + } + return volume; +} + + + void GRegion::addPrism(MPrism *p) { prisms.push_back(p); } @@ -317,4 +401,7 @@ void GRegion::registerBindings(binding *b) cm = cb->addMethod("addPrism", &GRegion::addPrism); cm->setDescription("insert a prism mesh element"); cm->setArgNames("prism", NULL); + cm = cb->addMethod("computeSolidProperties", &GRegion::computeSolidProperties); + cm->setDescription("returns the volume and computes the center of gravity and tensor of inertia of the volume (requires a surface mesh)"); + cm->setArgNames("cg","inertia", NULL); } diff --git a/Geo/GRegion.h b/Geo/GRegion.h index 705361afee2a9989c5c5614993b4374f9436fc58..d00fe5ddc877a9e3bec56948460ed7dd29c3a593 100644 --- a/Geo/GRegion.h +++ b/Geo/GRegion.h @@ -107,6 +107,10 @@ class GRegion : public GEntity { // replace edges (gor gluing) void replaceFaces (std::list<GFace*> &); + // compute volume, moment of intertia and center of gravity + double computeSolidProperties (std::vector<double> cg, + std::vector<double> inertia); + static void registerBindings(binding *b); }; diff --git a/Geo/Geo.cpp b/Geo/Geo.cpp index 3235a8f2a6653100a81d56e630b716240673059e..a3173f07836b611fbde1b09a40665c7a21fd3fce 100644 --- a/Geo/Geo.cpp +++ b/Geo/Geo.cpp @@ -1178,7 +1178,6 @@ void DeleteShape(int Type, int Num) if(gf) GModel::current()->remove(gf); } break; - case MSH_VOLUME_FROM_GMODEL: { GRegion *gr = GModel::current()->getRegionByTag(Num); diff --git a/Geo/discreteEdge.cpp b/Geo/discreteEdge.cpp index c112f4df7d47da90ab358fec1f6b76985c99794b..d94a56b2640bf623b09b5e64daa348422a0744c9 100644 --- a/Geo/discreteEdge.cpp +++ b/Geo/discreteEdge.cpp @@ -490,3 +490,9 @@ Range<double> discreteEdge::parBounds(int i) const { return Range<double>(0, lines.size()); } + +void discreteEdge::writeGEO(FILE *fp) +{ + if (getBeginVertex() && getEndVertex()) + fprintf(fp, "Discrete Line(%d) = {%d,%d};\n",tag(), getBeginVertex()->tag(), getEndVertex()->tag()); +} diff --git a/Geo/discreteEdge.h b/Geo/discreteEdge.h index 5c475bc28bc051d712cdaeaf608d19e647952135..29671932c147a48a0a92b289837c01c1a7572529 100644 --- a/Geo/discreteEdge.h +++ b/Geo/discreteEdge.h @@ -32,6 +32,7 @@ class discreteEdge : public GEdge { void setBoundVertices(); void createTopo(); void computeNormals () const; + void writeGEO(FILE *fp); }; #endif diff --git a/Geo/discreteFace.cpp b/Geo/discreteFace.cpp index 5a56ea02efb1c4f85cb3ad0fa3117acc976266ae..d872593d5f8a0e1da7b6855541d34af749cd9840 100644 --- a/Geo/discreteFace.cpp +++ b/Geo/discreteFace.cpp @@ -122,3 +122,17 @@ void discreteFace::secondDer(const SPoint2 ¶m, return; } } + +void discreteFace::writeGEO(FILE *fp) +{ + fprintf(fp, "Discrete Face(%d) = {",tag()); + int count = 0; + for (std::list<GEdge*>::iterator it = l_edges.begin(); + it != l_edges.end() ;++it){ + if (count == 0)fprintf(fp, "%d",(*it)->tag()); + else fprintf(fp, ",%d",(*it)->tag()); + count ++; + } + fprintf(fp, "};\n"); + +} diff --git a/Geo/discreteFace.h b/Geo/discreteFace.h index db16cfa9a41279f6f3ee0c26b5b4ad53b708d4cb..78bfa782e9ca7ae22aeb03e61f1520b471fedb31 100644 --- a/Geo/discreteFace.h +++ b/Geo/discreteFace.h @@ -25,6 +25,7 @@ class discreteFace : public GFace { SVector3 *dudu, SVector3 *dvdv, SVector3 *dudv) const; void setBoundEdges(std::vector<int> tagEdges); void findEdges(std::map<MEdge, std::vector<int>, Less_Edge > &map_edges); + void discreteFace::writeGEO(FILE *fp); }; #endif diff --git a/Mesh/Generator.cpp b/Mesh/Generator.cpp index 3bebd69de2aed13756a788be0c3ccc8673717fa5..276f6b84703b1fea73ffb78a4e2299a8918625a7 100644 --- a/Mesh/Generator.cpp +++ b/Mesh/Generator.cpp @@ -616,7 +616,7 @@ void GenerateMesh(GModel *m, int ask) } // Subdivide into quads or hexas - if(m->getMeshStatus() == 2 && CTX::instance()->mesh.algoSubdivide == 1) + if(m->getMeshStatus() == 2 && CTX::instance()->mesh.recombineAll && CTX::instance()->mesh.algoRecombine != 1) RefineMesh(m, CTX::instance()->mesh.secondOrderLinear, true); else if(m->getMeshStatus() == 3 && CTX::instance()->mesh.algoSubdivide == 2) RefineMesh(m, CTX::instance()->mesh.secondOrderLinear, false, true); diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp index dd8da594edd71d6a9352cce5efcc35812f71c5c0..2c6be0d2950c1c02ae33ac2f336e26b128b2b000 100644 --- a/Mesh/meshGFace.cpp +++ b/Mesh/meshGFace.cpp @@ -296,7 +296,7 @@ static void remeshUnrecoveredEdges(std::map<MVertex*, BDS_Point*> &recoverMapInv static bool algoDelaunay2D(GFace *gf) { // HACK REMOVE ME - if (gf->geomType() == GEntity::CompoundSurface)return true; + // if (gf->geomType() == GEntity::CompoundSurface)return true; if(noSeam(gf) && (CTX::instance()->mesh.algo2d == ALGO_2D_DELAUNAY || CTX::instance()->mesh.algo2d == ALGO_2D_BAMG || @@ -872,8 +872,8 @@ static bool meshGenerator(GFace *gf, int RECUR_ITER, // BDS mesh is passed in order not to recompute local coordinates of // vertices if(algoDelaunay2D(gf)){ - if(CTX::instance()->mesh.algo2d == ALGO_2D_FRONTAL || - gf->geomType() == GEntity::CompoundSurface) + if(CTX::instance()->mesh.algo2d == ALGO_2D_FRONTAL)// || + // gf->geomType() == GEntity::CompoundSurface) bowyerWatsonFrontal(gf); else if(CTX::instance()->mesh.algo2d == ALGO_2D_DELAUNAY) bowyerWatson(gf); @@ -1454,8 +1454,8 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true) } if(algoDelaunay2D(gf)){ - if(CTX::instance()->mesh.algo2d == ALGO_2D_FRONTAL || - gf->geomType() == GEntity::CompoundSurface) + if(CTX::instance()->mesh.algo2d == ALGO_2D_FRONTAL)// || + // gf->geomType() == GEntity::CompoundSurface) bowyerWatsonFrontal(gf); else if(CTX::instance()->mesh.algo2d == ALGO_2D_DELAUNAY) bowyerWatson(gf); diff --git a/Mesh/meshGFaceDelaunayInsertion.cpp b/Mesh/meshGFaceDelaunayInsertion.cpp index 44452b2c8003123f334cfdb2661ad5ffadd88864..6c8bec0890cad8fd20ca448eef4533bd3d94d434 100644 --- a/Mesh/meshGFaceDelaunayInsertion.cpp +++ b/Mesh/meshGFaceDelaunayInsertion.cpp @@ -16,7 +16,7 @@ #include "Numeric.h" #include "STensor3.h" -const double LIMIT_ = 0.5 * sqrt(2.0); +const double LIMIT_ = 0.5 * sqrt(2.0) * 1; static const bool _experimental_anisotropic_blues_band_ = false; diff --git a/Mesh/meshGFaceOptimize.cpp b/Mesh/meshGFaceOptimize.cpp index dbf4610d1e322fa9de5a0cacb0c5a38da5c2fc4c..cea0fc23a2812c9cc9b13a260f65127a38b610f8 100644 --- a/Mesh/meshGFaceOptimize.cpp +++ b/Mesh/meshGFaceOptimize.cpp @@ -849,6 +849,10 @@ void laplaceSmoothing(GFace *gf) int _edgeSwapQuadsForBetterQuality ( GFace *gf ) { return 0; + + v2t_cont adj_v; + buildVertexToElement(gf->quadrangles,adj_v); + e2t_cont adj; // buildEdgeToElement(gf->triangles, adj); buildEdgeToElement(gf->quadrangles, adj); @@ -882,30 +886,41 @@ int _edgeSwapQuadsForBetterQuality ( GFace *gf ) { if (ed.getVertex(0) == v2 && ed.getVertex(1) != v1)v22 = ed.getVertex(1); if (ed.getVertex(1) == v2 && ed.getVertex(0) != v1)v22 = ed.getVertex(0); } - MQuadrangle *q1 = new MQuadrangle (v11,v22,v2,v12); - MQuadrangle *q2 = new MQuadrangle (v22,v11,v1,v21); - - double sold = surfaceFaceUV(e1,gf) + surfaceFaceUV(e2,gf); - double snew = surfaceFaceUV(q1,gf) + surfaceFaceUV(q2,gf); - - double min_quality_old = std::min(e1->etaShapeMeasure(),e2->etaShapeMeasure()); - double min_quality_new = std::min(q1->etaShapeMeasure(),q2->etaShapeMeasure()); - - // if (min_quality_old < min_quality_new){ - if (sold > 1.00001*snew){ - printf("%g %g\n",sold, snew); + MQuadrangle *q1=0,*q2=0; + v2t_cont :: iterator it2 = adj_v.find(v2); + v2t_cont :: iterator it1 = adj_v.find(v1); + v2t_cont :: iterator it22 = adj_v.find(v22); + v2t_cont :: iterator it12 = adj_v.find(v12); + v2t_cont :: iterator it21 = adj_v.find(v21); + v2t_cont :: iterator it11 = adj_v.find(v11); + /* + int connectivity_default_config_1 = + abs(it1->size() - 4) + + abs(it2->size() - 4) + + abs(it2->size() - 4) + + abs(it2->size() - 4) ; + */ + if (it2->second.size() >= 5 && it1->second.size() >= 5){ + if (it22->second.size() <= 3 && it11->second.size() <= 3) { + q1 = new MQuadrangle (v11,v22,v2,v12); + q2 = new MQuadrangle (v22,v11,v1,v21); + } + else if (it21->second.size() <= 3 && it12->second.size() <= 3) { + q1 = new MQuadrangle (v11,v12,v21,v1); + q2 = new MQuadrangle (v21,v12,v2,v22); + } + } + if (q1 && q2){ deleted.insert(e1); deleted.insert(e2); created.push_back(q1); created.push_back(q2); + printf("edge swap performed\n"); COUNT++; } - else{ - delete q1; - delete q2; - } } } + if (COUNT)break; } for(unsigned int i = 0; i < gf->quadrangles.size(); i++){ @@ -1371,6 +1386,19 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) elist[2*i] = t2n[pairs[i].t1]; elist[2*i+1] = t2n[pairs[i].t2]; elen [i] = (int) pairs[i].angle; + double angle = atan2(pairs[i].n1->y()-pairs[i].n2->y(), + pairs[i].n1->x()-pairs[i].n2->x()); + + double x = .5*(pairs[i].n1->x()+pairs[i].n2->x()); + double y = .5*(pairs[i].n1->y()+pairs[i].n2->y()); + double opti = atan2(y,x); + angle -= opti; + while (angle < 0 || angle > M_PI/2){ + if (angle < 0) angle += M_PI/2; + if (angle > M_PI/2) angle -= M_PI/2; + } + //elen [i] = (int) 180. * fabs(angle-M_PI/4)/M_PI; + int NB = 0; if (pairs[i].n1->onWhat()->dim() < 2)NB++; if (pairs[i].n2->onWhat()->dim() < 2)NB++; @@ -1558,7 +1586,7 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) void recombineIntoQuads(GFace *gf) { - // gf->model()->writeMSH("before.msh"); + gf->model()->writeMSH("before.msh"); removeFourTrianglesNodes(gf, false); int success = _recombineIntoQuads(gf,0); gf->model()->writeMSH("raw.msh"); diff --git a/Mesh/meshGFaceOptimize.h b/Mesh/meshGFaceOptimize.h index e6b8e7538a5ee6a848da596ad29d24abc3688f92..bda526530abb7e3841b51e3bafd82448aa60a1e6 100644 --- a/Mesh/meshGFaceOptimize.h +++ b/Mesh/meshGFaceOptimize.h @@ -30,6 +30,9 @@ class edge_angle { typedef std::map<MVertex*, std::vector<MElement*> > v2t_cont; typedef std::map<MEdge, std::pair<MElement*, MElement*>, Less_Edge> e2t_cont; +template <class T> void buildVertexToElement(std::vector<T*> &eles, v2t_cont &adj); +template <class T> void buildEdgeToElement(std::vector<T*> &eles, e2t_cont &adj); + void buildVertexToTriangle(std::vector<MTriangle*> &, v2t_cont &adj); void buildEdgeToTriangle(std::vector<MTriangle*> &, e2t_cont &adj); void buildListOfEdgeAngle(e2t_cont adj, std::vector<edge_angle> &edges_detected, diff --git a/Mesh/meshRefine.cpp b/Mesh/meshRefine.cpp index c2e526392b43ca26891757af1834e5728372b444..021c17ca9a7ff6be31a5f32478f0fe53723cf07c 100644 --- a/Mesh/meshRefine.cpp +++ b/Mesh/meshRefine.cpp @@ -17,6 +17,8 @@ #include "MPyramid.h" #include "GmshMessage.h" #include "OS.h" +#include "Context.h" +#include "meshGFaceOptimize.h" class MVertexLessThanParam{ public: @@ -375,8 +377,11 @@ void RefineMesh(GModel *m, bool linear, bool splitIntoQuads, bool splitIntoHexas // mesh for(GModel::eiter it = m->firstEdge(); it != m->lastEdge(); ++it) Subdivide(*it); - for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it) + for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it){ Subdivide(*it, splitIntoQuads, splitIntoHexas, faceVertices); + for(int i = 0; i < CTX::instance()->mesh.nbSmoothing; i++) + laplaceSmoothing(*it); + } for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it) Subdivide(*it, splitIntoHexas, faceVertices); diff --git a/benchmarks/boolean/wikipedia.lua b/benchmarks/boolean/wikipedia.lua index bd1ee4e9b56f403e2ca28a3d1162b6e613dd7d15..1d7a612cd5cc8fca0329e8a61ba5efcac19dc9b7 100644 --- a/benchmarks/boolean/wikipedia.lua +++ b/benchmarks/boolean/wikipedia.lua @@ -1,8 +1,8 @@ -- from http://en.wikipedia.org/wiki/Constructive_solid_geometry -R = 1.0; -s = .8; +R = 1.4; +s = .4; t = 1.35; myModel = GModel(); myModel:addBlock({-R,-R,-R},{R,R,R});