From 514669beaf7438b352702e5d19e1381b5eb7e7ff Mon Sep 17 00:00:00 2001
From: Tristan Carrier Baudouin <tristan.carrier@uclouvain.be>
Date: Mon, 8 Oct 2012 15:17:30 +0000
Subject: [PATCH] 3D fields

---
 Mesh/directions3D.cpp | 124 +++++++++++++++++++++++++++++++++++++++---
 Mesh/directions3D.h   |   3 +
 2 files changed, 120 insertions(+), 7 deletions(-)

diff --git a/Mesh/directions3D.cpp b/Mesh/directions3D.cpp
index ca7bcab8f1..c5d155d59f 100644
--- a/Mesh/directions3D.cpp
+++ b/Mesh/directions3D.cpp
@@ -451,9 +451,7 @@ GRegion* Frame_field::test(){
 }
 
 void Frame_field::clear(){
-  #if defined(HAVE_ANN)
   Nearest_point::clear();	
-  #endif
   field.clear();
   random.clear();
   #if defined(HAVE_ANN)
@@ -670,12 +668,13 @@ void Nearest_point::init_region(GRegion* gr){
   fullMatrix<double> gauss_points;
   fullVector<double> gauss_weights;
 	
-  gaussIntegration::getTriangle(12,gauss_points,gauss_weights);
+  gaussIntegration::getTriangle(8,gauss_points,gauss_weights);
   gauss_num = gauss_points.size1();	
 	
   faces = gr->faces();
 	
   random.clear();
+  vicinity.clear();
   vertices.clear();
 	
   for(it=faces.begin();it!=faces.end();it++){
@@ -704,6 +703,7 @@ void Nearest_point::init_region(GRegion* gr){
 		z = T(u,v,z1,z2,z3);
 		
 		random.push_back(SPoint3(x,y,z));
+		vicinity.push_back(element);
 	  }
 		
 	  vertices.insert(element->getVertex(0));
@@ -716,7 +716,8 @@ void Nearest_point::init_region(GRegion* gr){
 	x = (*it2)->x();
 	y = (*it2)->y();
 	z = (*it2)->z();
-    random.push_back(SPoint3(x,y,z));
+    //random.push_back(SPoint3(x,y,z));
+	//vicinity.push_back(NULL);
   }
 	
   duplicate = annAllocPts(random.size(),3);
@@ -757,9 +758,15 @@ bool Nearest_point::search(double x,double y,double z,SVector3& vec){
   annDeallocPt(query);
   delete[] indices;
   delete[] distances;
-  	
-  e2 = 0.000001;
-  point = random[index];
+
+  if(vicinity[index]!=NULL){
+	point = closest(vicinity[index],SPoint3(x,y,z));
+  }
+  else{
+    point = random[index];
+  }
+	
+  e2 = 0.000001;	
 	
   if(fabs(point.x()-x)>e2 || fabs(point.y()-y)>e2 || fabs(point.z()-z)>e2){
     vec = SVector3(point.x()-x,point.y()-y,point.z()-z);
@@ -779,6 +786,107 @@ double Nearest_point::T(double u,double v,double val1,double val2,double val3){
   return (1.0-u-v)*val1 + u*val2 + v*val3;
 }
 
+//The following method comes from this page : gamedev.net/topic/552906-closest-point-on-triangle
+//It can also be found on this page : geometrictools.com/LibMathematics/Distance/Distance.html
+SPoint3 Nearest_point::closest(MElement* element,SPoint3 point){		
+  SVector3 edge0 = SVector3(element->getVertex(1)->x()-element->getVertex(0)->x(),element->getVertex(1)->y()-element->getVertex(0)->y(),
+							element->getVertex(1)->z()-element->getVertex(0)->z());
+  SVector3 edge1 = SVector3(element->getVertex(2)->x()-element->getVertex(0)->x(),element->getVertex(2)->y()-element->getVertex(0)->y(),
+							element->getVertex(2)->z()-element->getVertex(0)->z());
+  SVector3 v0 = SVector3(element->getVertex(0)->x()-point.x(),element->getVertex(0)->y()-point.y(),
+						 element->getVertex(0)->z()-point.z());
+	
+  double a = dot(edge0,edge0);
+  double b = dot(edge0,edge1);
+  double c = dot(edge1,edge1);
+  double d = dot(edge0,v0);
+  double e = dot(edge1,v0);
+		
+  double det = a*c-b*b;
+  double s = b*e-c*d;
+  double t = b*d-a*e;
+		
+  if(s+t<det){
+    if(s<0.0){
+	  if(t<0.0){
+	    if(d<0.0){
+		  s = clamp(-d/a,0.0,1.0);
+		  t = 0.0;
+		}
+		else{
+		  s = 0.0;
+		  t = clamp(-e/c,0.0,1.0);
+		}
+	  }
+	  else{
+	    s = 0.0;
+		t = clamp(-e/c,0.0,1.0);
+	  }
+	}
+	else if(t<0.0){
+	  s = clamp(-d/a,0.0,1.0);
+	  t = 0.0;
+	}
+	else{
+	  double invDet = 1.0/det;
+	  s *= invDet;
+	  t *= invDet;
+	}
+  }
+  else{
+    if(s<0.0){
+	  double tmp0 = b+d;
+	  double tmp1 = c+e;
+	  if(tmp1>tmp0){
+	    double numer = tmp1-tmp0;
+		double denom = a-2.0*b+c;
+		s = clamp(numer/denom,0.0,1.0);
+		t = 1.0-s;
+	  }
+	  else{
+	    t = clamp(-e/c,0.0,1.0);
+		s = 0.0;
+	  }
+	}
+	else if(t<0.0){
+	  if(a+d>b+e){
+	    double numer = c+e-b-d;
+		double denom = a-2.0*b+c;
+		s = clamp(numer/denom,0.0,1.0);
+		t = 1.0-s;
+	  }
+	  else{
+	    s = clamp(-e/c,0.0,1.0);
+		t = 0.0;
+	  }
+	}
+	else{
+	  double numer = c+e-b-d;
+	  double denom = a-2.0*b+c;
+	  s = clamp(numer/denom,0.0,1.0);
+	  t = 1.0-s;
+	}
+  }
+		
+  return SPoint3(element->getVertex(0)->x()+s*edge0.x()+t*edge1.x(),element->getVertex(0)->y()+s*edge0.y()+t*edge1.y(),
+				 element->getVertex(0)->z()+s*edge0.z()+t*edge1.z());
+}
+
+double Nearest_point::clamp(double x,double min,double max){
+  double val;
+	
+  val = x;
+  
+  if(val<min){
+    val = min;
+  }
+  else if(val>max){
+    val = max;
+  }
+	
+  return val;
+}
+
 void Nearest_point::print_field(GRegion* gr){
   unsigned int i;
   int j;
@@ -828,6 +936,7 @@ GRegion* Nearest_point::test(){
 
 void Nearest_point::clear(){
   random.clear();
+  vicinity.clear();
   #if defined(HAVE_ANN)
   delete duplicate;
   delete kd_tree;
@@ -848,6 +957,7 @@ std::map<MVertex*,double> Size_field::boundary;
 MElementOctree* Size_field::octree;
 
 std::vector<SPoint3> Nearest_point::random;
+std::vector<MElement*> Nearest_point::vicinity;
 #if defined(HAVE_ANN)
 ANNpointArray Nearest_point::duplicate;
 ANNkd_tree* Nearest_point::kd_tree;
diff --git a/Mesh/directions3D.h b/Mesh/directions3D.h
index 2b583e166b..95600ab751 100644
--- a/Mesh/directions3D.h
+++ b/Mesh/directions3D.h
@@ -80,6 +80,7 @@ class Size_field{
 class Nearest_point{
  private:
   static std::vector<SPoint3> random;
+  static std::vector<MElement*> vicinity;
   #if defined(HAVE_ANN)
   static ANNpointArray duplicate;
   static ANNkd_tree* kd_tree;
@@ -89,6 +90,8 @@ class Nearest_point{
   static void init_region(GRegion*);
   static bool search(double,double,double,SVector3&);
   static double T(double,double,double,double,double);
+  static SPoint3 closest(MElement*,SPoint3);
+  static double clamp(double,double,double);
   static void print_field(GRegion*);
   static void print_segment(SPoint3,SPoint3,std::ofstream&);
   static GRegion* test();
-- 
GitLab