From 164b5be98ca29482a215f78fa2cfe01adbe02615 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Thu, 21 Nov 2013 15:09:34 +0000
Subject: [PATCH] improve reproductibility of 2D mesh algorithm (compare
 vertices and triangles by number, not by pointer)

---
 Geo/MEdge.h              | 19 +++++++-------
 Mesh/meshGFace.cpp       | 42 +++++++++++++++---------------
 Mesh/meshGFaceOptimize.h | 55 +++++++++++++++++++---------------------
 3 files changed, 56 insertions(+), 60 deletions(-)

diff --git a/Geo/MEdge.h b/Geo/MEdge.h
index 94e31eed59..86c9857c27 100644
--- a/Geo/MEdge.h
+++ b/Geo/MEdge.h
@@ -25,7 +25,7 @@ class MEdge {
   MEdge(MVertex *v0, MVertex *v1)
   {
     _v[0] = v0; _v[1] = v1;
-    if(_v[1] < _v[0]) {
+    if(_v[1]->getNum() < _v[0]->getNum()) {
       _si[0] = 1;
       _si[1] = 0;
     }
@@ -41,13 +41,13 @@ class MEdge {
   inline MVertex *getMaxVertex() const { return _v[int(_si[1])]; }
   SVector3 scaledTangent() const
   {
-    return SVector3(_v[1]->x() - _v[0]->x(), 
+    return SVector3(_v[1]->x() - _v[0]->x(),
                     _v[1]->y() - _v[0]->y(),
                     _v[1]->z() - _v[0]->z());
   }
   SVector3 tangent() const
   {
-    SVector3 t(_v[1]->x() - _v[0]->x(), 
+    SVector3 t(_v[1]->x() - _v[0]->x(),
                _v[1]->y() - _v[0]->y(),
                _v[1]->z() - _v[0]->z());
     t.normalize();
@@ -55,12 +55,12 @@ class MEdge {
   }
   double length() const
   {
-    SVector3 t(_v[1]->x() - _v[0]->x(), 
+    SVector3 t(_v[1]->x() - _v[0]->x(),
                _v[1]->y() - _v[0]->y(),
                _v[1]->z() - _v[0]->z());
     return t.norm();
   }
-  SVector3 normal() const 
+  SVector3 normal() const
   {
     // this computes one of the normals to the edge
     SVector3 t = tangent(), ex(0., 0., 0.);
@@ -98,7 +98,7 @@ inline bool operator!=(const MEdge &e1, const MEdge &e2)
   return (e1.getMinVertex() != e2.getMinVertex() ||
           e1.getMaxVertex() != e2.getMaxVertex());
 }
-  
+
 struct Equal_Edge : public std::binary_function<MEdge, MEdge, bool> {
   bool operator()(const MEdge &e1, const MEdge &e2) const
   {
@@ -109,12 +109,11 @@ struct Equal_Edge : public std::binary_function<MEdge, MEdge, bool> {
 struct Less_Edge : public std::binary_function<MEdge, MEdge, bool> {
   bool operator()(const MEdge &e1, const MEdge &e2) const
   {
-    if(e1.getMinVertex() < e2.getMinVertex()) return true;
-    if(e1.getMinVertex() > e2.getMinVertex()) return false;
-    if(e1.getMaxVertex() < e2.getMaxVertex()) return true;
+    if(e1.getMinVertex()->getNum() < e2.getMinVertex()->getNum()) return true;
+    if(e1.getMinVertex()->getNum() > e2.getMinVertex()->getNum()) return false;
+    if(e1.getMaxVertex()->getNum() < e2.getMaxVertex()->getNum()) return true;
     return false;
   }
-
 };
 
 #endif
diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp
index 1590d0d43d..a7e6b12dbf 100644
--- a/Mesh/meshGFace.cpp
+++ b/Mesh/meshGFace.cpp
@@ -2509,9 +2509,9 @@ void directions_storage(GFace* gf){
   MElementOctree* octree;
   std::set<MVertex*> vertices;
   std::set<MVertex*>::iterator it;
-	
-  vertices.clear();	
-	
+
+  vertices.clear();
+
   for(i=0;i<gf->getNumMeshElements();i++){
     element = gf->getMeshElement(i);
 	for(j=0;j<element->getNumVertices();j++){
@@ -2519,18 +2519,18 @@ void directions_storage(GFace* gf){
 	  vertices.insert(vertex);
 	}
   }
-	
+
   backgroundMesh::set(gf);
   octree = backgroundMesh::current()->get_octree();
-	
+
   gf->storage1.clear();
   gf->storage2.clear();
   gf->storage3.clear();
   gf->storage4.clear();
-	
+
   for(it=vertices.begin();it!=vertices.end();it++){
     ok = 0;
-	  
+
 	if(!gf->getCompound()){
       if(gf->geomType()==GEntity::CompoundSurface){
 	    ok = translate(gf,octree,*it,SPoint2(0.0,0.0),v1,v2);
@@ -2539,16 +2539,16 @@ void directions_storage(GFace* gf){
 	    ok = improved_translate(gf,*it,v1,v2);
 	  }
 	}
-	  
+
 	if(ok){
       gf->storage1.push_back(SPoint3((*it)->x(),(*it)->y(),(*it)->z()));
 	  gf->storage2.push_back(v1);
 	  gf->storage3.push_back(v2);
 	  reparamMeshVertexOnFace(*it,gf,point);
 	  gf->storage4.push_back(backgroundMesh::current()->operator()(point.x(),point.y(),0.0));
-	}  
+	}
   }
-	
+
   backgroundMesh::unset();
 }
 
@@ -2565,7 +2565,7 @@ bool translate(GFace* gf,MElementOctree* octree,MVertex* vertex,SPoint2 corr,SVe
   SPoint2 point;
   GPoint gp1;
   GPoint gp2;
-	
+
   ok = true;
   k = 0.0001;
   reparamMeshVertexOnFace(vertex,gf,point);
@@ -2576,12 +2576,12 @@ bool translate(GFace* gf,MElementOctree* octree,MVertex* vertex,SPoint2 corr,SVe
 
   delta_x = k*size*cos(angle);
   delta_y = k*size*sin(angle);
-	
+
   x1 = x + delta_x;
   y1 = y + delta_y;
   x2 = x + delta_y;
   y2 = y - delta_x;
-	
+
   if(!inside_domain(octree,x1,y1)){
     x1 = x - delta_x;
 	y1 = y - delta_y;
@@ -2592,9 +2592,9 @@ bool translate(GFace* gf,MElementOctree* octree,MVertex* vertex,SPoint2 corr,SVe
 	y2 = y + delta_x;
 	if(!inside_domain(octree,x2,y2)) ok = false;
   }
-	
+
   ok = true; //?
-	
+
   if(ok){
     gp1 = gf->point(x1,y1);
 	gp2 = gf->point(x2,y2);
@@ -2616,27 +2616,27 @@ bool improved_translate(GFace* gf,MVertex* vertex,SVector3& v1,SVector3& v2){
   SVector3 normal;
   SVector3 basis_u,basis_v;
   Pair<SVector3,SVector3> derivatives;
-	
+
   reparamMeshVertexOnFace(vertex,gf,point);
   x = point.x();
   y = point.y();
-	
+
   angle = backgroundMesh::current()->getAngle(x,y,0.0);
   derivatives = gf->firstDer(point);
-	
+
   s1 = derivatives.first();
   s2 = derivatives.second();
   normal = crossprod(s1,s2);
-	
+
   basis_u = s1;
   basis_u.normalize();
   basis_v = crossprod(normal,basis_u);
   basis_v.normalize();
-	
+
   v1 = basis_u*cos(angle) + basis_v*sin(angle);
   v2 = crossprod(v1,normal);
   v2.normalize();
-	
+
   return 1;
 }
 
diff --git a/Mesh/meshGFaceOptimize.h b/Mesh/meshGFaceOptimize.h
index a866812ec0..8b7644cfe7 100644
--- a/Mesh/meshGFaceOptimize.h
+++ b/Mesh/meshGFaceOptimize.h
@@ -13,13 +13,10 @@
 #include "meshGFaceDelaunayInsertion.h"
 #include "STensor3.h"
 
-
-
 class GFace;
 class GVertex;
 class MVertex;
 
-
 class edge_angle {
  public :
   MVertex *v1, *v2;
@@ -28,10 +25,10 @@ class edge_angle {
   bool operator < (const edge_angle &other) const
   {
     return other.angle < angle;
-  }  
+  }
 };
 
-typedef std::map<MVertex*, std::vector<MElement*> > v2t_cont;
+typedef std::map<MVertex*, std::vector<MElement*>, MVertexLessThanNum > v2t_cont;
 typedef std::map<MEdge, std::pair<MElement*, MElement*>, Less_Edge> e2t_cont;
 
 template <class T> void buildVertexToElement(std::vector<T*> &eles, v2t_cont &adj){
@@ -51,6 +48,7 @@ template <class T> void buildVertexToElement(std::vector<T*> &eles, v2t_cont &ad
     }
   }
 }
+
 template <class T> void buildEdgeToElement(std::vector<T*> &eles, e2t_cont &adj);
 
 void buildVertexToTriangle(std::vector<MTriangle*> &, v2t_cont &adj);
@@ -71,18 +69,18 @@ void edgeSwappingLawson(GFace *gf);
 enum swapCriterion {SWCR_DEL, SWCR_QUAL, SWCR_NORM, SWCR_CLOSE};
 enum splitCriterion {SPCR_CLOSE, SPCR_QUAL, SPCR_ALLWAYS};
 
-int edgeSwapPass(GFace *gf, 
-                 std::set<MTri3*, compareTri3Ptr> &allTris, 
+int edgeSwapPass(GFace *gf,
+                 std::set<MTri3*, compareTri3Ptr> &allTris,
                  const swapCriterion &cr, bidimMeshData &DATA);
 void removeFourTrianglesNodes(GFace *gf, bool replace_by_quads);
 void removeThreeTrianglesNodes(GFace *gf);
-void buildMeshGenerationDataStructures(GFace *gf, 
+void buildMeshGenerationDataStructures(GFace *gf,
                                        std::set<MTri3*, compareTri3Ptr> &AllTris,
 				       bidimMeshData & data);
 void transferDataStructure(GFace *gf, std::set<MTri3*, compareTri3Ptr> &AllTris,bidimMeshData &DATA);
 void computeEquivalences(GFace *gf,bidimMeshData &DATA);
-void recombineIntoQuads(GFace *gf, 
-                        bool topologicalOpti   = true, 
+void recombineIntoQuads(GFace *gf,
+                        bool topologicalOpti   = true,
                         bool nodeRepositioning = true);
 
 //used for meshGFaceRecombine development
@@ -120,7 +118,7 @@ struct swapquad{
     std::sort(v, v + 4);
   }
 };
-      
+
 struct RecombineTriangle
 {
   MElement *t1, *t2;
@@ -132,14 +130,14 @@ struct RecombineTriangle
   {
     n1 = me.getVertex(0);
     n2 = me.getVertex(1);
-    
+
     if(t1->getVertex(0) != n1 && t1->getVertex(0) != n2) n3 = t1->getVertex(0);
     else if(t1->getVertex(1) != n1 && t1->getVertex(1) != n2) n3 = t1->getVertex(1);
     else if(t1->getVertex(2) != n1 && t1->getVertex(2) != n2) n3 = t1->getVertex(2);
     if(t2->getVertex(0) != n1 && t2->getVertex(0) != n2) n4 = t2->getVertex(0);
     else if(t2->getVertex(1) != n1 && t2->getVertex(1) != n2) n4 = t2->getVertex(1);
     else if(t2->getVertex(2) != n1 && t2->getVertex(2) != n2) n4 = t2->getVertex(2);
-    
+
     MQuadrangle q (n1,n3,n2,n4);
     angle = q.etaShapeMeasure();
 
@@ -162,21 +160,21 @@ struct RecombineTriangle
 /******************class Temporary******************/
 /***************************************************/
 
-class Temporary{ 	 	 
- private : 	 	 
-  static double w1,w2,w3; 	 	 
-  static std::vector<SVector3> gradients; 	 	 
-  void read_data(std::string); 	 	 
-  static SVector3 compute_normal(MElement*); 	 	 
-  static SVector3 compute_other_vector(MElement*); 	 	 
-  static SVector3 compute_gradient(MElement*); 	 	 
- public : 	 	 
-  Temporary(); 	 	 
-  ~Temporary(); 	 	 
-  void quadrilaterize(std::string,double,double,double); 	 	 
-  static double compute_total_cost(double,double); 	 	 
-  static void select_weights(double,double,double); 	 	 
-  static double compute_alignment(const MEdge&,MElement*,MElement*); 	 	 
+class Temporary{
+ private :
+  static double w1,w2,w3;
+  static std::vector<SVector3> gradients;
+  void read_data(std::string);
+  static SVector3 compute_normal(MElement*);
+  static SVector3 compute_other_vector(MElement*);
+  static SVector3 compute_gradient(MElement*);
+ public :
+  Temporary();
+  ~Temporary();
+  void quadrilaterize(std::string,double,double,double);
+  static double compute_total_cost(double,double);
+  static void select_weights(double,double,double);
+  static double compute_alignment(const MEdge&,MElement*,MElement*);
 };
 
 /***************************************************/
@@ -184,4 +182,3 @@ class Temporary{
 /***************************************************/
 
 #endif
-
-- 
GitLab