From ad5ce44d882e7c610a06465dd41992171c30694f Mon Sep 17 00:00:00 2001
From: Tristan Carrier Baudouin <tristan.carrier@uclouvain.be>
Date: Fri, 21 Jan 2011 14:37:03 +0000
Subject: [PATCH] lloyds algorithm in l1 metric

---
 Mesh/meshGFaceLloyd.cpp | 342 ++++++++++++++++++++++++++++++++++++++--
 Mesh/meshGFaceLloyd.h   |  20 ++-
 2 files changed, 350 insertions(+), 12 deletions(-)

diff --git a/Mesh/meshGFaceLloyd.cpp b/Mesh/meshGFaceLloyd.cpp
index 8fc7b94872..a54fed9a2c 100644
--- a/Mesh/meshGFaceLloyd.cpp
+++ b/Mesh/meshGFaceLloyd.cpp
@@ -9,7 +9,19 @@
 #include "meshGFace.h"
 #include "BackgroundMesh.h"
 
-void lloydAlgorithm::operator () (GFace *gf)
+/*List of parameters to modify*/
+//Line 76 : the variable "number" contains the number of points to remove.
+//Line 165 : the variable "test" is printed by the script.
+//Line 190 : the variable "angle" specifies the orientation of the mesh.
+//Line 287 : the variable "num" contains the number of iteration of the bisection method
+//used to find the fixed point.
+//Line 447 : it is the function "optimize" that needs to be called by the script.
+//Line 455 : put "lloyd(face)" in commentary to avoid calling the l1 lloyds method.
+//Line 456 : put "recombineIntoQuads(face,1,1)" in commentary to avoid calling the quad 
+//meshing method.
+//Line 461 : the code below line 461 refers to Lua and might need to be removed.
+
+void lloydAlgorithm::operator () (GFace *gf) 
 {
   std::set<MVertex*> all;
 
@@ -57,6 +69,26 @@ void lloydAlgorithm::operator () (GFace *gf)
     triangulator.data(i++) = (*it);
   }
  
+  triangulator.Voronoi();
+  triangulator.initialize();
+  int index,number,count,max;
+  bool recent;
+  number = 0; //This variable contains the number of points to remove.
+  count = 0;
+  max = 100000;
+  for(int i=0;i<max;i++)
+  {
+    if(count>=number) break;
+	index = (int)((triangulator.numPoints-1)*((double)rand()/(double)RAND_MAX));
+	PointRecord& pt = triangulator.points[index];
+	MVertex* v = (MVertex*)pt.data;
+	if(v->onWhat()==gf && !triangulator.onHull(index)){
+	  recent = triangulator.remove_point(index);
+	  if(recent) count++;
+	}
+  }
+  triangulator.remove_all();
+	
   // compute the Voronoi diagram
   triangulator.Voronoi();
   //printf("hullSize = %d\n",triangulator.hullSize());
@@ -81,12 +113,13 @@ void lloydAlgorithm::operator () (GFace *gf)
         triangulator.voronoiCell (i,pts); 
         double E, A;
         SPoint2 p(pt.where.h,pt.where.v);
-        if (!infiniteNorm){
-          centroidOfPolygon (p,pts, cgs(i,0),cgs(i,1),E, A, NULL); //backgroundMesh::current());       
-        }
-        else {
-          centroidOfOrientedBox (pts, 0.0, cgs(i,0),cgs(i,1),E, A);          
-        }
+		for(int k=0;k<pts.size();k++){
+		  rotate(p,pts[k]);
+		}
+		SPoint2 point = fixed_point(pts); //Fixed point for quad mesh generation
+		unrotate(p,point);
+		cgs(i,0) = point.x();
+		cgs(i,1) = point.y();
         ENERGY += E;
 	double d = sqrt((p.x()-cgs(i,0))*(p.x()-cgs(i,0))+
 			(p.y()-cgs(i,1))*(p.y()-cgs(i,1)));
@@ -117,8 +150,9 @@ void lloydAlgorithm::operator () (GFace *gf)
       triangulator.makePosView(name);
     }
   }
-
+	
   // now create the vertices
+  test = 0;
   std::vector<MVertex*> mesh_vertices;
   for (int i=0; i<triangulator.numPoints;i++){
     // get the ith vertex
@@ -127,7 +161,8 @@ void lloydAlgorithm::operator () (GFace *gf)
     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);
