From 777e460187f5b32d435d6d4d881b22506d2fc8b0 Mon Sep 17 00:00:00 2001 From: Tristan Carrier Baudouin <tristan.carrier@uclouvain.be> Date: Fri, 20 May 2011 12:31:26 +0000 Subject: [PATCH] levy --- Geo/GFace.h | 3 +- Mesh/BackgroundMesh.cpp | 6 +- Mesh/meshGFaceLloyd.cpp | 2415 ++++++++++++++++++++++------------ Mesh/meshGFaceLloyd.h | 275 +++- Numeric/DivideAndConquer.cpp | 253 +++- Numeric/DivideAndConquer.h | 66 +- Plugin/Distance.cpp | 1 - Plugin/Distance.h | 1 + 8 files changed, 2035 insertions(+), 985 deletions(-) diff --git a/Geo/GFace.h b/Geo/GFace.h index d2e6895662..bea0547df0 100644 --- a/Geo/GFace.h +++ b/Geo/GFace.h @@ -67,12 +67,13 @@ class GFace : public GEntity // layer meshes or when using Lloyd-like smoothing algorithms those // vertices are classifed on this GFace, their type is MFaceVertex. // After mesh generation, those are moved to the mesh_vertices array - std::vector<MVertex*> additionalVertices; public: GFace(GModel *model, int tag); virtual ~GFace(); + std::vector<MVertex*> additionalVertices; + // delete mesh data virtual void deleteMesh(); diff --git a/Mesh/BackgroundMesh.cpp b/Mesh/BackgroundMesh.cpp index d0984191f8..e6188996b8 100644 --- a/Mesh/BackgroundMesh.cpp +++ b/Mesh/BackgroundMesh.cpp @@ -652,10 +652,10 @@ double backgroundMesh::operator() (double u, double v, double w) const double uv[3] = {u, v, w}; double uv2[3]; // return 1.0; - MElement *e = _octree->find(u, v, w); + MElement *e = _octree->find(u, v, w, 2, true); if (!e) { Msg::Error("cannot find %g %g", u, v); - return 1.0; + return -1000.0; } e->xyz2uvw(uv, uv2); std::map<MVertex*,double>::const_iterator itv1 = _sizes.find(e->getVertex(0)); @@ -669,7 +669,7 @@ double backgroundMesh::getAngle (double u, double v, double w) const double uv[3] = {u, v, w}; double uv2[3]; // return 1.0; - MElement *e = _octree->find(u, v, w); + MElement *e = _octree->find(u, v, w, 2, true); if (!e) { Msg::Error("cannot find %g %g", u, v); return 0.0; diff --git a/Mesh/meshGFaceLloyd.cpp b/Mesh/meshGFaceLloyd.cpp index e757a73ff0..7dde29512e 100644 --- a/Mesh/meshGFaceLloyd.cpp +++ b/Mesh/meshGFaceLloyd.cpp @@ -1,9 +1,4 @@ #include <set> -#include <fstream> - -#include "GmshConfig.h" -#if defined(HAVE_BFGS) - #include "meshGFaceLloyd.h" #include "DivideAndConquer.h" #include "GFace.h" @@ -12,85 +7,167 @@ #include "MTriangle.h" #include "Context.h" #include "meshGFace.h" -#include "BackgroundMesh.h" +#include "BackgroundMesh.h" +#include <fstream> +#include "ap.h" +#include "alglibinternal.h" +#include "alglibmisc.h" +#include "linalg.h" +#include "optimization.h" +#include "polynomialBasis.h" +#include "MElementOctree.h" + /****************fonction callback****************/ /*************************************************/ -class gradientCallback { - DocRecord *_doc; - int _p; - GFace *_face; - int _dimension; - std::vector<SVector3> _gradients, _areaCentroids; - std::vector<double> _energies, _areas; - - public : - gradientCallback(DocRecord *doc, GFace *face, int dimension, int p){ - _doc = doc; - _face = face; - _dimension = dimension; - _p = p; - _gradients.resize(doc->numPoints); - _areaCentroids.resize(doc->numPoints); - _energies.resize(doc->numPoints); - _areas.resize(doc->numPoints); + +void callback(const alglib::real_1d_array& x,double& func,alglib::real_1d_array& grad,void* ptr){ + int i; + int p; + int num; + int index; + int dimension; + int identificator; + int iteration; + int max; + bool error1; + bool error2; + bool error3; + bool inside; + bool conformity; + double energy; + double start; + double u; + double v; + SPoint2 val; + GFace* gf; + DocRecord* pointer; + wrapper* w; + MElementOctree* octree; + lpcvt obj; + std::vector<SVector3> gradients; + + w = static_cast<wrapper*>(ptr); + p = w->get_p(); + dimension = w->get_dimension(); + gf = w->get_face(); + iteration = w->get_iteration(); + max = w->get_max(); + start = w->get_start(); + pointer = w->get_triangulator(); + octree = w->get_octree(); + num = pointer->numPoints; + gradients.resize(num); + error1 = 0; + error2 = 0; + error3 = 0; + + index = 0; + for(i=0;i<num;i++){ + if(obj.interior(*pointer,gf,i)){ + u = x[index]; + v = x[index + dimension/2]; + inside = domain_search(octree,gf,u,v); + if(!inside) error1 = 1; + pointer->points[i].where.h = u; + pointer->points[i].where.v = v; + pointer->points[i].identificator = index; + index++; + } } - void compute(const alglib::real_1d_array& x,double& func,alglib::real_1d_array& grad) - { - int index = 0; - for (int i = 0; i < _doc->numPoints; ++i) { - PointRecord &pt = _doc->points[i]; - MVertex *v = (MVertex*) pt.data; - if(v->onWhat() == _face && ! _doc->onHull(i)){ - _doc->points[i].where.h = x[index]; - _doc->points[i].where.v = x[index + _dimension/2]; - _doc->points[i].identificator = index; - index++; - } - } - _doc->Voronoi(); - lloydAlgorithm lloyd; - lloyd.eval(*_doc, _face, _gradients, _energies, _areaCentroids, _areas, _p); - func = lloyd.total_energy(_energies); - printf("%f\n",1E18*func); - - for(int i = 0; i < _doc->numPoints; ++i){ - PointRecord &pt = _doc->points[i]; - MVertex *v = (MVertex*)pt.data; - if(v->onWhat() == _face && !_doc->onHull(i)){ - int identificator = _doc->points[i].identificator; - grad[identificator] = _gradients[i].x(); - grad[identificator + _dimension/2] = _gradients[i].y(); - } - } + if(iteration>=max){ + error2 = 1; + } + + if(!error1 && !error2){ + pointer->Voronoi(); + pointer->build_edges(); + conformity = pointer->delaunay_conformity(gf); + if(!conformity) error3 = 1; + pointer->clear_edges(); + if(!error3){ + val = obj.seed(*pointer,gf); + pointer->concave(val.x(),val.y(),gf); + obj.compute_metrics(*pointer); + obj.clip_cells(*pointer,gf); + obj.swap(); + obj.get_gauss(); + obj.eval(*pointer,gradients,energy,p); + func = energy; + } + } + + if(error1 || error2 || error3){ + energy = 1000000000.0; + for(i=0;i<num;i++){ + gradients[i] = SVector3(0.0,0.0,0.0); + } + func = energy; } - static void Callback(const alglib::real_1d_array& x,double& func,alglib::real_1d_array& grad, void* ptr) - { - gradientCallback *cb = static_cast<gradientCallback *> (ptr); - cb->compute(x, func, grad); + if(error1){ + printf("Vertices outside domain.\n"); + } + + if(error2){ + printf("Oscillations.\n"); + } + + if(error3){ + printf("Boundary intersection.\n"); + } + + if(start>0.0){ + printf("%d %.3f\n",iteration,100.0*(start-energy)/start); } -}; + else if(!error1 && !error2 && !error3){ + w->set_start(energy); + } + w->set_iteration(iteration+1); + + for(i=0;i<num;i++){ + if(obj.interior(*pointer,gf,i)){ + identificator = pointer->points[i].identificator; + grad[identificator] = gradients[i].x(); + grad[identificator + dimension/2] = gradients[i].y(); + } + } +} + +bool domain_search(MElementOctree* octree,GFace* gf,double x,double y){ + GPoint gp; + MElement* element; + + gp = gf->point(x,y); + element = (MElement*)octree->find(gp.x(),gp.y(),gp.z(),2,true); + if(element!=NULL) return 1; + else return 0; +} -/****************fonctions principales****************/ -/*****************************************************/ +/****************class lloydAlgorithm****************/ void lloydAlgorithm::operator () (GFace *gf) { std::set<MVertex*> all; + // get all the points of the face ... for (unsigned int i = 0; i < gf->getNumMeshElements(); i++){ MElement *e = gf->getMeshElement(i); for (int j = 0;j<e->getNumVertices(); j++){ MVertex *v = e->getVertex(j); - all.insert(v); + //if (v->onWhat()->dim() < 2){ + all.insert(v); + //} } } + backgroundMesh::set(gf); + + // Create a triangulator DocRecord triangulator(all.size()); Range<double> du = gf->parBounds(0) ; @@ -99,6 +176,9 @@ void lloydAlgorithm::operator () (GFace *gf) const double LC2D = sqrt((du.high()-du.low())*(du.high()-du.low()) + (dv.high()-dv.low())*(dv.high()-dv.low())); + //printf("Lloyd on face %d %d elements %d nodes LC %g\n", gf->tag(), + // gf->getNumMeshElements(), (int)all.size(), LC2D); + int i = 0; for (std::set<MVertex*>::iterator it = all.begin(); it != all.end(); ++it){ SPoint2 p; @@ -137,64 +217,130 @@ void lloydAlgorithm::operator () (GFace *gf) } triangulator.remove_all(); - /*triangulator.Voronoi(); + triangulator.Voronoi(); double delta; - delta = 0.2; + delta = 0.01; for(int i=0;i<triangulator.numPoints;i++){ PointRecord& pt = triangulator.points[i]; MVertex* v = (MVertex*)pt.data; if(v->onWhat()==gf && !triangulator.onHull(i)){ - triangulator.points[i].where.h = delta + (1.0-2.0*delta)*((double)rand()/(double)RAND_MAX); - triangulator.points[i].where.v = delta + (1.0-2.0*delta)*((double)rand()/(double)RAND_MAX); + //triangulator.points[i].where.h = delta + (1.0-2.0*delta)*((double)rand()/(double)RAND_MAX); + //triangulator.points[i].where.v = delta + (1.0-2.0*delta)*((double)rand()/(double)RAND_MAX); } - }*/ + } - int exponent = 8; + int index1 = -1; + int index2 = -1; + int index3 = -1; + int index4 = -1; + int index5 = -1; + int index6 = -1; + int index7 = -1; + int index8 = -1; + for(int i=0;i<triangulator.numPoints;i++){ + PointRecord& pt = triangulator.points[i]; + MVertex* v = (MVertex*)pt.data; + if(v->onWhat()==gf && !triangulator.onHull(i)){ + if(index1==-1) index1 = i; + else if(index2==-1) index2 = i; + else if(index3==-1) index3 = i; + else if(index4==-1) index4 = i; + else if(index5==-1) index5 = i; + else if(index6==-1) index6 = i; + else if(index7==-1) index7 = i; + else if(index8==-1) index8 = i; + + } + } + /*triangulator.points[index1].where.h = 0.01; + triangulator.points[index1].where.v = 0.01; + triangulator.points[index2].where.h = 0.01; + triangulator.points[index2].where.v = 0.99; + triangulator.points[index3].where.h = 0.99; + triangulator.points[index3].where.v = 0.01; + triangulator.points[index4].where.h = 0.99; + triangulator.points[index4].where.v = 0.99;*/ + /*triangulator.points[index5].where.h = 0.500; + triangulator.points[index5].where.v = 0.002; + triangulator.points[index6].where.h = 0.510; + triangulator.points[index6].where.v = 0.001; + triangulator.points[index7].where.h = 0.520; + triangulator.points[index7].where.v = 0.003; + triangulator.points[index8].where.h = 0.530; + triangulator.points[index8].where.v = 0.004;*/ + // compute the Voronoi diagram triangulator.Voronoi(); + //printf("hullSize = %d\n",triangulator.hullSize()); triangulator.makePosView("LloydInit.pos"); - + //triangulator.printMedialAxis("medialAxis.pos"); + + int exponent; int num_interior; - std::vector<double> initial_conditions(2*triangulator.numPoints); + double epsg; + double epsf; + double epsx; + lpcvt obj; + double initial_conditions[2*triangulator.numPoints]; + alglib::ae_int_t maxits; + alglib::minlbfgsstate state; + alglib::minlbfgsreport rep; + alglib::real_1d_array x; + wrapper w; + MElementOctree* octree; + + exponent = NORM; + epsg = 0; + epsf = 0; + epsx = 0; + maxits = ITER_MAX; + num_interior = 0; for(int i=0;i<triangulator.numPoints;i++){ - PointRecord& pt = triangulator.points[i]; - MVertex* v = (MVertex*)pt.data; - if(v->onWhat()==gf && !triangulator.onHull(i)){ + if(obj.interior(triangulator,gf,i)){ num_interior++; } } + index = 0; for(int i=0;i<triangulator.numPoints;i++){ - PointRecord& pt = triangulator.points[i]; - MVertex* v = (MVertex*)pt.data; - if(v->onWhat()==gf && !triangulator.onHull(i)){ + if(obj.interior(triangulator,gf,i)){ initial_conditions[index] = triangulator.points[i].where.h; initial_conditions[index+num_interior] = triangulator.points[i].where.v; index++; } } - alglib::real_1d_array x; - x.setcontent(2*num_interior,&initial_conditions[0]); - - double epsg = 0; - double epsf = 0; - double epsx = 1e-4; - alglib::ae_int_t maxits = 0; - alglib::minlbfgsstate state; - alglib::minlbfgsreport rep; - minlbfgscreate(2*num_interior, 4, x, state); - minlbfgssetcond(state, epsg, epsf, epsx, maxits); - gradientCallback cb(&triangulator, gf, 2 * num_interior, exponent); - minlbfgsoptimize(state, gradientCallback::Callback, NULL, &cb); - minlbfgsresults(state, x, rep); + x.setcontent(2*num_interior,initial_conditions); + + octree = new MElementOctree(gf->model()); + + w.set_p(exponent); + w.set_dimension(2*num_interior); + w.set_face(gf); + w.set_max(2*ITER_MAX); + w.set_triangulator(&triangulator); + w.set_octree(octree); + + minlbfgscreate(2*num_interior,4,x,state); + minlbfgssetcond(state,epsg,epsf,epsx,maxits); + minlbfgsoptimize(state,callback,NULL,&w); + minlbfgsresults(state,x,rep); + + delete octree; + + /*lpcvt obj2; + SPoint2 val = obj2.seed(triangulator,gf); + triangulator.concave(val.x(),val.y(),gf); + obj2.compute_metrics(triangulator); + obj2.clip_cells(triangulator,gf); + obj2.swap(); + obj2.get_gauss(); + obj2.write(triangulator,gf,6);*/ index = 0; for(i=0;i<triangulator.numPoints;i++){ - PointRecord &pt = triangulator.points[i]; - MVertex *v = (MVertex*)pt.data; - if(v->onWhat()==gf && !triangulator.onHull(i)){ + if(obj.interior(triangulator,gf,i)){ triangulator.points[i].where.h = x[index]; triangulator.points[i].where.v = x[index + num_interior]; index++; @@ -202,37 +348,55 @@ void lloydAlgorithm::operator () (GFace *gf) } triangulator.Voronoi(); - test = 0; + //lpcvt obj; + //SPoint2 val = obj.seed(triangulator,gf); + //triangulator.concave(val.x(),val.y(),gf); + //obj.clip_cells(triangulator,gf); + //obj.print_voronoi1(); + //obj.print_voronoi2(); + //obj.print_delaunay(triangulator); + //test = obj.total_area(); + //obj.swap(); + //obj.get_gauss(); + //obj.write(triangulator,gf,6); + + // now create the vertices std::vector<MVertex*> mesh_vertices; for (int i=0; i<triangulator.numPoints;i++){ + // get the ith vertex PointRecord &pt = triangulator.points[i]; MVertex *v = (MVertex*)pt.data; if (v->onWhat() == gf && !triangulator.onHull(i)){ GPoint gp = gf->point (pt.where.h,pt.where.v); MFaceVertex *v = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v()); mesh_vertices.push_back(v); - test++; } } + // destroy the mesh deMeshGFace killer; killer(gf); + // put all additional vertices in the list of + // vertices gf->additionalVertices = mesh_vertices; + // remesh the face with all those vertices in Msg::Info("Lloyd remeshing of face %d ", gf->tag()); meshGFace mesher; mesher(gf); + // assign those vertices to the face internal vertices gf->mesh_vertices.insert(gf->mesh_vertices.begin(), gf->additionalVertices.begin(), gf->additionalVertices.end()); + // clear the list of additional vertices gf->additionalVertices.clear(); } -double lloydAlgorithm::optimize(int max,int flag){ +void lloydAlgorithm::optimize(int itermax,int norm){ GFace*face; GModel*model = GModel::current(); GModel::fiter iterator; - lloydAlgorithm lloyd(max,flag); + lloydAlgorithm lloyd(itermax,norm); for(iterator = model->firstFace();iterator != model->lastFace();iterator++) { face = *iterator; @@ -241,909 +405,1520 @@ double lloydAlgorithm::optimize(int max,int flag){ recombineIntoQuads(face,1,1); } } - return lloyd.test; } -/****************Calcul du gradient****************/ -/**************************************************/ +/****************class lpcvt****************/ -void lloydAlgorithm::eval(DocRecord& triangulator,GFace* gf,std::vector<SVector3>& gradients,std::vector<double>& energies,std::vector<SVector3>& area_centroids,std::vector<double>& areas,int p) -{ - int i; - - for(i=0;i<triangulator.numPoints;i++){ - gradients[i] = SVector3(0.0,0.0,0.0); - energies[i] = 0.0; - area_centroids[i] = SVector3(0.0,0.0,0.0); - areas[i] = 0.0; +lpcvt::lpcvt(){} + +lpcvt::~lpcvt(){} + +double lpcvt::angle(SPoint2 p1,SPoint2 p2,SPoint2 p3){ + double x1,x2; + double y1,y2; + double product; + double norm1,norm2; + double angle; + x1 = p2.x() - p1.x(); + y1 = p2.y() - p1.y(); + x2 = p3.x() - p1.x(); + y2 = p3.y() - p1.y(); + norm1 = sqrt(x1*x1 + y1*y1); + norm2 = sqrt(x2*x2 + y2*y2); + product = x1*x2 + y1*y2; + angle = product/(norm1*norm2); + angle = 180.0*myacos(angle)/M_PI; + return angle; +} + +SVector3 lpcvt::normal(SPoint2 p1,SPoint2 p2){ + double x; + double y; + SVector3 val; + x = p2.x() - p1.x(); + y = p2.y() - p1.y(); + val = SVector3(-y,x,0.0); + return val; +} + +SPoint2 lpcvt::mid(SPoint2 p1,SPoint2 p2){ + double x; + double y; + x = 0.5*(p1.x() + p2.x()); + y = 0.5*(p1.y() + p2.y()); + return SPoint2(x,y); +} + +bool lpcvt::same_side(SPoint2 p1,SPoint2 p2,SPoint2 p3,SPoint2 p4){ + double x1,y1; + double x2,y2; + double x3,y3; + double product1; + double product2; + x1 = p2.x()-p1.x(); + y1 = p2.y()-p1.y(); + x2 = p3.x()-p1.x(); + y2 = p3.y()-p1.y(); + x3 = p4.x()-p1.x(); + y3 = p4.y()-p1.y(); + product1 = x2*y1 - x1*y2; + product2 = x3*y1 - x1*y3; + if(product1>0.0 && product2>0.0){ + return 1; } - - for(i=0;i<triangulator.numPoints;i++){ - PointRecord &pt = triangulator.points[i]; - MVertex *v = (MVertex*)pt.data; - if(v->onWhat()==gf && !triangulator.onHull(i)){ - bool is_inside1; - bool is_inside2; - bool flag; - int num = triangulator._adjacencies[i].t_length; - for(int j=0;j<num;j++){ - int index3 = triangulator._adjacencies[i].t[j]; - int index2 = triangulator._adjacencies[i].t[(j+1)%num]; - int index1 = triangulator._adjacencies[i].t[(j+2)%num]; - double _x0[2] = {triangulator.points[i].where.h,triangulator.points[i].where.v}; - double _x1[2] = {triangulator.points[index1].where.h,triangulator.points[index1].where.v}; - double _x2[2] = {triangulator.points[index2].where.h,triangulator.points[index2].where.v}; - double _x3[2] = {triangulator.points[index3].where.h,triangulator.points[index3].where.v}; - SPoint2 x0(_x0[0],_x0[1]); - SPoint2 x1(_x1[0],_x1[1]); - SPoint2 x2(_x2[0],_x2[1]); - SPoint2 x3(_x3[0],_x3[1]); - double CC1[2]; - double CC2[2]; - circumCenterXY(_x0,_x1,_x2,CC1); - circumCenterXY(_x0,_x2,_x3,CC2); - SPoint2 C1(CC1[0],CC1[1]); - SPoint2 C2(CC2[0],CC2[1]); - is_inside1 = inside_domain(C1.x(),C1.y()); - is_inside2 = inside_domain(C2.x(),C2.y()); - if(is_inside1 && is_inside2){ - energies[i] = energies[i] + F(x0,C1,C2,p); - gradients[i] = gradients[i] + simple(x0,C1,C2,p); - area_centroids[i] = area_centroids[i] + area_centroid(x0,C1,C2); - areas[i] = areas[i] + triangle_area(x0,C1,C2); - SVector3 grad1 = dF_dC1(x0,C1,C2,p); - SVector3 grad2 = dF_dC2(x0,C1,C2,p); - gradients[i] = gradients[i] + inner_dFdx0(grad1,C1,x0,x1,x2); - gradients[index1] = gradients[index1] + inner_dFdx0(grad1,C1,x1,x0,x2); - gradients[index2] = gradients[index2] + inner_dFdx0(grad1,C1,x2,x0,x1); - gradients[i] = gradients[i] + inner_dFdx0(grad2,C2,x0,x2,x3); - gradients[index2] = gradients[index2] + inner_dFdx0(grad2,C2,x2,x0,x3); - gradients[index3] = gradients[index3] + inner_dFdx0(grad2,C2,x3,x0,x2); - } - else if(is_inside1){ - SPoint2 first; - SPoint2 second; - SVector3 vecA; - SVector3 vecB; - first = boundary_intersection(C1,C2,flag,vecA); - second = boundary_intersection(x0,C2,flag,vecB); - energies[i] = energies[i] + F(x0,C1,first,p); - energies[i] = energies[i] + F(x0,first,second,p); - gradients[i] = gradients[i] + simple(x0,C1,first,p); - gradients[i] = gradients[i] + simple(x0,first,second,p); - area_centroids[i] = area_centroids[i] + area_centroid(x0,C1,first); - area_centroids[i] = area_centroids[i] + area_centroid(x0,first,second); - areas[i] = areas[i] + triangle_area(x0,C1,first); - areas[i] = areas[i] + triangle_area(x0,first,second); - SVector3 grad1 = dF_dC1(x0,C1,first,p); - SVector3 grad2 = dF_dC2(x0,C1,first,p); - SVector3 grad3 = dF_dC1(x0,first,second,p); - gradients[i] = gradients[i] + inner_dFdx0(grad1,C1,x0,x1,x2); - gradients[index1] = gradients[index1] + inner_dFdx0(grad1,C1,x1,x0,x2); - gradients[index2] = gradients[index2] + inner_dFdx0(grad1,C1,x2,x0,x1); - gradients[i] = gradients[i] + boundary_dFdx0(grad2,first,x0,x2,vecA); - gradients[index2] = gradients[index2] + boundary_dFdx0(grad2,first,x2,x0,vecA); - gradients[i] = gradients[i] + boundary_dFdx0(grad3,first,x0,x2,vecA); - gradients[index2] = gradients[index2] + boundary_dFdx0(grad3,first,x2,x0,vecA); - } - else if(is_inside2){ - SPoint2 first; - SPoint2 second; - SVector3 vecA; - SVector3 vecB; - first = boundary_intersection(C1,C2,flag,vecA); - second = boundary_intersection(x0,C1,flag,vecB); - energies[i] = energies[i] + F(x0,second,first,p); - energies[i] = energies[i] + F(x0,first,C2,p); - gradients[i] = gradients[i] + simple(x0,second,first,p); - gradients[i] = gradients[i] + simple(x0,first,C2,p); - area_centroids[i] = area_centroids[i] + area_centroid(x0,second,first); - area_centroids[i] = area_centroids[i] + area_centroid(x0,first,C2); - areas[i] = areas[i] + triangle_area(x0,second,first); - areas[i] = areas[i] + triangle_area(x0,first,C2); - SVector3 grad1 = dF_dC2(x0,second,first,p); - SVector3 grad2 = dF_dC1(x0,first,C2,p); - SVector3 grad3 = dF_dC2(x0,first,C2,p); - gradients[i] = gradients[i] + inner_dFdx0(grad3,C2,x0,x2,x3); - gradients[index2] = gradients[index2] + inner_dFdx0(grad3,C2,x2,x0,x3); - gradients[index3] = gradients[index3] + inner_dFdx0(grad3,C2,x3,x0,x2); - gradients[i] = gradients[i] + boundary_dFdx0(grad2,first,x0,x2,vecA); - gradients[index2] = gradients[index2] + boundary_dFdx0(grad2,first,x2,x0,vecA); - gradients[i] = gradients[i] + boundary_dFdx0(grad1,first,x0,x2,vecA); - gradients[index2] = gradients[index2] + boundary_dFdx0(grad1,first,x2,x0,vecA); - } - else{ - SPoint2 first; - SPoint2 second; - SPoint2 third; - SPoint2 fourth; - SPoint2 median; - SPoint2 any; - SVector3 vecA; - SVector3 vecB; - SVector3 vec; - any = boundary_intersection(C1,C2,flag,vec); - if(flag){ - median = mid(x0,x2); - first = boundary_intersection(median,C1,flag,vecA); - second = boundary_intersection(median,C2,flag,vecB); - third = boundary_intersection(x0,C1,flag,vec); - fourth = boundary_intersection(x0,C2,flag,vec); - energies[i] = energies[i] + F(x0,first,second,p); - energies[i] = energies[i] + F(x0,third,first,p); - energies[i] = energies[i] + F(x0,second,fourth,p); - gradients[i] = gradients[i] + simple(x0,first,second,p); - gradients[i] = gradients[i] + simple(x0,third,first,p); - gradients[i] = gradients[i] + simple(x0,second,fourth,p); - area_centroids[i] = area_centroids[i] + area_centroid(x0,first,second); - area_centroids[i] = area_centroids[i] + area_centroid(x0,third,first); - area_centroids[i] = area_centroids[i] + area_centroid(x0,second,fourth); - areas[i] = areas[i] + triangle_area(x0,first,second); - areas[i] = areas[i] + triangle_area(x0,third,first); - areas[i] = areas[i] + triangle_area(x0,second,fourth); - SVector3 grad1 = dF_dC1(x0,first,second,p); - SVector3 grad2 = dF_dC2(x0,first,second,p); - SVector3 grad3 = dF_dC2(x0,third,first,p); - SVector3 grad4 = dF_dC1(x0,second,fourth,p); - gradients[i] = gradients[i] + boundary_dFdx0(grad1,first,x0,x2,vecA); - gradients[index2] = gradients[index2] + boundary_dFdx0(grad1,first,x2,x0,vecA); - gradients[i] = gradients[i] + boundary_dFdx0(grad2,second,x0,x2,vecB); - gradients[index2] = gradients[index2] + boundary_dFdx0(grad2,second,x2,x0,vecB); - gradients[i] = gradients[i] + boundary_dFdx0(grad3,first,x0,x2,vecA); - gradients[index2] = gradients[index2] + boundary_dFdx0(grad3,first,x2,x0,vecA); - gradients[i] = gradients[i] + boundary_dFdx0(grad4,second,x0,x2,vecB); - gradients[index2] = gradients[index2] + boundary_dFdx0(grad4,second,x2,x0,vecB); - } - else{ - first = boundary_intersection(x0,C1,flag,vec); - second = boundary_intersection(x0,C2,flag,vec); - energies[i] = energies[i] + F(x0,first,second,p); - gradients[i] = gradients[i] + simple(x0,first,second,p); - area_centroids[i] = area_centroids[i] + area_centroid(x0,first,second); - areas[i] = areas[i] + triangle_area(x0,first,second); - } - } - } - } - else { - double e = 0.00000001; - bool ok_triangle1; - bool ok_triangle2; - bool is_inside1; - bool is_inside2; - bool is_inside; - bool flag; - int num = triangulator._adjacencies[i].t_length; - for(int j=0;j<num;j++){ - int index3 = triangulator._adjacencies[i].t[j]; - int index2 = triangulator._adjacencies[i].t[(j+1)%num]; - int index1 = triangulator._adjacencies[i].t[(j+2)%num]; - if(index1!=index2 && index1!=index3 && index2!=index3 && i!=index1 && i!=index2 && i!=index3){ - double _x0[2] = {triangulator.points[i].where.h,triangulator.points[i].where.v}; - double _x1[2] = {triangulator.points[index1].where.h,triangulator.points[index1].where.v}; - double _x2[2] = {triangulator.points[index2].where.h,triangulator.points[index2].where.v}; - double _x3[2] = {triangulator.points[index3].where.h,triangulator.points[index3].where.v}; - SPoint2 x0(_x0[0],_x0[1]); - SPoint2 x1(_x1[0],_x1[1]); - SPoint2 x2(_x2[0],_x2[1]); - SPoint2 x3(_x3[0],_x3[1]); - ok_triangle1 = adjacent(triangulator,index1,index2) && triangle_area(x0,x1,x2)>e; - ok_triangle2 = adjacent(triangulator,index2,index3) && triangle_area(x0,x2,x3)>e; - if(ok_triangle1 && ok_triangle2){ - double CC1[2]; - double CC2[2]; - circumCenterXY(_x0,_x1,_x2,CC1); - circumCenterXY(_x0,_x2,_x3,CC2); - SPoint2 C1(CC1[0],CC1[1]); - SPoint2 C2(CC2[0],CC2[1]); - is_inside1 = inside_domain(C1.x(),C1.y()); - is_inside2 = inside_domain(C2.x(),C2.y()); - if(is_inside1 && is_inside2){ - energies[i] = energies[i] + F(x0,C1,C2,p); - SVector3 grad1 = dF_dC1(x0,C1,C2,p); - SVector3 grad2 = dF_dC2(x0,C1,C2,p); - gradients[index1] = gradients[index1] + inner_dFdx0(grad1,C1,x1,x0,x2); - gradients[index2] = gradients[index2] + inner_dFdx0(grad1,C1,x2,x0,x1); - gradients[index2] = gradients[index2] + inner_dFdx0(grad2,C2,x2,x0,x3); - gradients[index3] = gradients[index3] + inner_dFdx0(grad2,C2,x3,x0,x2); - } - else if(is_inside1){ - SPoint2 val; - SVector3 vec; - val = boundary_intersection(C1,C2,flag,vec); - energies[i] = energies[i] + F(x0,C1,val,p); - SVector3 grad1 = dF_dC1(x0,C1,val,p); - SVector3 grad2 = dF_dC2(x0,C1,val,p); - gradients[index1] = gradients[index1] + inner_dFdx0(grad1,C1,x1,x0,x2); - gradients[index2] = gradients[index2] + inner_dFdx0(grad1,C1,x2,x0,x1); - gradients[index2] = gradients[index2] + boundary_dFdx0(grad2,val,x2,x0,vec); - } - else if(is_inside2){ - SPoint2 val; - SVector3 vec; - val = boundary_intersection(C1,C2,flag,vec); - energies[i] = energies[i] + F(x0,val,C2,p); - SVector3 grad1 = dF_dC1(x0,val,C2,p); - SVector3 grad2 = dF_dC2(x0,val,C2,p); - gradients[index2] = gradients[index2] + inner_dFdx0(grad2,C2,x2,x0,x3); - gradients[index3] = gradients[index3] + inner_dFdx0(grad2,C2,x3,x0,x2); - gradients[index2] = gradients[index2] + boundary_dFdx0(grad1,val,x2,x0,vec); - } - else{ - SPoint2 first; - SPoint2 second; - SPoint2 median; - SPoint2 any; - SVector3 vecA; - SVector3 vecB; - SVector3 vec; - any = boundary_intersection(C1,C2,flag,vec); - if(flag){ - median = mid(x0,x2); - first = boundary_intersection(median,C1,flag,vecA); - second = boundary_intersection(median,C2,flag,vecB); - energies[i] = energies[i] + F(x0,first,second,p); - SVector3 grad1 = dF_dC1(x0,first,second,p); - SVector3 grad2 = dF_dC2(x0,first,second,p); - gradients[index2] = gradients[index2] + boundary_dFdx0(grad1,first,x2,x0,vecA); - gradients[index2] = gradients[index2] + boundary_dFdx0(grad2,second,x2,x0,vecB); - } - } - } - else if(ok_triangle1){ - double CC[2]; - circumCenterXY(_x0,_x1,_x2,CC); - SPoint2 C(CC[0],CC[1]); - is_inside = inside_domain(C.x(),C.y()); - if(is_inside){ - SPoint2 val; - val = mid(x0,x2); - energies[i] = energies[i] + F(x0,C,val,p); - SVector3 grad1 = dF_dC1(x0,C,val,p); - gradients[index1] = gradients[index1] + inner_dFdx0(grad1,C,x1,x0,x2); - } - } - else if(ok_triangle2){ - double CC[2]; - circumCenterXY(_x0,_x2,_x3,CC); - SPoint2 C(CC[0],CC[1]); - is_inside = inside_domain(C.x(),C.y()); - if(is_inside){ - SPoint2 val; - val = mid(x0,x2); - energies[i] = energies[i] + F(x0,val,C,p); - SVector3 grad1 = dF_dC2(x0,val,C,p); - gradients[index3] = gradients[index3] + inner_dFdx0(grad1,C,x3,x0,x2); - } - } - } - } - } + else if(product1<0.0 && product2<0.0){ + return 1; } + else return 0; } -double lloydAlgorithm::total_energy(std::vector<double> energies){ - int i; - double total; - total = 0.0; - for(i=0;i<energies.size();i++){ - total = total + energies[i]; +bool lpcvt::interior(DocRecord& triangulator,GFace* gf,int index){ + PointRecord& temp = triangulator.points[index]; + MVertex* vertex = (MVertex*)temp.data; + if(vertex->onWhat()==gf && !triangulator.onHull(index)){ + return 1; } - return total; + else return 0; } -SVector3 lloydAlgorithm::numerical(DocRecord& triangulator,GFace* gf,int index,int p){ - double x_original; - double y_original; - double energy_right; - double energy_left; - double energy_up; - double energy_down; - double comp_x; - double comp_y; - double e; - std::vector<double> energies(triangulator.numPoints); - std::vector<SVector3> gradients(triangulator.numPoints); - std::vector<SVector3> area_centroids(triangulator.numPoints); - std::vector<double> areas(triangulator.numPoints); - e = 0.00001; - x_original = triangulator.points[index].where.h; - y_original = triangulator.points[index].where.v; - - triangulator.points[index].where.h = x_original + e; - triangulator.points[index].where.v = y_original; - eval(triangulator,gf,gradients,energies,area_centroids,areas,p); - energy_right = total_energy(energies); - - triangulator.points[index].where.h = x_original - e; - triangulator.points[index].where.v = y_original; - eval(triangulator,gf,gradients,energies,area_centroids,areas,p); - energy_left = total_energy(energies); - - triangulator.points[index].where.h = x_original; - triangulator.points[index].where.v = y_original + e; - eval(triangulator,gf,gradients,energies,area_centroids,areas,p); - energy_up = total_energy(energies); - - triangulator.points[index].where.h = x_original; - triangulator.points[index].where.v = y_original - e; - eval(triangulator,gf,gradients,energies,area_centroids,areas,p); - energy_down = total_energy(energies); - - comp_x = (energy_right - energy_left)/(2*e); - comp_y = (energy_up - energy_down)/(2*e); - - triangulator.points[index].where.h = x_original; - triangulator.points[index].where.v = y_original; - - return SVector3(comp_x,comp_y,0.0); +bool lpcvt::interior(DocRecord& triangulator,segment s1,segment s2,double angle,SPoint2 p){ + SPoint2 p1,p2,p3,p4; + SPoint2 reference1,reference2; + bool condition1,condition2; + p1 = convert(triangulator,s1.get_index1()); + p2 = convert(triangulator,s1.get_index2()); + p3 = convert(triangulator,s2.get_index1()); + p4 = convert(triangulator,s2.get_index2()); + reference1 = convert(triangulator,s1.get_reference()); + reference2 = convert(triangulator,s2.get_reference()); + condition1 = same_side(p1,p2,reference1,p); + condition2 = same_side(p3,p4,reference2,p); + if(angle>=180.0){ + if(condition1 || condition2) return 1; + else return 0; + } + else{ + if(condition1 && condition2) return 1; + else return 0; + } } -void lloydAlgorithm::write(DocRecord& triangulator,GFace* gf,int p){ +bool lpcvt::invisible(DocRecord& triangulator,GFace* gf,int index){ int i; - SVector3 grad1; - SVector3 grad2; - SVector3 ecart; - std::vector<SVector3> gradients(triangulator.numPoints); - std::vector<double> energies(triangulator.numPoints); - std::vector<SVector3> area_centroids(triangulator.numPoints); - std::vector<double> areas(triangulator.numPoints); - - eval(triangulator,gf,gradients,energies,area_centroids,areas,p); - - std::ofstream file("gradient"); - - for(i=0;i<triangulator.numPoints;i++){ - PointRecord& pt = triangulator.points[i]; - MVertex* v = (MVertex*)pt.data; - if(v->onWhat()==gf && !triangulator.onHull(i)){ - grad1 = numerical(triangulator,gf,i,p); - grad2 = gradients[i]; - ecart = grad1-grad2; - file << grad1.x() << " "; - file << grad2.x() << " "; - file << grad1.y() << " "; - file << grad2.y() << " "; - file << 100.0*ecart.norm()/grad1.norm() << " "; - file << "\n"; + int num; + int index2; + num = triangulator._adjacencies[index].t_length; + for(i=0;i<num;i++){ + index2 = triangulator._adjacencies[index].t[i]; + if(interior(triangulator,gf,index2)){ + return 0; } } + return 1; } -void lloydAlgorithm::write2(DocRecord& triangulator,GFace* gf){ - int i; - SPoint2 generator; - SVector3 grad1; - SVector3 grad2; - SVector3 ecart; - std::vector<SVector3> gradients(triangulator.numPoints); - std::vector<double> energies(triangulator.numPoints); - std::vector<SVector3> area_centroids(triangulator.numPoints); - std::vector<double> areas(triangulator.numPoints); - - eval(triangulator,gf,gradients,energies,area_centroids,areas,2); - - std::ofstream file("gradient2"); - - for(i=0;i<triangulator.numPoints;i++){ - PointRecord& pt = triangulator.points[i]; - MVertex* v = (MVertex*)pt.data; - if(v->onWhat()==gf && !triangulator.onHull(i)){ - generator = SPoint2(triangulator.points[i].where.h,triangulator.points[i].where.v); - grad1 = analytical(generator,area_centroids[i],areas[i]); - grad2 = gradients[i]; - ecart = grad1-grad2; - file << grad1.x() << " "; - file << grad2.x() << " "; - file << grad1.y() << " "; - file << grad2.y() << " "; - file << 100.0*ecart.norm()/grad1.norm() << " "; - file << "\n"; - } - } +bool lpcvt::real(DocRecord& triangulator,int index1,int index2,int index3){ + return triangulator.contain(index1,index2,index3); } -SVector3 lloydAlgorithm::analytical(SPoint2 generator,SVector3 area_centroid,double area){ - SVector3 _generator; - SVector3 val; - _generator = SVector3(generator.x(),generator.y(),0.0); - val = 2.0*area*(_generator - (1.0/area)*area_centroid); - return val; +double lpcvt::triangle_area(SPoint2 p1,SPoint2 p2,SPoint2 p3){ + double area; + double x1,y1; + double x2,y2; + x1 = p2.x() - p1.x(); + y1 = p2.y() - p1.y(); + x2 = p3.x() - p1.x(); + y2 = p3.y() - p1.y(); + area = 0.5*fabs(x1*y2 - x2*y1); + return area; } -SVector3 lloydAlgorithm::area_centroid(SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double x; - double y; +bool lpcvt::sliver(SPoint2 p1,SPoint2 p2,SPoint2 p3){ double area; + double e; + e = 0.000000001; area = triangle_area(p1,p2,p3); - x = (1.0/3.0)*(p1.x() + p2.x() + p3.x()); - y = (1.0/3.0)*(p1.y() + p2.y() + p3.y()); - return SVector3(area*x,area*y,0.0); + if(area<e) return 1; + else return 0; +} + +SPoint2 lpcvt::intersection(DocRecord& triangulator,segment s1,segment s2,SPoint2 p1,SPoint2 p2,bool &flag,SVector3& vec,segment& s){ + bool flag1; + bool flag2; + SPoint2 p3; + SPoint2 p4; + SPoint2 p5; + SPoint2 p6; + SPoint2 val1; + SPoint2 val2; + p3 = convert(triangulator,s1.get_index1()); + p4 = convert(triangulator,s1.get_index2()); + p5 = convert(triangulator,s2.get_index1()); + p6 = convert(triangulator,s2.get_index2()); + val1 = intersection(p3,p4,p1,p2,flag1); + val2 = intersection(p5,p6,p1,p2,flag2); + if(flag1){ + flag = 1; + vec = normal(p3,p4); + s = s1; + return val1; + } + else if(flag2){ + flag = 1; + vec = normal(p5,p6); + s = s2; + return val2; + } + else{ + flag = 0; + vec = SVector3(0.0,0.0,0.0); + s = segment(-1,-1,-1); + return SPoint2(0.0,0.0); + } } +SPoint2 lpcvt::intersection(SPoint2 p1,SPoint2 p2,SPoint2 p3,SPoint2 p4,bool& flag){ + double x1,y1; + double x2,y2; + double x3,y3; + double x4,y4; + double ua,ub; + double num_ua; + double num_ub; + double denom; + double e; + x1 = p1.x(); + y1 = p1.y(); + x2 = p2.x(); + y2 = p2.y(); + x3 = p3.x(); + y3 = p3.y(); + x4 = p4.x(); + y4 = p4.y(); + e = 0.000001; + denom = (y4-y3)*(x2-x1) - (x4-x3)*(y2-y1); + if(fabs(denom)<e){ + flag = 0; + return SPoint2(0.0,0.0); + } + num_ua = (x4-x3)*(y1-y3) - (y4-y3)*(x1-x3); + num_ub = (x2-x1)*(y1-y3) - (y2-y1)*(x1-x3); + ua = num_ua/denom; + ub = num_ub/denom; + if(ua<=1.0 && ua>=0.0 && ub<=1.0 && ub>=0.0){ + flag = 1; + return SPoint2(x1+ua*(x2-x1),y1+ua*(y2-y1)); + } + else{ + flag = 0; + return SPoint2(0.0,0.0); + } +} +SPoint2 lpcvt::convert(DocRecord& triangulator,int index){ + SPoint2 p; + double _p[2] = {triangulator.points[index].where.h,triangulator.points[index].where.v}; + p = SPoint2(_p[0],_p[1]); + return p; +} -/****************Fonctions pour le calcul du gradient****************/ -/********************************************************************/ +SPoint2 lpcvt::circumcircle(DocRecord& triangulator,int index1,int index2,int index3){ + double _C[2]; + SPoint2 C; + double _x1[2] = {triangulator.points[index1].where.h,triangulator.points[index1].where.v}; + double _x2[2] = {triangulator.points[index2].where.h,triangulator.points[index2].where.v}; + double _x3[2] = {triangulator.points[index3].where.h,triangulator.points[index3].where.v}; + circumCenterXY(_x1,_x2,_x3,_C); + C = SPoint2(_C[0],_C[1]); + return C; +} -double lloydAlgorithm::F(SPoint2 generator,SPoint2 C1,SPoint2 C2,int p){ +SPoint2 lpcvt::seed(DocRecord& triangulator,GFace* gf){ int i; + int j; int num; - int order; - double x; - double y; - double energy; - SPoint2 point; - fullMatrix<double> pts; - fullMatrix<double> weights; - order = 8; - gaussIntegration::getTriangle(order,pts,weights); - num = pts.size1(); - energy = 0.0; - for(i=0;i<num;i++){ - x = Tx(pts(i,0),pts(i,1),generator,C1,C2); - y = Ty(pts(i,0),pts(i,1),generator,C1,C2); - point = SPoint2(x,y); - energy = energy + weights(i,0)*f(generator,point,p); + int index1; + int index2; + double x,y; + SPoint2 x0,x1,x2; + for(i=0;i<triangulator.numPoints;i++){ + if(interior(triangulator,gf,i)){ + num = triangulator._adjacencies[i].t_length; + for(j=0;j<num;j++){ + index1 = triangulator._adjacencies[i].t[j]; + index2 = triangulator._adjacencies[i].t[(j+1)%num]; + if(interior(triangulator,gf,index1) && interior(triangulator,gf,index2)){ + x0 = convert(triangulator,i); + x1 = convert(triangulator,index1); + x2 = convert(triangulator,index2); + x = (x0.x() + x1.x() + x2.x())/3.0; + y = (x0.y() + x1.y() + x2.y())/3.0; + return SPoint2(x,y); + } + } + } } - energy = J(generator,C1,C2)*energy; - return energy; + return SPoint2(0.0,0.0); } -SVector3 lloydAlgorithm::simple(SPoint2 generator,SPoint2 C1,SPoint2 C2,int p){ +void lpcvt::step1(DocRecord& triangulator,GFace* gf){ int i; + int j; int num; - int order; - double x; - double y; - double comp_x; - double comp_y; - SPoint2 point; - fullMatrix<double> pts; - fullMatrix<double> weights; + int index1,index2,index3; + bool ok_triangle1,ok_triangle2; + SPoint2 x0,x1,x2,x3; + + borders.resize(triangulator.numPoints); + angles.resize(triangulator.numPoints); + for(i=0;i<triangulator.numPoints;i++){ + angles[i] = 0.0; + } + temp.resize(triangulator.numPoints); + + for(i=0;i<triangulator.numPoints;i++){ + if(!interior(triangulator,gf,i) && !invisible(triangulator,gf,i)){ + num = triangulator._adjacencies[i].t_length; + for(j=0;j<num;j++){ + index1 = triangulator._adjacencies[i].t[j]; + index2 = triangulator._adjacencies[i].t[(j+1)%num]; + index3 = triangulator._adjacencies[i].t[(j+2)%num]; + x0 = convert(triangulator,i); + x1 = convert(triangulator,index1); + x2 = convert(triangulator,index2); + x3 = convert(triangulator,index3); + ok_triangle1 = real(triangulator,i,index1,index2) && !sliver(x0,x1,x2); + ok_triangle2 = real(triangulator,i,index2,index3) && !sliver(x0,x2,x3); + if(ok_triangle1 && !ok_triangle2){ + borders[i].add_segment(i,index2,index1); + } + else if(!ok_triangle1 && ok_triangle2){ + borders[i].add_segment(i,index2,index3); + } + + if(ok_triangle1){ + angles[i] = angles[i] + angle(x0,x1,x2); + } + } + } + } +} + +void lpcvt::step2(DocRecord& triangulator,GFace* gf){ + int i; + int j; + int num; + int index1,index2; + SPoint2 C; + voronoi_vertex vertex; + for(i=0;i<triangulator.numPoints;i++){ + if(interior(triangulator,gf,i)){ + num = triangulator._adjacencies[i].t_length; + for(j=0;j<num;j++){ + index1 = triangulator._adjacencies[i].t[j]; + index2 = triangulator._adjacencies[i].t[(j+1)%num]; + C = circumcircle(triangulator,i,index1,index2); + vertex = voronoi_vertex(C); + vertex.set_index1(i); + vertex.set_index2(index1); + vertex.set_index3(index2); + temp[i].add_vertex(vertex); + } + } + } +} + +void lpcvt::step3(DocRecord& triangulator,GFace* gf){ + int i; + int j; + int num; + double angle; + bool ok_triangle1,ok_triangle2; + bool is_inside,is_inside1,is_inside2; + bool flag,flag1,flag2; + SPoint2 x0,x1,x2,x3; + SPoint2 C,C1,C2; + SPoint2 val; + SPoint2 first,second,median,any; + SVector3 vec,vecA,vecB; + segment s,s1,s2,s3,s4; + voronoi_vertex vertex,vertex1,vertex2,vertex3; + for(i=0;i<triangulator.numPoints;i++){ + if(!interior(triangulator,gf,i) && !invisible(triangulator,gf,i)){ + num = triangulator._adjacencies[i].t_length; + s1 = borders[i].get_segment(0); + s2 = borders[i].get_segment(1); + angle = angles[i]; + for(j=0;j<num;j++){ + int index1 = triangulator._adjacencies[i].t[j]; + int index2 = triangulator._adjacencies[i].t[(j+1)%num]; + int index3 = triangulator._adjacencies[i].t[(j+2)%num]; + x0 = convert(triangulator,i); + x1 = convert(triangulator,index1); + x2 = convert(triangulator,index2); + x3 = convert(triangulator,index3); + ok_triangle1 = real(triangulator,i,index1,index2) && !sliver(x0,x1,x2); + ok_triangle2 = real(triangulator,i,index2,index3) && !sliver(x0,x2,x3); + if(ok_triangle1 && ok_triangle2){ + C1 = circumcircle(triangulator,i,index1,index2); + C2 = circumcircle(triangulator,i,index2,index3); + is_inside1 = interior(triangulator,s1,s2,angle,C1); + is_inside2 = interior(triangulator,s1,s2,angle,C2); + if(is_inside1 && is_inside2){ + vertex = voronoi_vertex(C1); + vertex.set_index1(i); + vertex.set_index2(index1); + vertex.set_index3(index2); + temp[i].add_vertex(vertex); + } + else if(is_inside1){ + val = intersection(triangulator,s1,s2,C1,C2,flag,vec,s); + vertex1 = voronoi_vertex(C1); + vertex1.set_index1(i); + vertex1.set_index2(index1); + vertex1.set_index3(index2); + vertex2 = voronoi_vertex(val); + vertex2.set_index1(i); + vertex2.set_index2(index2); + vertex2.set_normal(vec); + temp[i].add_vertex(vertex1); + temp[i].add_vertex(vertex2); + flag = borders[index2].add_segment(s); + if(flag){ + fifo.push(index2); + } + } + else if(is_inside2){ + val = intersection(triangulator,s1,s2,C1,C2,flag,vec,s); + vertex1 = voronoi_vertex(x0); + vertex1.set_duplicate(1); + vertex2 = voronoi_vertex(val); + vertex2.set_index1(i); + vertex2.set_index2(index2); + vertex2.set_normal(vec); + temp[i].add_vertex(vertex1); + temp[i].add_vertex(vertex2); + flag = borders[index2].add_segment(s); + if(flag){ + fifo.push(index2); + } + } + else{ + any = intersection(triangulator,s1,s2,C1,C2,flag,vec,s); + if(flag){ + median = mid(x0,x2); + first = intersection(triangulator,s1,s2,C1,median,flag,vecA,s3); + second = intersection(triangulator,s1,s2,C2,median,flag,vecB,s4); + vertex1 = voronoi_vertex(x0); + vertex1.set_duplicate(1); + vertex2 = voronoi_vertex(first); + vertex2.set_index1(i); + vertex2.set_index2(index2); + vertex2.set_normal(vecA); + vertex3 = voronoi_vertex(second); + vertex3.set_index1(i); + vertex3.set_index2(index2); + vertex3.set_normal(vecB); + temp[i].add_vertex(vertex1); + temp[i].add_vertex(vertex2); + temp[i].add_vertex(vertex3); + flag1 = borders[index2].add_segment(s3); + flag2 = borders[index2].add_segment(s4); + if(flag1 || flag2){ + fifo.push(index2); + } + } + } + } + else if(ok_triangle1){ + C = circumcircle(triangulator,i,index1,index2); + is_inside = interior(triangulator,s1,s2,angle,C); + if(is_inside){ + val = mid(x0,x2); + vertex1 = voronoi_vertex(C); + vertex1.set_index1(i); + vertex1.set_index2(index1); + vertex1.set_index3(index2); + vertex2 = voronoi_vertex(val); + temp[i].add_vertex(vertex1); + temp[i].add_vertex(vertex2); + } + } + else if(ok_triangle2){ + C = circumcircle(triangulator,i,index2,index3); + is_inside = interior(triangulator,s1,s2,angle,C); + if(is_inside){ + val = mid(x0,x2); + vertex1 = voronoi_vertex(x0); + vertex1.set_duplicate(1); + vertex2 = voronoi_vertex(val); + temp[i].add_vertex(vertex1); + temp[i].add_vertex(vertex2); + } + } + } + } + } +} + +void lpcvt::step4(DocRecord& triangulator,GFace* gf){ + int i; + int j; + int num; + int index; + int start; + int opposite; + bool flag1,flag2; + SPoint2 val; + SPoint2 C1,C2; + SPoint2 p1,p2; + voronoi_vertex vertex1,vertex2; + segment s; + while(!fifo.empty()){ + index = fifo.front(); + fifo.pop(); + num = temp[index].get_number_vertices(); + if(interior(triangulator,gf,index)){ + start = 0; + } + else start = 2; + for(i=start;i<borders[index].get_number_segments();i++){ + s = borders[index].get_segment(i); + p1 = convert(triangulator,s.get_index1()); + p2 = convert(triangulator,s.get_index2()); + for(j=0;j<num;j++){ + vertex1 = temp[index].get_vertex(j); + vertex2 = temp[index].get_vertex((j+1)%num); + C1 = vertex1.get_point(); + C2 = vertex2.get_point(); + val = intersection(C1,C2,p1,p2,flag1); + if(flag1){ + if(vertex1.get_index3()!=-1){ + opposite = vertex1.get_index3(); + } + else if(vertex1.get_index2()!=-1){ + opposite = vertex1.get_index2(); + } + else if(vertex2.get_index2()!=-1){ + opposite = vertex2.get_index2(); + } + flag2 = borders[opposite].add_segment(s); + if(flag2){ + fifo.push(opposite); + } + } + } + } + } +} + +void lpcvt::step5(DocRecord& triangulator,GFace* gf){ + int i; + int j; + int k; + int num; + int start; + int opposite; + bool flag; + SPoint2 p1,p2,p3,p4,reference,val; + SVector3 n; + segment s; + voronoi_vertex vertex,vertex1,vertex2; + voronoi_cell cell; + for(i=0;i<triangulator.numPoints;i++){ + cell.clear(); + if(interior(triangulator,gf,i)){ + start = 0; + } + else start = 2; + for(j=start;j<borders[i].get_number_segments();j++){ + s = borders[i].get_segment(j); + p3 = convert(triangulator,s.get_index1()); + p4 = convert(triangulator,s.get_index2()); + reference = convert(triangulator,s.get_reference()); + n = normal(p3,p4); + num = temp[i].get_number_vertices(); + for(k=0;k<num;k++){ + vertex1 = temp[i].get_vertex(k); + vertex2 = temp[i].get_vertex((k+1)%num); + p1 = vertex1.get_point(); + p2 = vertex2.get_point(); + if(same_side(p3,p4,reference,p1)){ + cell.add_vertex(vertex1); + } + val = intersection(p1,p2,p3,p4,flag); + if(flag){ + if(vertex1.get_index3()!=-1){ + opposite = vertex1.get_index3(); + } + else if(vertex1.get_index2()!=-1){ + opposite = vertex1.get_index2(); + } + else if(vertex2.get_index2()!=-1){ + opposite = vertex2.get_index2(); + } + vertex = voronoi_vertex(val); + vertex.set_index1(i); + vertex.set_index2(opposite); + vertex.set_normal(n); + cell.add_vertex(vertex); + } + } + temp[i].clear(); + for(k=0;k<cell.get_number_vertices();k++){ + temp[i].add_vertex(cell.get_vertex(k)); + } + cell.clear(); + } + num = temp[i].get_number_vertices(); + for(j=0;j<num;j++){ + vertex = voronoi_vertex(convert(triangulator,i)); + vertex.set_index1(i); + vertex1 = temp[i].get_vertex(j); + vertex2 = temp[i].get_vertex((j+1)%num); + if(!vertex1.get_duplicate() && !vertex2.get_duplicate()){ + clipped.push_back(voronoi_element(vertex,vertex1,vertex2)); + } + } + } +} + +void lpcvt::clip_cells(DocRecord& triangulator,GFace* gf){ + step1(triangulator,gf); + step2(triangulator,gf); + step3(triangulator,gf); + step4(triangulator,gf); + step5(triangulator,gf); +} + +void lpcvt::clear(){ + int i; + for(i=0;i<fifo.size();i++){ + fifo.pop(); + } + clipped.clear(); + borders.clear(); + angles.clear(); + temp.clear(); + metrics.clear(); +} + +double lpcvt::total_area(){ + double total; + SPoint2 p1,p2,p3; + voronoi_vertex v1,v2,v3; + std::list<voronoi_element>::iterator it; + total = 0.0; + for(it=clipped.begin();it!=clipped.end();it++){ + v1 = it->get_v1(); + v2 = it->get_v2(); + v3 = it->get_v3(); + p1 = v1.get_point(); + p2 = v2.get_point(); + p3 = v3.get_point(); + total = total + triangle_area(p1,p2,p3); + } + return total; +} + +void lpcvt::print_voronoi1(){ + SPoint2 p1,p2,p3; + voronoi_vertex v1,v2,v3; + std::list<voronoi_element>::iterator it; + std::ofstream file("voronoi1.pos"); + file << "View \"test\" {\n"; + for(it=clipped.begin();it!=clipped.end();it++){ + v1 = it->get_v1(); + v2 = it->get_v2(); + v3 = it->get_v3(); + p1 = v1.get_point(); + p2 = v2.get_point(); + p3 = v3.get_point(); + print_segment(p2,p3,file); + } + file << "};\n"; +} + +void lpcvt::print_voronoi2(){ + int i; + int j; + int num; + SPoint2 p1,p2; + voronoi_vertex v1,v2; + std::ofstream file("voronoi2.pos"); + file << "View \"test\" {\n"; + for(i=0;i<temp.size();i++){ + num = temp[i].get_number_vertices(); + for(j=0;j<num;j++){ + v1 = temp[i].get_vertex(j); + v2 = temp[i].get_vertex((j+1)%num); + p1 = v1.get_point(); + p2 = v2.get_point(); + print_segment(p1,p2,file); + } + } + file << "};\n"; +} + +void lpcvt::print_delaunay(DocRecord& triangulator){ + int i; + int j; + int num; + int index1; + int index2; + SPoint2 x1,x2; + std::ofstream file("delaunay.pos"); + file << "View \"test\" {\n"; + for(i=0;i<triangulator.numPoints;i++){ + num = triangulator._adjacencies[i].t_length; + for(j=0;j<num;j++){ + index1 = triangulator._adjacencies[i].t[j]; + index2 = triangulator._adjacencies[i].t[(j+1)%num]; + if(triangulator.contain(i,index1,index2)){ + x1 = convert(triangulator,index1); + x2 = convert(triangulator,index2); + print_segment(x1,x2,file); + } + } + } + file << "};\n"; +} + +void lpcvt::print_segment(SPoint2 p1,SPoint2 p2,std::ofstream& file){ + file << "SL (" << p1.x() << ", " << p1.y() << ", 0, " + << p2.x() << ", " << p2.y() << ", 0){" + << "10, 20};\n"; +} + +void lpcvt::compute_metrics(DocRecord& triangulator){ + int i; + double x; + double y; + double angle; + double cosinus; + double sinus; + SPoint2 point; + metric m; + + metrics.resize(triangulator.numPoints); + + for(i=0;i<triangulator.numPoints;i++){ + point = convert(triangulator,i); + x = point.x(); + y = point.y(); + angle = backgroundMesh::current()->getAngle(x,y,0.0); //-myatan2(y,x); + cosinus = cos(angle); + sinus = sin(angle); + m = metric(cosinus,-sinus,sinus,cosinus); + metrics[i] = m; + } +} + +double lpcvt::get_rho(SPoint2 point,int p){ + double x; + double y; + double h; + double rho; + + x = point.x(); + y = point.y(); + h = backgroundMesh::current()->operator()(x,y,0.0); //0.1; + if(h>=0.0){ + rho = pow_int(1.0/h,p+1); //integer only, theoric value : p+2 + } + else{ + rho = -1000.0; + } + return rho; +} + +double lpcvt::drho_dx(SPoint2 point,int p){ + double x; + double y; + double e; + double val; + double rho; + double rho_less2; + double rho_less1; + double rho_plus1; + double rho_plus2; + SPoint2 less2; + SPoint2 less1; + SPoint2 plus1; + SPoint2 plus2; + + x = point.x(); + y = point.y(); + e = 0.00000001; + less2 = SPoint2(x-2.0*e,y); + less1 = SPoint2(x-e,y); + plus1 = SPoint2(x+e,y); + plus2 = SPoint2(x+2.0*e,y); + rho = get_rho(point,p); + rho_less2 = get_rho(less2,p); + rho_less1 = get_rho(less1,p); + rho_plus1 = get_rho(plus1,p); + rho_plus2 = get_rho(plus2,p); + if(rho_less2>=0.0 && rho_less1>=0.0 && rho_plus1>=0.0 && rho_plus2>=0.0){ + val = (rho_less2 - 8.0*rho_less1 + 8.0*rho_plus1 - rho_plus2)/(12.0*e); + } + else if(rho_less1>=0.0 && rho>=0.0){ + val = (rho - rho_less1)/e; + } + else if(rho>=0.0 && rho_plus1>=0.0){ + val = (rho_plus1 - rho)/e; + } + else{ + val = 0.0; + } + return val; +} + +double lpcvt::drho_dy(SPoint2 point,int p){ + double x; + double y; + double e; + double val; + double rho; + double rho_less2; + double rho_less1; + double rho_plus1; + double rho_plus2; + SPoint2 less2; + SPoint2 less1; + SPoint2 plus1; + SPoint2 plus2; + + x = point.x(); + y = point.y(); + e = 0.00000001; + less2 = SPoint2(x,y-2.0*e); + less1 = SPoint2(x,y-e); + plus1 = SPoint2(x,y+e); + plus2 = SPoint2(x,y+2.0*e); + rho = get_rho(point,p); + rho_less2 = get_rho(less2,p); + rho_less1 = get_rho(less1,p); + rho_plus1 = get_rho(plus1,p); + rho_plus2 = get_rho(plus2,p); + if(rho_less2>=0.0 && rho_less1>=0.0 && rho_plus1>=0.0 && rho_plus2>=0.0){ + val = (rho_less2 - 8.0*rho_less1 + 8.0*rho_plus1 - rho_plus2)/(12.0*e); + } + else if(rho_less1>=0.0 && rho>=0.0){ + val = (rho - rho_less1)/e; + } + else if(rho>=0.0 && rho_plus1>=0.0){ + val = (rho_plus1 - rho)/e; + } + else{ + val = 0.0; + } + return val; +} + +void lpcvt::write(DocRecord& triangulator,GFace* gf,int p){ + int i; + double energy; + SVector3 grad; + std::vector<SVector3> gradients(triangulator.numPoints); + + eval(triangulator,gradients,energy,p); + + std::ofstream file("gradient"); + + for(i=0;i<triangulator.numPoints;i++){ + if(interior(triangulator,gf,i)){ + grad = gradients[i]; + file << grad.x() << " "; + file << grad.y() << " "; + file << "\n"; + } + } +} + +void lpcvt::eval(DocRecord& triangulator,std::vector<SVector3>& gradients,double& energy,int p){ + int i; + int index; + int index1; + int index2; + int index3; + SPoint2 generator; + SPoint2 C1,C2; + SPoint2 p1,p2,p3; + SVector3 grad1,grad2; + SVector3 normal; + voronoi_vertex v1,v2,v3; + std::list<voronoi_element>::iterator it; + + for(i=0;i<gradients.size();i++){ + gradients[i] = SVector3(0.0,0.0,0.0); + } + energy = 0.0; + + for(it=clipped.begin();it!=clipped.end();it++){ + v1 = it->get_v1(); + v2 = it->get_v2(); + v3 = it->get_v3(); + generator = v1.get_point(); + C1 = v2.get_point(); + C2 = v3.get_point(); + index = v1.get_index1(); + energy = energy + F(generator,C1,C2,p,index); + gradients[index] = gradients[index] + simple(generator,C1,C2,p,index); + grad1 = dF_dC1(generator,C1,C2,p,index); + grad2 = dF_dC2(generator,C1,C2,p,index); + if(v2.get_index3()!=-1){ + index1 = v2.get_index1(); + index2 = v2.get_index2(); + index3 = v2.get_index3(); + p1 = convert(triangulator,index1); + p2 = convert(triangulator,index2); + p3 = convert(triangulator,index3); + gradients[index1] = gradients[index1] + inner_dFdx0(grad1,C1,p1,p2,p3); + gradients[index2] = gradients[index2] + inner_dFdx0(grad1,C1,p2,p1,p3); + gradients[index3] = gradients[index3] + inner_dFdx0(grad1,C1,p3,p1,p2); + } + else if(v2.get_index2()!=-1){ + index1 = v2.get_index1(); + index2 = v2.get_index2(); + normal = v2.get_normal(); + p1 = convert(triangulator,index1); + p2 = convert(triangulator,index2); + gradients[index1] = gradients[index1] + boundary_dFdx0(grad1,C1,p1,p2,normal); + gradients[index2] = gradients[index2] + boundary_dFdx0(grad1,C1,p2,p1,normal); + } + if(v3.get_index3()!=-1){ + index1 = v3.get_index1(); + index2 = v3.get_index2(); + index3 = v3.get_index3(); + p1 = convert(triangulator,index1); + p2 = convert(triangulator,index2); + p3 = convert(triangulator,index3); + gradients[index1] = gradients[index1] + inner_dFdx0(grad2,C2,p1,p2,p3); + gradients[index2] = gradients[index2] + inner_dFdx0(grad2,C2,p2,p1,p3); + gradients[index3] = gradients[index3] + inner_dFdx0(grad2,C2,p3,p1,p2); + } + else if(v3.get_index2()!=-1){ + index1 = v3.get_index1(); + index2 = v3.get_index2(); + normal = v3.get_normal(); + p1 = convert(triangulator,index1); + p2 = convert(triangulator,index2); + gradients[index1] = gradients[index1] + boundary_dFdx0(grad2,C2,p1,p2,normal); + gradients[index2] = gradients[index2] + boundary_dFdx0(grad2,C2,p2,p1,normal); + } + } +} + +void lpcvt::swap(){ + voronoi_vertex vertex; + std::list<voronoi_element>::iterator it; + for(it=clipped.begin();it!=clipped.end();it++){ + vertex = it->get_v3(); + it->set_v3(it->get_v2()); + it->set_v2(vertex); + } +} + +void lpcvt::get_gauss(){ + int order; order = 8; - gaussIntegration::getTriangle(order,pts,weights); - num = pts.size1(); + gaussIntegration::getTriangle(order,gauss_points,gauss_weights); + gauss_num = gauss_points.size1(); +} + +double lpcvt::F(SPoint2 generator,SPoint2 C1,SPoint2 C2,int p,int index){ + int i; + double x; + double y; + double energy; + double u; + double v; + double weight; + SPoint2 point; + energy = 0.0; + for(i=0;i<gauss_num;i++){ + u = gauss_points(i,0); + v = gauss_points(i,1); + weight = gauss_weights(i,0); + x = Tx(u,v,generator,C1,C2); + y = Ty(u,v,generator,C1,C2); + point = SPoint2(x,y); + energy = energy + weight*get_rho(point,p)*f(generator,point,p,index); + } + energy = J(generator,C1,C2)*energy; + return energy; +} + +SVector3 lpcvt::simple(SPoint2 generator,SPoint2 C1,SPoint2 C2,int p,int index){ + int i; + double x; + double y; + double comp_x; + double comp_y; + double jacobian; + double u; + double v; + double weight; + double rho; + SPoint2 point; comp_x = 0.0; comp_y = 0.0; - for(i=0;i<num;i++){ - x = Tx(pts(i,0),pts(i,1),generator,C1,C2); - y = Ty(pts(i,0),pts(i,1),generator,C1,C2); + jacobian = J(generator,C1,C2); + for(i=0;i<gauss_num;i++){ + u = gauss_points(i,0); + v = gauss_points(i,1); + weight = gauss_weights(i,0); + x = Tx(u,v,generator,C1,C2); + y = Ty(u,v,generator,C1,C2); point = SPoint2(x,y); - comp_x = comp_x + weights(i,0)*df_dx(generator,point,p); - comp_y = comp_y + weights(i,0)*df_dy(generator,point,p); + rho = get_rho(point,p); + comp_x = comp_x + weight*rho*df_dx(generator,point,p,index); + comp_y = comp_y + weight*rho*df_dy(generator,point,p,index); } - comp_x = J(generator,C1,C2)*comp_x; - comp_y = J(generator,C1,C2)*comp_y; + comp_x = jacobian*comp_x; + comp_y = jacobian*comp_y; return SVector3(comp_x,comp_y,0.0); } -SVector3 lloydAlgorithm::dF_dC1(SPoint2 generator,SPoint2 C1,SPoint2 C2,int p){ +SVector3 lpcvt::dF_dC1(SPoint2 generator,SPoint2 C1,SPoint2 C2,int p,int index){ int i; - int num; - int order; double x; double y; double comp_x; double comp_y; + double jacobian; + double u; + double v; + double weight; + double rho; SPoint2 point; - fullMatrix<double> pts; - fullMatrix<double> weights; - order = 8; - gaussIntegration::getTriangle(order,pts,weights); - num = pts.size1(); comp_x = 0.0; comp_y = 0.0; - for(i=0;i<num;i++){ - x = Tx(pts(i,0),pts(i,1),generator,C1,C2); - y = Ty(pts(i,0),pts(i,1),generator,C1,C2); - point = SPoint2(x,y); - comp_x = comp_x + weights(i,0)*df_dx(point,generator,p)*dTx_dp2x(pts(i,0),pts(i,1))*J(generator, C1, C2); - comp_x = comp_x + weights(i,0)*f(point,generator,p)*dJ_dp2x(generator,C1,C2); - comp_y = comp_y + weights(i,0)*df_dy(point,generator,p)*dTy_dp2y(pts(i,0),pts(i,1))*J(generator, C1, C2); - comp_y = comp_y + weights(i,0)*f(point,generator,p)*dJ_dp2y(generator,C1,C2); + jacobian = J(generator,C1,C2); + for(i=0;i<gauss_num;i++){ + u = gauss_points(i,0); + v = gauss_points(i,1); + weight = gauss_weights(i,0); + x = Tx(u,v,generator,C1,C2); + y = Ty(u,v,generator,C1,C2); + point = SPoint2(x,y); + rho = get_rho(point,p); + comp_x = comp_x + weight*rho*df_dx(point,generator,p,index)*u*jacobian; + comp_x = comp_x + weight*rho*f(point,generator,p,index)*(C2.y()-generator.y()); + comp_x = comp_x + weight*drho_dx(point,p)*u*f(point,generator,p,index)*jacobian; + comp_y = comp_y + weight*rho*df_dy(point,generator,p,index)*u*jacobian; + comp_y = comp_y + weight*rho*f(point,generator,p,index)*(generator.x()-C2.x()); + comp_y = comp_y + weight*drho_dy(point,p)*u*f(point,generator,p,index)*jacobian; } return SVector3(comp_x,comp_y,0.0); } -SVector3 lloydAlgorithm::dF_dC2(SPoint2 generator,SPoint2 C1,SPoint2 C2,int p){ +SVector3 lpcvt::dF_dC2(SPoint2 generator,SPoint2 C1,SPoint2 C2,int p,int index){ int i; - int num; - int order; double x; double y; double comp_x; double comp_y; + double jacobian; + double u; + double v; + double weight; + double rho; SPoint2 point; - fullMatrix<double> pts; - fullMatrix<double> weights; - order = 8; - gaussIntegration::getTriangle(order,pts,weights); - num = pts.size1(); comp_x = 0.0; comp_y = 0.0; - for(i=0;i<num;i++){ - x = Tx(pts(i,0),pts(i,1),generator,C1,C2); - y = Ty(pts(i,0),pts(i,1),generator,C1,C2); + jacobian = J(generator,C1,C2); + for(i=0;i<gauss_num;i++){ + u = gauss_points(i,0); + v = gauss_points(i,1); + weight = gauss_weights(i,0); + x = Tx(u,v,generator,C1,C2); + y = Ty(u,v,generator,C1,C2); point = SPoint2(x,y); - comp_x = comp_x + weights(i,0)*df_dx(point,generator,p)*dTx_dp3x(pts(i,0),pts(i,1))*J(generator,C1,C2); - comp_x = comp_x + weights(i,0)*f(point,generator,p)*dJ_dp3x(generator,C1,C2); - comp_y = comp_y + weights(i,0)*df_dy(point,generator,p)*dTy_dp3y(pts(i,0),pts(i,1))*J(generator,C1,C2); - comp_y = comp_y + weights(i,0)*f(point,generator,p)*dJ_dp3y(generator,C1,C2); + rho = get_rho(point,p); + comp_x = comp_x + weight*rho*df_dx(point,generator,p,index)*v*jacobian; + comp_x = comp_x + weight*rho*f(point,generator,p,index)*(generator.y()-C1.y()); + comp_x = comp_x + weight*drho_dx(point,p)*v*f(point,generator,p,index)*jacobian; + comp_y = comp_y + weight*rho*df_dy(point,generator,p,index)*v*jacobian; + comp_y = comp_y + weight*rho*f(point,generator,p,index)*(C1.x()-generator.x()); + comp_y = comp_y + weight*drho_dy(point,p)*v*f(point,generator,p,index)*jacobian; } return SVector3(comp_x,comp_y,0.0); } -double lloydAlgorithm::f(SPoint2 p1,SPoint2 p2,int p){ +double lpcvt::f(SPoint2 p1,SPoint2 p2,int p,int index){ + double x1; + double y1; + double x2; + double y2; + double val1; + double val2; double val; - val = exp(p1.x()-p2.x(),p) + exp(p1.y()-p2.y(),p); + double a; + double b; + double c; + double d; + metric m; + + x1 = p1.x(); + y1 = p1.y(); + x2 = p2.x(); + y2 = p2.y(); + m = metrics[index]; + a = m.get_a(); + b = m.get_b(); + c = m.get_c(); + d = m.get_d(); + val1 = a*x1 + b*y1 - a*x2 - b*y2; + val2 = c*x1 + d*y1 - c*x2 - d*y2; + val = pow_int(val1,p) + pow_int(val2,p); return val; } -double lloydAlgorithm::df_dx(SPoint2 p1,SPoint2 p2,int p){ +double lpcvt::df_dx(SPoint2 p1,SPoint2 p2,int p,int index){ + double x1; + double y1; + double x2; + double y2; + double val1; + double val2; double val; - val = ((double)p)*exp(p1.x()-p2.x(),p-1); + double a; + double b; + double c; + double d; + metric m; + + x1 = p1.x(); + y1 = p1.y(); + x2 = p2.x(); + y2 = p2.y(); + m = metrics[index]; + a = m.get_a(); + b = m.get_b(); + c = m.get_c(); + d = m.get_d(); + val1 = a*x1 + b*y1 - a*x2 - b*y2; + val2 = c*x1 + d*y1 - c*x2 - d*y2; + val = ((double)p)*pow_int(val1,p-1)*a + ((double)p)*pow_int(val2,p-1)*c; return val; } -double lloydAlgorithm::df_dy(SPoint2 p1,SPoint2 p2,int p){ +double lpcvt::df_dy(SPoint2 p1,SPoint2 p2,int p,int index){ + double x1; + double y1; + double x2; + double y2; + double val1; + double val2; double val; - val = ((double)p)*exp(p1.y()-p2.y(),p-1); + double a; + double b; + double c; + double d; + metric m; + + x1 = p1.x(); + y1 = p1.y(); + x2 = p2.x(); + y2 = p2.y(); + m = metrics[index]; + a = m.get_a(); + b = m.get_b(); + c = m.get_c(); + d = m.get_d(); + val1 = a*x1 + b*y1 - a*x2 - b*y2; + val2 = c*x1 + d*y1 - c*x2 - d*y2; + val = ((double)p)*pow_int(val1,p-1)*b + ((double)p)*pow_int(val2,p-1)*d; return val; } -double lloydAlgorithm::L1(double u,double v){ +double lpcvt::Tx(double u,double v,SPoint2 p1,SPoint2 p2,SPoint2 p3){ double val; - val = 1.0-u-v; + val = (1.0-u-v)*p1.x() + u*p2.x() + v*p3.x(); return val; } -double lloydAlgorithm::dL1_du(){ - return -1.0; -} - -double lloydAlgorithm::dL1_dv(){ - return -1.0; +double lpcvt::Ty(double u,double v,SPoint2 p1,SPoint2 p2,SPoint2 p3){ + double val; + val = (1.0-u-v)*p1.y() + u*p2.y() + v*p3.y(); + return val; } -double lloydAlgorithm::L2(double u,double v){ +double lpcvt::J(SPoint2 p1,SPoint2 p2,SPoint2 p3){ double val; - val = u; + val = (p2.x()-p1.x())*(p3.y()-p1.y()) - (p3.x()-p1.x())*(p2.y()-p1.y()); return val; } -double lloydAlgorithm::dL2_du(){ - return 1.0; +SVector3 lpcvt::inner_dFdx0(SVector3 dFdC,SPoint2 C,SPoint2 x0,SPoint2 x1,SPoint2 x2){ + double det; + double A[2][2]; + double B[2][2]; + double M[2][2]; + det = (x1.x()-x0.x())*(x2.y()-x0.y()) - (x1.y() - x0.y())*(x2.x() - x0.x()); + A[0][0] = (x2.y() - x0.y())/det; + A[0][1] = -(x1.y() - x0.y())/det; + A[1][0] = -(x2.x() - x0.x())/det; + A[1][1] = (x1.x() - x0.x())/det; + B[0][0] = C.x() - x0.x(); + B[0][1] = C.y() - x0.y(); + B[1][0] = C.x() - x0.x(); + B[1][1] = C.y() - x0.y(); + M[0][0] = A[0][0]*B[0][0] + A[0][1]*B[1][0]; + M[0][1] = A[0][0]*B[0][1] + A[0][1]*B[1][1]; + M[1][0] = A[1][0]*B[0][0] + A[1][1]*B[1][0]; + M[1][1] = A[1][0]*B[0][1] + A[1][1]*B[1][1]; + return SVector3(dFdC.x()*M[0][0]+dFdC.y()*M[1][0],dFdC.x()*M[0][1]+dFdC.y()*M[1][1],0.0); } -double lloydAlgorithm::dL2_dv(){ - return 0.0; +SVector3 lpcvt::boundary_dFdx0(SVector3 dFdC,SPoint2 C,SPoint2 x0,SPoint2 x1,SVector3 normal){ + fullMatrix<double> A(2,2); + fullMatrix<double> B(2,2); + fullMatrix<double> M(2,2); + fullMatrix<double> _dFdC(1,2); + fullMatrix<double> _val(1,2); + A(0,0) = x1.x() - x0.x(); + A(0,1) = x1.y() - x0.y(); + A(1,0) = normal.x(); + A(1,1) = normal.y(); + A.invertInPlace(); + B(0,0) = C.x() - x0.x(); + B(0,1) = C.y() - x0.y(); + B(1,0) = 0.0; + B(1,1) = 0.0; + A.mult_naive(B,M); + _dFdC(0,0) = dFdC.x(); + _dFdC(0,1) = dFdC.y(); + _dFdC.mult_naive(M,_val); + return SVector3(_val(0,0),_val(0,1),0.0); } -double lloydAlgorithm::L3(double u,double v){ - double val; - val = v; - return val; -} -double lloydAlgorithm::dL3_du(){ - return 0.0; + +/****************class voronoi_vertex****************/ + +voronoi_vertex::voronoi_vertex(SPoint2 new_point){ + point = new_point; + index1 = -1; + index2 = -1; + index3 = -1; + normal = SVector3(0.0,0.0,0.0); + duplicate = 0; } -double lloydAlgorithm::dL3_dv(){ - return 1.0; +voronoi_vertex::voronoi_vertex(){} + +voronoi_vertex::~voronoi_vertex(){} + +SPoint2 voronoi_vertex::get_point(){ + return point; } -double lloydAlgorithm::Tx(double u,double v,SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double val; - val = L1(u,v)*p1.x() + L2(u,v)*p2.x() + L3(u,v)*p3.x(); - return val; +int voronoi_vertex::get_index1(){ + return index1; } -double lloydAlgorithm::dTx_dp1x(double u,double v){ - return L1(u,v); +int voronoi_vertex::get_index2(){ + return index2; } -double lloydAlgorithm::dTx_dp2x(double u,double v){ - return L2(u,v); +int voronoi_vertex::get_index3(){ + return index3; } -double lloydAlgorithm::dTx_dp3x(double u,double v){ - return L3(u,v); +SVector3 voronoi_vertex::get_normal(){ + return normal; } -double lloydAlgorithm::dTx_du(SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double val; - val = dL1_du()*p1.x() + dL2_du()*p2.x() + dL3_du()*p3.x(); - return val; +bool voronoi_vertex::get_duplicate(){ + return duplicate; } -double lloydAlgorithm::dTx_dv(SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double val; - val = dL1_dv()*p1.x() + dL2_dv()*p2.x() + dL3_dv()*p3.x(); - return val; +void voronoi_vertex::set_point(SPoint2 new_point){ + point = new_point; } -double lloydAlgorithm::Ty(double u,double v,SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double val; - val = L1(u,v)*p1.y() + L2(u,v)*p2.y() + L3(u,v)*p3.y(); - return val; +void voronoi_vertex::set_index1(int new_index1){ + index1 = new_index1; } -double lloydAlgorithm::dTy_dp1y(double u,double v){ - return L1(u,v); +void voronoi_vertex::set_index2(int new_index2){ + index2 = new_index2; } -double lloydAlgorithm::dTy_dp2y(double u,double v){ - return L2(u,v); +void voronoi_vertex::set_index3(int new_index3){ + index3 = new_index3; } -double lloydAlgorithm::dTy_dp3y(double u,double v){ - return L3(u,v); +void voronoi_vertex::set_normal(SVector3 new_normal){ + normal = new_normal; } -double lloydAlgorithm::dTy_du(SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double val; - val = dL1_du()*p1.y() + dL2_du()*p2.y() + dL3_du()*p3.y(); - return val; +void voronoi_vertex::set_duplicate(bool new_duplicate){ + duplicate = new_duplicate; } -double lloydAlgorithm::dTy_dv(SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double val; - val = dL1_dv()*p1.y() + dL2_dv()*p2.y() + dL3_dv()*p3.y(); - return val; + + +/****************class voronoi_element****************/ + +voronoi_element::voronoi_element(voronoi_vertex new_v1,voronoi_vertex new_v2,voronoi_vertex new_v3){ + v1 = new_v1; + v2 = new_v2; + v3 = new_v3; } -double lloydAlgorithm::J(SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double val; - val = dTx_du(p1,p2,p3)*dTy_dv(p1,p2,p3) - dTx_dv(p1,p2,p3)*dTy_du(p1,p2,p3); - return val; +voronoi_element::voronoi_element(){} + +voronoi_element::~voronoi_element(){} + +voronoi_vertex voronoi_element::get_v1(){ + return v1; } -double lloydAlgorithm::dJ_dp1x(SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double val; - val = dL1_du()*dTy_dv(p1,p2,p3) - dL1_dv()*dTy_du(p1,p2,p3); - return val; +voronoi_vertex voronoi_element::get_v2(){ + return v2; } -double lloydAlgorithm::dJ_dp2x(SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double val; - val = dL2_du()*dTy_dv(p1,p2,p3) - dL2_dv()*dTy_du(p1,p2,p3); - return val; +voronoi_vertex voronoi_element::get_v3(){ + return v3; } -double lloydAlgorithm::dJ_dp3x(SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double val; - val = dL3_du()*dTy_dv(p1,p2,p3) - dL3_dv()*dTy_du(p1,p2,p3); - return val; +void voronoi_element::set_v1(voronoi_vertex new_v1){ + v1 = new_v1; } -double lloydAlgorithm::dJ_dp1y(SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double val; - val = dTx_du(p1,p2,p3)*dL1_dv() - dTx_dv(p1,p2,p3)*dL1_du(); - return val; +void voronoi_element::set_v2(voronoi_vertex new_v2){ + v2 = new_v2; } -double lloydAlgorithm::dJ_dp2y(SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double val; - val = dTx_du(p1,p2,p3)*dL2_dv() - dTx_dv(p1,p2,p3)*dL2_du(); - return val; +void voronoi_element::set_v3(voronoi_vertex new_v3){ + v3 = new_v3; } -double lloydAlgorithm::dJ_dp3y(SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double val; - val = dTx_du(p1,p2,p3)*dL3_dv() - dTx_dv(p1,p2,p3)*dL3_du(); - return val; + + +/****************class voronoi_cell****************/ + +voronoi_cell::voronoi_cell(){} + +voronoi_cell::~voronoi_cell(){} + +int voronoi_cell::get_number_vertices(){ + return vertices.size(); } -SVector3 lloydAlgorithm::inner_dFdx0(SVector3 dFdC,SPoint2 C,SPoint2 x0,SPoint2 x1,SPoint2 x2){ - fullMatrix<double> A(2,2); - fullMatrix<double> B(2,2); - fullMatrix<double> M(2,2); - fullMatrix<double> _dFdC(1,2); - fullMatrix<double> _val(1,2); - A(0,0) = x1.x() - x0.x(); - A(0,1) = x1.y() - x0.y(); - A(1,0) = x2.x() - x0.x(); - A(1,1) = x2.y() - x0.y(); - A.invertInPlace(); - B(0,0) = C.x() - x0.x(); - B(0,1) = C.y() - x0.y(); - B(1,0) = C.x() - x0.x(); - B(1,1) = C.y() - x0.y(); - A.mult_naive(B,M); - _dFdC(0,0) = dFdC.x(); - _dFdC(0,1) = dFdC.y(); - _dFdC.mult_naive(M,_val); - return SVector3(_val(0,0),_val(0,1),0.0); +voronoi_vertex voronoi_cell::get_vertex(int index){ + return vertices[index]; } -SVector3 lloydAlgorithm::boundary_dFdx0(SVector3 dFdC,SPoint2 C,SPoint2 x0,SPoint2 x1,SVector3 normal){ - fullMatrix<double> A(2,2); - fullMatrix<double> B(2,2); - fullMatrix<double> M(2,2); - fullMatrix<double> _dFdC(1,2); - fullMatrix<double> _val(1,2); - A(0,0) = x1.x() - x0.x(); - A(0,1) = x1.y() - x0.y(); - A(1,0) = normal.x(); - A(1,1) = normal.y(); - A.invertInPlace(); - B(0,0) = C.x() - x0.x(); - B(0,1) = C.y() - x0.y(); - B(1,0) = 0.0; - B(1,1) = 0.0; - A.mult_naive(B,M); - _dFdC(0,0) = dFdC.x(); - _dFdC(0,1) = dFdC.y(); - _dFdC.mult_naive(M,_val); - return SVector3(_val(0,0),_val(0,1),0.0); +void voronoi_cell::add_vertex(voronoi_vertex vertex){ + vertices.push_back(vertex); } -double lloydAlgorithm::exp(double a,int b) -{ - int i; - double val = 1.0; - for(i=0;i<b;i++){ - val = val*a; - } - return val; +void voronoi_cell::clear(){ + vertices.clear(); } -/****************Calcul des intersections****************/ -/********************************************************/ +/****************class segment****************/ -SVector3 lloydAlgorithm::normal(SPoint2 p1,SPoint2 p2){ - double x; - double y; - SVector3 val; - x = p2.x() - p1.x(); - y = p2.y() - p1.y(); - val = SVector3(-y,x,0.0); - return val; +segment::segment(int new_index1,int new_index2,int new_reference){ + index1 = new_index1; + index2 = new_index2; + reference = new_reference; } -SPoint2 lloydAlgorithm::mid(SPoint2 p1,SPoint2 p2){ - double x; - double y; - x = 0.5*(p1.x() + p2.x()); - y = 0.5*(p1.y() + p2.y()); - return SPoint2(x,y); +segment::segment(){} + +segment::~segment(){} + +int segment::get_index1(){ + return index1; } -void lloydAlgorithm::print_segment(SPoint2 p1,SPoint2 p2,std::ofstream& file){ - file << "SL (" << p1.x() << ", " - << p1.y() << ", 0, " - << p2.x() << ", " - << p2.y() << ", 0){" << "10, 20};\n"; +int segment::get_index2(){ + return index2; } -bool lloydAlgorithm::adjacent(const DocRecord& triangulator,int index1,int index2){ - int num = triangulator._adjacencies[index1].t_length; - for(int i=0;i<num;i++){ - if(triangulator._adjacencies[index1].t[i] == index2){ - return 1; - } - } - return 0; +int segment::get_reference(){ + return reference; } -double lloydAlgorithm::triangle_area(SPoint2 p1,SPoint2 p2,SPoint2 p3){ - double area; - double x1,y1; - double x2,y2; - x1 = p2.x() - p1.x(); - y1 = p2.y() - p1.y(); - x2 = p3.x() - p1.x(); - y2 = p3.y() - p1.y(); - area = 0.5*fabs(x1*y2 - x2*y1); - return area; +void segment::set_index1(int new_index1){ + index1 = new_index1; } -SPoint2 lloydAlgorithm::boundary_intersection(SPoint2 p1,SPoint2 p2,bool& flag,SVector3& vec){ - int i; - int num; - bool flag2; - SPoint2 p3; - SPoint2 p4; - SPoint2 val; - boundary_edge edge; - num = get_number_boundary_edges(); - for(i=0;i<num;i++){ - edge = get_boundary_edge(i); - p3 = edge.get_p1(); - p4 = edge.get_p2(); - val = intersection(p1,p2,p3,p4,flag2); - if(flag2){ - flag = 1; - vec = normal(p3,p4); - return val; - } - } - flag = 0; - vec = SVector3(0.0,0.0,0.0); - return SPoint2(0.0,0.0); +void segment::set_index2(int new_index2){ + index2 = new_index2; } -bool lloydAlgorithm::inside_domain(double x,double y){ - if(x<=1.0 && x>=0.0 && y<=1.0 && y>=0.0){ +void segment::set_reference(int new_reference){ + reference = new_reference; +} + +bool segment::equal(int index3,int index4){ + if(index1==index3 && index2==index4){ return 1; } - else{ - return 0; + else if(index1==index4 && index2==index3){ + return 1; } + else return 0; } -int lloydAlgorithm::get_number_boundary_edges(){ - return 4; + + +/****************class list_segment****************/ + +segment_list::segment_list(){} + +segment_list::~segment_list(){} + +int segment_list::get_number_segments(){ + return segments.size(); } -boundary_edge lloydAlgorithm::get_boundary_edge(int i){ - if(i==0) return boundary_edge(SPoint2(0.0,0.0),SPoint2(1.0,0.0)); - else if(i==1) return boundary_edge(SPoint2(1.0,0.0),SPoint2(1.0,1.0)); - else if(i==2) return boundary_edge(SPoint2(1.0,1.0),SPoint2(0.0,1.0)); - else if(i==3) return boundary_edge(SPoint2(0.0,1.0),SPoint2(0.0,0.0)); +segment segment_list::get_segment(int index){ + return segments[index]; } -SPoint2 lloydAlgorithm::intersection(SPoint2 p1,SPoint2 p2,SPoint2 p3,SPoint2 p4,bool& flag){ - double x1,y1; - double x2,y2; - double x3,y3; - double x4,y4; - double ua,ub; - double num_ua; - double num_ub; - double denom; - double e; - x1 = p1.x(); - y1 = p1.y(); - x2 = p2.x(); - y2 = p2.y(); - x3 = p3.x(); - y3 = p3.y(); - x4 = p4.x(); - y4 = p4.y(); - e = 0.000001; - denom = (y4-y3)*(x2-x1) - (x4-x3)*(y2-y1); - if(fabs(denom)<e){ - flag = 0; - return SPoint2(0.0,0.0); - } - num_ua = (x4-x3)*(y1-y3) - (y4-y3)*(x1-x3); - num_ub = (x2-x1)*(y1-y3) - (y2-y1)*(x1-x3); - ua = num_ua/denom; - ub = num_ub/denom; - if(ua<=1.0 && ua>=0.0 && ub<=1.0 && ub>=0.0){ - flag = 1; - return SPoint2(x1 + ua * (x2 - x1), y1 + ua * (y2 - y1)); - } - else{ - flag = 0; - return SPoint2(0.0,0.0); +bool segment_list::add_segment(int index1,int index2,int reference){ + int i; + for(i=0;i<segments.size();i++){ + if(segments[i].equal(index1,index2)) return 0; } + segments.push_back(segment(index1,index2,reference)); + return 1; } -/****************Class boundary_edge****************/ -boundary_edge::boundary_edge(SPoint2 new_p1, SPoint2 new_p2){ - p1 = new_p1; - p2 = new_p2; +bool segment_list::add_segment(segment s){ + return add_segment(s.get_index1(),s.get_index2(),s.get_reference()); } -boundary_edge::boundary_edge(){} -boundary_edge::~boundary_edge(){} -SPoint2 boundary_edge::get_p1(){ - return p1; +/****************class metric****************/ + +metric::metric(double new_a,double new_b,double new_c,double new_d){ + a = new_a; + b = new_b; + c = new_c; + d = new_d; } -SPoint2 boundary_edge::get_p2(){ - return p2; +metric::metric(){} + +metric::~metric(){} + +void metric::set_a(double new_a){ + a = new_a; } +void metric::set_b(double new_b){ + b = new_b; +} -#endif +void metric::set_c(double new_c){ + c = new_c; +} + +void metric::set_d(double new_d){ + d = new_d; +} + +double metric::get_a(){ + return a; +} + +double metric::get_b(){ + return b; +} + +double metric::get_c(){ + return c; +} + +double metric::get_d(){ + return d; +} + + + +/****************class wrapper****************/ + +wrapper::wrapper(){ + iteration = 0; + start = -100.0; +} + +wrapper::~wrapper(){} + +int wrapper::get_p(){ + return p; +} + +void wrapper::set_p(int new_p){ + p = new_p; +} + +int wrapper::get_dimension(){ + return dimension; +} + +void wrapper::set_dimension(int new_dimension){ + dimension = new_dimension; +} + +GFace* wrapper::get_face(){ + return gf; +} + +void wrapper::set_face(GFace* new_gf){ + gf = new_gf; +} + +int wrapper::get_iteration(){ + return iteration; +} + +void wrapper::set_iteration(int new_iteration){ + iteration = new_iteration; +} + +int wrapper::get_max(){ + return max; +} + +void wrapper::set_max(int new_max){ + max = new_max; +} + +double wrapper::get_start(){ + return start; +} + +void wrapper::set_start(double new_start){ + start = new_start; +} + +DocRecord* wrapper::get_triangulator(){ + return triangulator; +} + +void wrapper::set_triangulator(DocRecord* new_triangulator){ + triangulator = new_triangulator; +} + +MElementOctree* wrapper::get_octree(){ + return octree; +} + +void wrapper::set_octree(MElementOctree* new_octree){ + octree = new_octree; +} diff --git a/Mesh/meshGFaceLloyd.h b/Mesh/meshGFaceLloyd.h index cc79af379e..8499a317ea 100644 --- a/Mesh/meshGFaceLloyd.h +++ b/Mesh/meshGFaceLloyd.h @@ -1,107 +1,236 @@ -// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle +// Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle // // See the LICENSE.txt file for license information. Please report all // bugs and problems to <gmsh@geuz.org>. #ifndef _MESH_GFACE_LLOYD_H_ #define _MESH_GFACE_LLOYD_H_ - #include "fullMatrix.h" #include "DivideAndConquer.h" -#include "GmshConfig.h" - -#if defined(HAVE_BFGS) +#include <queue> #include "ap.h" #include "alglibinternal.h" -#include "alglibmisc.h" +#include "alglibmisc.h" #include "linalg.h" #include "optimization.h" +#include "MElementOctree.h" class GFace; -class boundary_edge; +class voronoi_vertex; +class voronoi_element; +class voronoi_cell; +class segment; +class segment_list; +class metric; + +void callback(const alglib::real_1d_array&,double&,alglib::real_1d_array&,void*); +bool domain_search(MElementOctree*,GFace*,double,double); class lloydAlgorithm { int ITER_MAX; - bool infiniteNorm; - double test; + int NORM; public : - lloydAlgorithm (int itermax, bool infnorm = false) - : ITER_MAX(itermax), infiniteNorm(infnorm) {} + lloydAlgorithm (int itermax, int norm) : ITER_MAX(itermax), NORM(norm) {} lloydAlgorithm() {} void operator () (GFace *); - double optimize(int,int); - - void eval(DocRecord&,GFace*,std::vector<SVector3>&,std::vector<double>&,std::vector<SVector3>&,std::vector<double>&,int); - double total_energy(std::vector<double>); - SVector3 numerical(DocRecord&,GFace*,int,int); + void optimize(int,int); +}; + +class lpcvt{ + private : + std::list<voronoi_element> clipped; + std::queue<int> fifo; + std::vector<segment_list> borders; + std::vector<double> angles; + std::vector<voronoi_cell> temp; + fullMatrix<double> gauss_points; + fullMatrix<double> gauss_weights; + std::vector<metric> metrics; + int gauss_num; + public : + lpcvt(); + ~lpcvt(); + double angle(SPoint2,SPoint2,SPoint2); + SVector3 normal(SPoint2,SPoint2); + SPoint2 mid(SPoint2,SPoint2); + bool same_side(SPoint2,SPoint2,SPoint2,SPoint2); + bool interior(DocRecord&,GFace*,int); + bool interior(DocRecord&,segment,segment,double,SPoint2); + bool invisible(DocRecord&,GFace*,int); + bool real(DocRecord&,int,int,int); + double triangle_area(SPoint2,SPoint2,SPoint2); + bool sliver(SPoint2,SPoint2,SPoint2); + SPoint2 intersection(DocRecord&,segment,segment,SPoint2,SPoint2,bool&,SVector3&,segment&); + SPoint2 intersection(SPoint2,SPoint2,SPoint2,SPoint2,bool&); + SPoint2 convert(DocRecord&,int); + SPoint2 circumcircle(DocRecord&,int,int,int); + SPoint2 seed(DocRecord&,GFace*); + void step1(DocRecord&,GFace*); + void step2(DocRecord&,GFace*); + void step3(DocRecord&,GFace*); + void step4(DocRecord&,GFace*); + void step5(DocRecord&,GFace*); + void clip_cells(DocRecord&,GFace*); + void clear(); + double total_area(); + void print_voronoi1(); + void print_voronoi2(); + void print_delaunay(DocRecord&); + void print_segment(SPoint2,SPoint2,std::ofstream&); + + void compute_metrics(DocRecord&); + double get_rho(SPoint2,int); + double drho_dx(SPoint2,int); + double drho_dy(SPoint2,int); void write(DocRecord&,GFace*,int); - void write2(DocRecord&,GFace*); - SVector3 analytical(SPoint2,SVector3,double); - SVector3 area_centroid(SPoint2,SPoint2,SPoint2); - - double F(SPoint2,SPoint2,SPoint2,int); - SVector3 simple(SPoint2,SPoint2,SPoint2,int); - SVector3 dF_dC1(SPoint2,SPoint2,SPoint2,int); - SVector3 dF_dC2(SPoint2,SPoint2,SPoint2,int); - double f(SPoint2,SPoint2,int); - double df_dx(SPoint2,SPoint2,int); - double df_dy(SPoint2,SPoint2,int); - double L1(double,double); - double dL1_du(); - double dL1_dv(); - double L2(double,double); - double dL2_du(); - double dL2_dv(); - double L3(double,double); - double dL3_du(); - double dL3_dv(); + void eval(DocRecord&,std::vector<SVector3>&,double&,int); + void swap(); + void get_gauss(); + double F(SPoint2,SPoint2,SPoint2,int,int); + SVector3 simple(SPoint2,SPoint2,SPoint2,int,int); + SVector3 dF_dC1(SPoint2,SPoint2,SPoint2,int,int); + SVector3 dF_dC2(SPoint2,SPoint2,SPoint2,int,int); + double f(SPoint2,SPoint2,int,int); + double df_dx(SPoint2,SPoint2,int,int); + double df_dy(SPoint2,SPoint2,int,int); double Tx(double,double,SPoint2,SPoint2,SPoint2); - double dTx_dp1x(double,double); - double dTx_dp2x(double,double); - double dTx_dp3x(double,double); - double dTx_du(SPoint2,SPoint2,SPoint2); - double dTx_dv(SPoint2,SPoint2,SPoint2); double Ty(double,double,SPoint2,SPoint2,SPoint2); - double dTy_dp1y(double,double); - double dTy_dp2y(double,double); - double dTy_dp3y(double,double); - double dTy_du(SPoint2,SPoint2,SPoint2); - double dTy_dv(SPoint2,SPoint2,SPoint2); double J(SPoint2,SPoint2,SPoint2); - double dJ_dp1x(SPoint2,SPoint2,SPoint2); - double dJ_dp2x(SPoint2,SPoint2,SPoint2); - double dJ_dp3x(SPoint2,SPoint2,SPoint2); - double dJ_dp1y(SPoint2,SPoint2,SPoint2); - double dJ_dp2y(SPoint2,SPoint2,SPoint2); - double dJ_dp3y(SPoint2,SPoint2,SPoint2); SVector3 inner_dFdx0(SVector3,SPoint2,SPoint2,SPoint2,SPoint2); SVector3 boundary_dFdx0(SVector3,SPoint2,SPoint2,SPoint2,SVector3); - double exp(double,int); - - SVector3 normal(SPoint2,SPoint2); - SPoint2 mid(SPoint2,SPoint2); - void print_segment(SPoint2,SPoint2,std::ofstream&); - bool adjacent(const DocRecord&,int,int); - double triangle_area(SPoint2,SPoint2,SPoint2); - SPoint2 boundary_intersection(SPoint2,SPoint2,bool&,SVector3&); - bool inside_domain(double,double); - int get_number_boundary_edges(); - boundary_edge get_boundary_edge(int); - SPoint2 intersection(SPoint2,SPoint2,SPoint2,SPoint2,bool&); }; -class boundary_edge{ +class voronoi_vertex{ private : - SPoint2 p1; - SPoint2 p2; + SPoint2 point; + int index1; + int index2; + int index3; + SVector3 normal; + bool duplicate; public : - boundary_edge(SPoint2,SPoint2); - boundary_edge(); - ~boundary_edge(); - SPoint2 get_p1(); - SPoint2 get_p2(); + voronoi_vertex(SPoint2); + voronoi_vertex(); + ~voronoi_vertex(); + SPoint2 get_point(); + int get_index1(); + int get_index2(); + int get_index3(); + SVector3 get_normal(); + bool get_duplicate(); + void set_point(SPoint2); + void set_index1(int); + void set_index2(int); + void set_index3(int); + void set_normal(SVector3); + void set_duplicate(bool); }; -#endif +class voronoi_element{ + private : + voronoi_vertex v1; + voronoi_vertex v2; + voronoi_vertex v3; + public : + voronoi_element(voronoi_vertex,voronoi_vertex,voronoi_vertex); + voronoi_element(); + ~voronoi_element(); + voronoi_vertex get_v1(); + voronoi_vertex get_v2(); + voronoi_vertex get_v3(); + void set_v1(voronoi_vertex); + void set_v2(voronoi_vertex); + void set_v3(voronoi_vertex); +}; + +class voronoi_cell{ + private : + std::vector<voronoi_vertex> vertices; + public : + voronoi_cell(); + ~voronoi_cell(); + int get_number_vertices(); + voronoi_vertex get_vertex(int); + void add_vertex(voronoi_vertex); + void clear(); +}; + +class segment{ + private : + int index1; + int index2; + int reference; + public : + segment(int,int,int); + segment(); + ~segment(); + int get_index1(); + int get_index2(); + int get_reference(); + void set_index1(int); + void set_index2(int); + void set_reference(int); + bool equal(int,int); +}; + +class segment_list{ + private : + std::vector<segment> segments; + public : + segment_list(); + ~segment_list(); + int get_number_segments(); + segment get_segment(int); + bool add_segment(int,int,int); + bool add_segment(segment); +}; + +class metric{ + private : + double a,b,c,d; + public : + metric(double,double,double,double); + metric(); + ~metric(); + void set_a(double); + void set_b(double); + void set_c(double); + void set_d(double); + double get_a(); + double get_b(); + double get_c(); + double get_d(); +}; + +class wrapper{ + private : + int p; + int dimension; + GFace* gf; + int iteration; + int max; + double start; + DocRecord* triangulator; + MElementOctree* octree; + public : + wrapper(); + ~wrapper(); + int get_p(); + void set_p(int); + int get_dimension(); + void set_dimension(int); + GFace* get_face(); + void set_face(GFace*); + int get_iteration(); + void set_iteration(int); + int get_max(); + void set_max(int); + double get_start(); + void set_start(double); + DocRecord* get_triangulator(); + void set_triangulator(DocRecord*); + MElementOctree* get_octree(); + void set_octree(MElementOctree*); +}; #endif diff --git a/Numeric/DivideAndConquer.cpp b/Numeric/DivideAndConquer.cpp index 8071ad32d1..c00acdd004 100644 --- a/Numeric/DivideAndConquer.cpp +++ b/Numeric/DivideAndConquer.cpp @@ -1,4 +1,4 @@ -// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle +// Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle // // See the LICENSE.txt file for license information. Please report all // bugs and problems to <gmsh@geuz.org>. @@ -27,6 +27,7 @@ #define Pred(x) ((x)->prev) #define Succ(x) ((x)->next) + PointNumero DocRecord::Predecessor(PointNumero a, PointNumero b) { DListPeek p = points[a].adjacent; @@ -835,7 +836,7 @@ DocRecord::~DocRecord() for(int i = 0; i < numPoints; i++) delete [] _adjacencies[i].t; delete _adjacencies; - } + } } void DocRecord::MakeMeshWithPoints() @@ -843,7 +844,7 @@ void DocRecord::MakeMeshWithPoints() if(numPoints < 3) return; BuildDelaunay(); ConvertDListToTriangles(); - RemoveAllDList(); + //RemoveAllDList(); } void DocRecord::Voronoi() @@ -853,79 +854,150 @@ void DocRecord::Voronoi() ConvertDListToVoronoiData(); } -void DocRecord::recur_tag_triangles (int iTriangle, - std::set<int> &taggedTriangles, - std::map< std::pair<void*,void*>, std::pair<int,int> > & edgesToTriangles){ +void DocRecord::setPoints(fullMatrix<double> *p) +{ + if (numPoints != p->size1())throw; + for (int i = 0; i < p->size1(); i++){ + x(i) = (*p)(i, 0); + y(i) = (*p)(i, 1); + data(i) = (*p)(i, 2) < 0 ? (void *) 1 : NULL; + } +} - if (taggedTriangles.find(iTriangle) != taggedTriangles.end())return; - +void DocRecord::recur_tag_triangles(int iTriangle,std::set<int>& taggedTriangles,std::map<std::pair<void*,void*>,std::pair<int,int> >& edgesToTriangles){ + if(taggedTriangles.find(iTriangle)!=taggedTriangles.end()) return; + taggedTriangles.insert(iTriangle); - + int a = triangles[iTriangle].a; int b = triangles[iTriangle].b; int c = triangles[iTriangle].c; - PointRecord *p[3] = {&points[a],&points[b],&points[c]}; - - for (int j=0;j<3;j++){ - if (!lookForBoundaryEdge(p[j]->data,p[(j+1)%3]->data)){ - std::pair<void*,void*> ab = std::make_pair(std::min(p[j]->data,p[(j+1)%3]->data),std::max(p[j]->data,p[(j+1)%3]->data)); - std::pair<int,int> & adj = edgesToTriangles[ab]; - if (iTriangle == adj.first && adj.second != -1)recur_tag_triangles(adj.second, taggedTriangles, edgesToTriangles); - else recur_tag_triangles(adj.first, taggedTriangles, edgesToTriangles); - } + PointRecord* p[3] = {&points[a],&points[b],&points[c]}; + + for(int j=0;j<3;j++){ + if(!lookForBoundaryEdge(p[j]->data,p[(j+1)%3]->data)){ + std::pair<void*,void*> ab = std::make_pair(std::min(p[j]->data,p[(j+1)%3]->data),std::max(p[j]->data,p[(j+1)%3]->data)); + std::pair<int,int>& adj = (edgesToTriangles.find(ab))->second; + if(iTriangle==adj.first && adj.second!=-1) recur_tag_triangles(adj.second,taggedTriangles,edgesToTriangles); + else recur_tag_triangles(adj.first,taggedTriangles,edgesToTriangles); + } } } - -std::set<int> DocRecord::tagInterior (double x, double y){ - std::map< std::pair<void*,void*>, std::pair<int,int> > edgesToTriangles; +std::set<int> DocRecord::tagInterior(double x,double y){ + std::map<std::pair<void*,void*>,std::pair<int,int> > edgesToTriangles; int iFirst = 1; - for (int i=0;i<numTriangles;i++){ + for(int i=0;i<numTriangles;i++){ int a = triangles[i].a; - int b = triangles[i].b; - int c = triangles[i].c; - PointRecord *p[3] = {&points[a],&points[b],&points[c]}; - - // TODO : regarde quel triangle contient x y et retiens le dans iFirst; - - for (int j=0;j<3;j++){ - std::pair<void*,void*> ab = std::make_pair(std::min(p[j]->data,p[(j+1)%3]->data),std::max(p[j]->data,p[(j+1)%3]->data)); - std::map< std::pair<void*,void*>, std::pair<int,int> > :: iterator it = edgesToTriangles.find(ab); - if (it == edgesToTriangles.end()){ - edgesToTriangles[ab] = std::make_pair(i,-1); - } - else { - it->second.second = i; - } - } + int b = triangles[i].b; + int c = triangles[i].c; + PointRecord* p[3] = {&points[a],&points[b],&points[c]}; + + //Weisstein, Eric W. "Triangle Interior." From MathWorld--A Wolfram Web Resource. + double x0 = points[a].where.h; + double y0 = points[a].where.v; + double x1 = points[b].where.h - points[a].where.h; + double y1 = points[b].where.v - points[a].where.v; + double x2 = points[c].where.h - points[a].where.h; + double y2 = points[c].where.v - points[a].where.v; + double k1 = ((x*y2-x2*y)-(x0*y2-x2*y0))/(x1*y2-x2*y1); + double k2 = -((x*y1-x1*y)-(x0*y1-x1*y0))/(x1*y2-x2*y1); + if(k1>0.0 && k2>0.0 && k1+k2<1.0) iFirst = i; + + for(int j=0;j<3;j++){ + std::pair<void*,void*> ab = std::make_pair(std::min(p[j]->data,p[(j+1)%3]->data),std::max(p[j]->data,p[(j+1)%3]->data)); + std::map<std::pair<void*,void*>,std::pair<int,int> >::iterator it = edgesToTriangles.find(ab); + if(it==edgesToTriangles.end()){ + edgesToTriangles[ab] = std::make_pair(i,-1); + } + else{ + it->second.second = i; + } + } } - std::set<int> taggedTriangles; - recur_tag_triangles (iFirst, taggedTriangles, edgesToTriangles); + recur_tag_triangles(iFirst,taggedTriangles,edgesToTriangles); return taggedTriangles; } +void DocRecord::concave(double x,double y,GFace* gf){ + int i; + int index1; + int index2; + int index3; + GEdge* edge; + MElement* element; + MVertex* vertex1; + MVertex* vertex2; + std::list<GEdge*> list; + std::list<GEdge*>::iterator it1; + std::set<int> set; + std::set<int>::iterator it2; + + list = gf->edges(); + for(it1=list.begin();it1!=list.end();it1++){ + edge = *it1; + for(i=0;i<edge->getNumMeshElements();i++){ + element = edge->getMeshElement(i); + vertex1 = element->getVertex(0); + vertex2 = element->getVertex(1); + addBoundaryEdge(vertex1,vertex2); + } + } -void DocRecord::setPoints(fullMatrix<double> *p) -{ - if (numPoints != p->size1())throw; - for (int i = 0; i < p->size1(); i++){ - x(i) = (*p)(i, 0); - y(i) = (*p)(i, 1); - data(i) = (*p)(i, 2) < 0 ? (void *) 1 : NULL; + for(i=0;i<numPoints;i++){ + points[i].vicinity.clear(); } -} + + MakeMeshWithPoints(); + set = tagInterior(x,y); + for(it2=set.begin();it2!=set.end();it2++){ + index1 = triangles[*it2].a; + index2 = triangles[*it2].b; + index3 = triangles[*it2].c; + + add(index1,index2); + add(index1,index3); + + add(index2,index1); + add(index2,index3); + + add(index3,index1); + add(index3,index2); + } +} -void DocRecord::initialize() -{ +bool DocRecord::contain(int index1,int index2,int index3){ int i; - for(i = 0; i < numPoints; i++){ - points[i].flag = 0; + void* dataA; + void* dataB; + dataA = points[index2].data; + dataB = points[index3].data; + for(i=0;i<points[index1].vicinity.size()-1;i=i+2){ + if(points[index1].vicinity[i]==dataA && points[index1].vicinity[i+1]==dataB){ + return 1; + } + else if(points[index1].vicinity[i]==dataB && points[index1].vicinity[i+1]==dataA){ + return 1; + } } + return 0; } -bool DocRecord::remove_point(int index) -{ +void DocRecord::add(int index1,int index2){ + void* data; + data = points[index2].data; + points[index1].vicinity.push_back(data); +} + +void DocRecord::initialize(){ + int i; + for(i=0;i<numPoints;i++){ + points[i].flag = 0; + } +} + +bool DocRecord::remove_point(int index){ if(points[index].flag == 0){ points[index].flag = 1; return 1; @@ -933,37 +1005,35 @@ bool DocRecord::remove_point(int index) else return 0; } -void DocRecord::remove_all() -{ +void DocRecord::remove_all(){ int i; int index; int numPoints2; PointRecord* points2; numPoints2 = 0; for(i=0;i<numPoints;i++){ - if(points[i].flag == 0){ + if(points[i].flag==0){ numPoints2++; } } points2 = new PointRecord[numPoints2]; index = 0; - for(i = 0; i < numPoints; i++){ - if(points[i].flag==0){ - points2[index].where.h = points[i].where.h; - points2[index].where.v = points[i].where.v; - points2[index].data = points[i].data; - points2[index].flag = points[i].flag; - points2[index].identificator = points[i].identificator; - index++; - } + for(i=0;i<numPoints;i++){ + if(points[i].flag==0){ + points2[index].where.h = points[i].where.h; + points2[index].where.v = points[i].where.v; + points2[index].data = points[i].data; + points2[index].flag = points[i].flag; + points2[index].identificator = points[i].identificator; + index++; + } } delete [] points; points = points2; numPoints = numPoints2; } -void DocRecord::add_point(double x,double y,GFace*face) -{ +void DocRecord::add_point(double x,double y,GFace*face){ PointRecord point; point.where.h = x; point.where.v = y; @@ -972,3 +1042,50 @@ void DocRecord::add_point(double x,double y,GFace*face) numPoints = numPoints+1; } +void DocRecord::build_edges(){ + int i; + int j; + int num; + int index; + MVertex* vertex1; + MVertex* vertex2; + + for(i=0;i<numPoints;i++){ + vertex1 = (MVertex*)points[i].data; + num = _adjacencies[i].t_length; + for(j=0;j<num;j++){ + index = _adjacencies[i].t[j]; + vertex2 = (MVertex*)points[index].data; + add_edge(vertex1,vertex2); + } + } +} + +void DocRecord::clear_edges(){ + mesh_edges.clear(); +} + +bool DocRecord::delaunay_conformity(GFace* gf){ + int i; + bool flag; + GEdge* edge; + MElement* element; + MVertex* vertex1; + MVertex* vertex2; + std::list<GEdge*> list; + std::list<GEdge*>::iterator it; + + list = gf->edges(); + for(it=list.begin();it!=list.end();it++){ + edge = *it; + for(i=0;i<edge->getNumMeshElements();i++){ + element = edge->getMeshElement(i); + vertex1 = element->getVertex(0); + vertex2 = element->getVertex(1); + flag = find_edge(vertex1,vertex2); + if(!flag) return 0; + } + } + return 1; +} + \ No newline at end of file diff --git a/Numeric/DivideAndConquer.h b/Numeric/DivideAndConquer.h index a04b72cbb2..c26ff04f4a 100644 --- a/Numeric/DivideAndConquer.h +++ b/Numeric/DivideAndConquer.h @@ -1,4 +1,4 @@ -// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle +// Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle // // See the LICENSE.txt file for license information. Please report all // bugs and problems to <gmsh@geuz.org>. @@ -15,6 +15,7 @@ #include "simpleFunction.h" #include "Octree.h" +class binding; class GFace; typedef struct _CDLIST DListRecord, *DListPeek; typedef int PointNumero; @@ -30,7 +31,8 @@ struct PointRecord { void *data; int flag; //0:to be kept, 1:to be removed int identificator; - PointRecord() : adjacent(0), data (0), flag(0) {} + std::vector<void*> vicinity; + PointRecord() : adjacent(0), data (0) {} }; struct _CDLIST{ @@ -89,26 +91,11 @@ class DocRecord{ PointRecord *points; // points to triangulate int numTriangles; // number of triangles Triangle *triangles; // 2D results - std::set<std::pair<void*,void*> > boundaryEdges; DocRecord(int n); double &x(int i){ return points[i].where.h; } double &y(int i){ return points[i].where.v; } void* &data(int i){ return points[i].data; } - void addBoundaryEdge (void* p1, void* p2){ - void *a = (p1 < p2) ? p1 : p2; - void *b = (p1 > p2) ? p1 : p2; - boundaryEdges.insert(std::make_pair(a,b)); - } - bool lookForBoundaryEdge(void *p1, void* p2){ - void *a = (p1 < p2) ? p1 : p2; - void *b = (p1 > p2) ? p1 : p2; - std::set<std::pair<void*,void*> >::iterator it = boundaryEdges.find(std::make_pair(a,b)); - return it != boundaryEdges.end(); - } - void recur_tag_triangles (int iTriangle, - std::set<int> &taggedTriangles, - std::map< std::pair<void*,void*>, std::pair<int,int> > & edgesToTriangles); - void setPoints(fullMatrix<double> *p); + void setPoints(fullMatrix<double> *p); ~DocRecord(); void MakeMeshWithPoints(); void Voronoi (); @@ -118,12 +105,53 @@ class DocRecord{ void printMedialAxis(Octree *_octree, std::string, GFace *gf=NULL, GEdge *ge=NULL); double Lloyd (int); void voronoiCell (PointNumero pt, std::vector<SPoint2> &pts) const; + + std::set<std::pair<void*,void*> > boundaryEdges; + + void addBoundaryEdge(void* p1,void* p2){ + void* a = (p1 < p2) ? p1 : p2; + void* b = (p1 > p2) ? p1 : p2; + boundaryEdges.insert(std::make_pair(a,b)); + } + + bool lookForBoundaryEdge(void* p1,void* p2){ + void* a = (p1 < p2) ? p1 : p2; + void* b = (p1 > p2) ? p1 : p2; + std::set<std::pair<void*,void*> >::iterator it = boundaryEdges.find(std::make_pair(a,b)); + return it!=boundaryEdges.end(); + } + + void recur_tag_triangles(int,std::set<int>&,std::map<std::pair<void*,void*>,std::pair<int,int> >&); + std::set<int> tagInterior(double,double); + void concave(double,double,GFace*); + bool contain(int,int,int); + void add(int,int); + void initialize(); bool remove_point(int); void remove_all(); void add_point(double,double,GFace*); + + std::set<std::pair<void*,void*> > mesh_edges; + + void add_edge(void* p1,void* p2){ + void* a = (p1 < p2) ? p1 : p2; + void* b = (p1 > p2) ? p1 : p2; + mesh_edges.insert(std::make_pair(a,b)); + } + + bool find_edge(void* p1,void* p2){ + void* a = (p1 < p2) ? p1 : p2; + void* b = (p1 > p2) ? p1 : p2; + std::set<std::pair<void*,void*> >::iterator it = mesh_edges.find(std::make_pair(a,b)); + return it!=mesh_edges.end(); + } + + void build_edges(); + void clear_edges(); + bool delaunay_conformity(GFace*); + PointNumero *ConvertDlistToArray(DListPeek *dlist, int *n); - std::set<int> tagInterior (double x, double y); }; void centroidOfOrientedBox(std::vector<SPoint2> &pts, diff --git a/Plugin/Distance.cpp b/Plugin/Distance.cpp index 817d0ae4c2..345e74b4a9 100644 --- a/Plugin/Distance.cpp +++ b/Plugin/Distance.cpp @@ -190,7 +190,6 @@ PView *GMSH_DistancePlugin::execute(PView *v) return view; } - std::map<MVertex*,double > _distance_map; std::vector<SPoint3> pts; std::vector<double> distances; std::vector<MVertex* > pt2Vertex; diff --git a/Plugin/Distance.h b/Plugin/Distance.h index 70b2d0adea..14b13b226d 100644 --- a/Plugin/Distance.h +++ b/Plugin/Distance.h @@ -26,6 +26,7 @@ class GMSH_DistancePlugin : public GMSH_PostPlugin int _maxDim; PViewDataList *_data; public: + std::map<MVertex*,double > _distance_map; GMSH_DistancePlugin(); std::string getName() const { return "Distance"; } std::string getShortHelp() const -- GitLab