+	  mesh_vertices.push_back(v);
+	  test++;
     }
   }
 
@@ -147,5 +182,290 @@ void lloydAlgorithm::operator () (GFace *gf)
                            gf->_additional_vertices.begin(),  
                            gf->_additional_vertices.end());  
   // clear the list of additional vertices
-  gf->_additional_vertices.clear();  
-} 
+  gf->_additional_vertices.clear();
+}
+
+double lloydAlgorithm::get_angle(double x,double y){
+  double angle;
+  angle = M_PI/4.0; //This variable specifies the orientation of the mesh.
+  return angle;
+}
+
+//This function returns the a, b, c and d components of the rotation matrix.
+void lloydAlgorithm::get_rotation(double x,double y,double& a,double& b,double& c,double& d){
+  double angle;
+  angle = get_angle(x,y);
+  a = cos(angle);
+  b = -sin(angle);
+  c = sin(angle);
+  d = cos(angle);
+}
+
+//This function returns the a, b, c and d components of the inverse rotation matrix.
+void lloydAlgorithm::get_unrotation(double x,double y,double& _a,double& _b,double& _c,double& _d){
+  double a,b,c,d;
+  double det;
+  get_rotation(x,y,a,b,c,d);
+  det = 1.0/(a*d-b*c);
+  _a = d/det;
+  _b = -b/det;
+  _c = -c/det;
+  _d = a/det;
+}
+
+//This function rotates a vertice (point) belonging to a Voronoi cell.
+//The angle is specified by the location of the generator, because we want all vertices
+//of the Voronoi cell to be rotated by the same amount in case the orientation of the
+//mesh is not constant.
+//The generator itself is not rotated.
+void lloydAlgorithm::rotate(SPoint2 generator,SPoint2& point){
+  double x,y;
+  double new_x,new_y;
+  double a,b,c,d;
+  get_rotation(generator.x(),generator.y(),a,b,c,d);
+  x = point.x();
+  y = point.y();
+  new_x = a*x + b*y;
+  new_y = c*x + d*y;
+  point.setPosition(new_x,new_y);
+}
+
+//This function rotates a vertice (point) belonging to a Voronoi cell in the reverse direction.
+//The angle is specified by the location of the generator, because we want all vertices
+//of the Voronoi cell to be rotated by the same amount in case the orientation of the
+//mesh is not constant.
+//The generator itself is not rotated.
+void lloydAlgorithm::unrotate(SPoint2 generator,SPoint2& point){
+  double x,y;
+  double new_x,new_y;
+  double a,b,c,d;
+  get_unrotation(generator.x(),generator.y(),a,b,c,d);
+  x = point.x();
+  y = point.y();
+  new_x = a*x + b*y;
+  new_y = c*x + d*y;
+  point.setPosition(new_x,new_y);
+}
+
+//This function returns the fixed point of the voronoi cell specified in argument (polygon).
+//It finds the bounding box of the voronoi cell and then it calls the function range in x and y.
+SPoint2 lloydAlgorithm::fixed_point(const std::vector<SPoint2>& polygon){
+  int i,num;
+  double x,y;
+  double x_min,y_min;
+  double x_max,y_max;
+  double solution_x,solution_y;
+  SPoint2 point;
+  x_min = 100000000.0;
+  y_min = 100000000.0;
+  x_max = -100000000.0;
+  y_max = -100000000.0;
+  num = polygon.size();
+  for(i=0;i<num;i++){
+	point = polygon[i];
+    x = point.x();
+	y = point.y();
+	if(x < x_min) x_min = x;
+	if(y < y_min) y_min = y;
+	if(x > x_max) x_max = x;
+	if(y > y_max) y_max = y;
+  }
+  solution_x = range(polygon,x_min,x_max,1);
+  solution_y = range(polygon,y_min,y_max,0);
+  return SPoint2(solution_x,solution_y);
+}
+
+//This function returns the x or y median of the Voronoi cell specified in argument (polygon).
+//If direction = 1, the function will return the x median.
+//If direction = 0, the function will return the y median.
+//The variables u1 and u2 should be respectively equal to the minimum and the maximum of x or y,
+//depending of the value of direction.
+//This function uses the bisection method.
+double lloydAlgorithm::range(const std::vector<SPoint2>& polygon,double u1,double u2,bool direction){
+  int i,num;
+  double mid,val;
+  num = 16; //This variable specifies the number of iteration of the bisection method.
+  for(i=0;i<num;i++){
+	mid = 0.5*(u1 + u2);
+	val = gradient(polygon,mid,direction);
+	if(val >= 0) u2 = mid;
+	else u1 = mid;
+  }
+  return 0.5*(u1 + u2);
+}
+
+//This function returns the x or y component of the l1 gradient of the voronoi cell
+//specified in argument (polygon).
+//If direction = 1, it will return the x component.
+//If direction = 0, it will return the y component.
+//The variable generator should be equal to the x or y component of the point to which the 
+//voronoi cell belongs.
+//x component = A1-A2, A1 : area of the left part, A2 : area of the right part
+//y component = A3-A4, A3 : area of the lower part, A4 : area of the higher part
+double lloydAlgorithm::gradient(const std::vector<SPoint2>& polygon,double generator,bool direction){
+  int i,num,index1,index2;
+  bool intersection,side;
+  double areaA,areaB;
+  SPoint2 p1,p2,solution;
+  std::vector<bool> category;
+  std::vector<SPoint2> new_polygon;
+  std::vector<SPoint2> polygonA;
+  std::vector<SPoint2> polygonB;
+  num = polygon.size();
+  for(i=0;i<num;i++){
+	index1 = i;
+	index2 = (i+1)%num;
+	p1 = polygon[index1];
+	p2 = polygon[index2];
+	solution = line_intersection(p1,p2,generator,direction,intersection);
+	if(intersection){
+	  new_polygon.push_back(p1);
+	  new_polygon.push_back(solution);
+	  category.push_back(1);
+	  category.push_back(0);	
+	}
+	else{
+	  new_polygon.push_back(p1);
+	  category.push_back(1);	
+	}
+  }
+  num = new_polygon.size();
+  for(i=0;i<num;i++){
+	if(category[i]){
+	  side = point_side(new_polygon[i],generator,direction);
+	  if(side){
+	    polygonA.push_back(new_polygon[i]);
+	  }
+	  else{
+	    polygonB.push_back(new_polygon[i]);
+	  }
+	}
+	else{
+	  polygonA.push_back(new_polygon[i]);
+	  polygonB.push_back(new_polygon[i]);
+	}
+  }
+  areaA = polygon_area(polygonA);
+  areaB = polygon_area(polygonB);
+  return areaA-areaB;
+}
+
+//The point p is a vertice of a Voronoi cell.
+//The variable generator contains the x or y component of the point to which
+//the Voronoi cell belongs. If direction = 1, it will contain the x component,
+//if direction = 0, it will contain the y component.
+//If direction = 1, this function will return 1 if p is at the left of the generator
+//and it will return 0 if p is at the right of the generator.
+//If direction = 0, this function will return 1 if p is below the generator
+//and it will return 0 if p is higher than the generator.
+bool lloydAlgorithm::point_side(SPoint2 p,double generator,bool direction){
+  if(direction){
+    if(p.x()<=generator) return 1;
+	else return 0;
+  }
+  else{
+    if(p.y()<=generator) return 1;
+	else return 0;
+  }
+}
+
+//This function uses the Surveyors Formula to calculate the area of the Voronoi cell
+//specified in argument (polygon).
+double lloydAlgorithm::polygon_area(const std::vector<SPoint2>& polygon){
+  int i;
+  int num;
+  double area;
+  num = polygon.size();
+  if(num<3) return 0.0;
+  else{
+    area = 0.0;
+    for(i=0;i<num-1;i++){
+	  area = area + 0.5*(polygon[i].x()*polygon[i+1].y() - polygon[i+1].x()*polygon[i].y());
+    }
+    area = area + 0.5*(polygon[num-1].x()*polygon[0].y() - polygon[0].x()*polygon[num-1].y());
+    return fabs(area);
+  }
+}
+
+//This function determines if there is an intersection between the segment p1-p2 and the
+//infinite line passing through the generator, which is the point to which the Voronoi cell
+//belongs.
+//If there is an intersection, then the variable intersection will contain 1, otherwise it will
+//contain 0. In that case, the point that the function returns is not imporant.
+//If direction = 1, the variable generator will contain the x component, in that case,
+//the infinite line will be vertical.
+//If direction = 0, the variable generator will contain the y component, in that case,
+//the infinite line will be horizontal. 
+SPoint2 lloydAlgorithm::line_intersection(SPoint2 p1,SPoint2 p2,double generator,bool direction,bool& intersection){
+  double x1,x2,solution_x;
+  double y1,y2,solution_y;
+  double u,e;
+  x1 = p1.x();
+  y1 = p1.y();
+  x2 = p2.x();
+  y2 = p2.y();
+  e = 0.0000001;
+  intersection = 0;
+  if(direction){
+	if(fabs(x1 - generator)<e){
+	  intersection = 1;
+	  return SPoint2(x1,y1);
+	}
+	else if(fabs(x2 - generator)<e){
+	  intersection = 1;
+	  return SPoint2(x2,y2);
+	}
+	else if((x1<generator && x2>generator)||(x1>generator && x2<generator)){
+	  intersection = 1;
+	  u = (generator-x1)/(x2-x1);
+	  solution_x = generator;
+	  solution_y = y1 + u*(y2-y1);
+	  return SPoint2(solution_x,solution_y);
+	}
+  }
+  else{
+	if(fabs(y1 - generator)<e){
+	  intersection = 1;
+	  return SPoint2(x1,y1);
+	}
+	else if(fabs(y2 - generator)<e){
+	  intersection = 1;
+	  return SPoint2(x2,y2);
+	}
+	else if((y1<generator && y2>generator)||(y1>generator && y2<generator)){
+	  intersection = 1;
+	  u = (generator-y1)/(y2-y1);
+	  solution_x = x1 + u*(x2-x1);
+	  solution_y = generator;
+	  return SPoint2(solution_x,solution_y);
+	}
+  }
+  return SPoint2(0.0,0.0);
+}
+
+//This is the function called by the script.
+double lloydAlgorithm::optimize(int max,int flag){
+  GFace*face;
+  GModel*model = GModel::current();
+  GModel::fiter iterator;
+  lloydAlgorithm lloyd(max,flag);
+  for(iterator = model->firstFace();iterator != model->lastFace();iterator++)
+  {
+    face = *iterator;
+	lloyd(face);
+	recombineIntoQuads(face,1,1);
+  }
+  return lloyd.test;
+}
+
+#include "Bindings.h"
+void lloydAlgorithm::registerBindings(binding *b){
+  classBinding*cb = b->addClass<lloydAlgorithm>("lloydAlgorithm");
+  cb->setDescription("This class is used to move the points according to lloyd algorithm.");
+  methodBinding*cm;
+  cm = cb->setConstructor<lloydAlgorithm>();
+  cm->setDescription("This is the constructor.");
+  cm = cb->addMethod("optimize",&lloydAlgorithm::optimize);
+  cm->setDescription("This function moves the points.");
+  cm->setArgNames("max","flag",NULL);
+}
diff --git a/Mesh/meshGFaceLloyd.h b/Mesh/meshGFaceLloyd.h
index b560f44870..b86fd54b2a 100644
--- a/Mesh/meshGFaceLloyd.h
+++ b/Mesh/meshGFaceLloyd.h
@@ -5,16 +5,34 @@
 
 #ifndef _MESH_GFACE_LLOYD_H_
 #define _MESH_GFACE_LLOYD_H_
+#include "fullMatrix.h"
+#include "DivideAndConquer.h"
+#include "Bindings.h"
 
 class GFace;
 
 class lloydAlgorithm {
   int ITER_MAX;
-  bool infiniteNorm ;
+  bool infiniteNorm;
+  double test;
  public :
   lloydAlgorithm (int itermax, bool infnorm = false)
   : ITER_MAX(itermax), infiniteNorm(infnorm) {}
+  lloydAlgorithm() {}
   void operator () (GFace *);
+  double get_angle(double,double);
+  void get_rotation(double,double,double&,double&,double&,double&);
+  void get_unrotation(double,double,double&,double&,double&,double&);
+  void rotate(SPoint2,SPoint2&);
+  void unrotate(SPoint2,SPoint2&);
+  SPoint2 fixed_point(const std::vector<SPoint2>&);
+  double range(const std::vector<SPoint2>&,double,double,bool);
+  double gradient(const std::vector<SPoint2>&,double,bool);
+  bool point_side(SPoint2,double,bool);
+  double polygon_area(const std::vector<SPoint2>&);
+  SPoint2 line_intersection(SPoint2,SPoint2,double,bool,bool&);
+  double optimize(int,int);
+  static void registerBindings(binding *b);
 };
 
 #endif
-- 
GitLab