From 9c5da6b2161cd6df8fab9da077012d5c7d0ff339 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Tue, 3 Aug 2010 07:34:22 +0000
Subject: [PATCH] pp+MVertexOctree

---
 Geo/CMakeLists.txt                |  5 +--
 Geo/MElementOctree.h              |  5 +++
 Geo/MVertex.cpp                   | 11 ++++-
 Geo/MVertexOctree.cpp             | 72 +++++++++++++++++++++++++++++++
 Geo/MVertexOctree.h               | 19 ++++++++
 Mesh/meshGFaceExtruded.cpp        | 33 ++++++++------
 Mesh/meshGRegionExtruded.cpp      | 55 +++++++++++++----------
 benchmarks/extrude/degenerate.geo |  2 +-
 8 files changed, 161 insertions(+), 41 deletions(-)
 create mode 100644 Geo/MVertexOctree.cpp
 create mode 100644 Geo/MVertexOctree.h

diff --git a/Geo/CMakeLists.txt b/Geo/CMakeLists.txt
index 70310e4ae6..f9be3537e7 100644
--- a/Geo/CMakeLists.txt
+++ b/Geo/CMakeLists.txt
@@ -30,10 +30,9 @@ set(SRC
   findLinks.cpp
   SOrientedBoundingBox.cpp
   GeomMeshMatcher.cpp
-  MVertex.cpp
+  MVertex.cpp MVertexOctree.cpp
   MFace.cpp
-  MElement.cpp
-  MElementOctree.cpp
+  MElement.cpp MElementOctree.cpp
     MLine.cpp MTriangle.cpp MQuadrangle.cpp MTetrahedron.cpp
     MHexahedron.cpp MPrism.cpp MPyramid.cpp MElementCut.cpp
   MZone.cpp MZoneBoundary.cpp
diff --git a/Geo/MElementOctree.h b/Geo/MElementOctree.h
index 8e883f996f..35606fcd53 100644
--- a/Geo/MElementOctree.h
+++ b/Geo/MElementOctree.h
@@ -1,3 +1,8 @@
+// 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 _MELEMENT_OCTREE_
 #define _MELEMENT_OCTREE_
 
diff --git a/Geo/MVertex.cpp b/Geo/MVertex.cpp
index 314c69861a..f67b7374cf 100644
--- a/Geo/MVertex.cpp
+++ b/Geo/MVertex.cpp
@@ -222,11 +222,20 @@ std::set<MVertex*, MVertexLessThanLexicographic>::iterator
 MVertex::linearSearch(std::set<MVertex*, MVertexLessThanLexicographic> &pos)
 {
   double tol = MVertexLessThanLexicographic::tolerance;
+  double dmin = 1e22;
+  std::set<MVertex*, MVertexLessThanLexicographic>::iterator itmin = pos.end();
   for(std::set<MVertex*, MVertexLessThanLexicographic>::iterator it = pos.begin();
       it != pos.end(); ++it){
+    double d = distance(*it);
+    if(d < dmin){
+      dmin = d;
+      itmin = it;
+    }
     if(distance(*it) < tol) return it;
   }
-  return pos.end();
+  Msg::Warning("Could not find point: returning closest (dist = %g)", dmin);
+  //return pos.end();
+  return itmin;
 }
 
 static void getAllParameters(MVertex *v, GFace *gf, std::vector<SPoint2> &params)
diff --git a/Geo/MVertexOctree.cpp b/Geo/MVertexOctree.cpp
new file mode 100644
index 0000000000..0dedfcd98f
--- /dev/null
+++ b/Geo/MVertexOctree.cpp
@@ -0,0 +1,72 @@
+// 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>.
+
+#include "Octree.h"
+#include "GModel.h"
+#include "MVertex.h"
+#include "MVertexOctree.h"
+#include "SBoundingBox3d.h"
+
+static void MVertexBB(void *a, double *min, double *max)
+{
+  MVertex *v = (MVertex*)a;
+  double tol = MVertexLessThanLexicographic::tolerance;
+  min[0] = v->x() - tol;
+  max[0] = v->x() + tol;
+  min[1] = v->y() - tol;
+  max[1] = v->y() + tol;
+  min[2] = v->z() - tol;
+  max[2] = v->z() + tol;
+}
+
+static void MVertexCentroid(void *a, double *x)
+{
+  MVertex *v = (MVertex*)a;
+  x[0] = v->x();
+  x[1] = v->y();
+  x[2] = v->z();
+}
+
+static int MVertexInEle(void *a, double *x)
+{
+  MVertex *v = (MVertex*)a;
+  double d = sqrt((x[0] - v->x()) * (x[0] - v->x()) +
+                  (x[1] - v->y()) * (x[1] - v->y()) +
+                  (x[2] - v->z()) * (x[2] - v->z()));
+  return (d < MVertexLessThanLexicographic::tolerance);
+}
+
+MVertexOctree::MVertexOctree(GModel *m)
+{
+  SBoundingBox3d bb = m->bounds();
+  double min[3] = {bb.min().x(), bb.min().y(), bb.min().z()};
+  double size[3] = {bb.max().x() - bb.min().x(),
+                    bb.max().y() - bb.min().y(),
+                    bb.max().z() - bb.min().z()};
+  const int maxElePerBucket = 100; // memory vs. speed trade-off
+  _octree = Octree_Create(maxElePerBucket, min, size,
+                          MVertexBB, MVertexCentroid, MVertexInEle);
+}
+
+MVertexOctree::~MVertexOctree()
+{
+  Octree_Delete(_octree);
+}
+
+void MVertexOctree::insert(MVertex *v)
+{
+  Octree_Insert(v, _octree);
+}
+
+void MVertexOctree::finalize()
+{
+  Octree_Arrange(_octree);
+}
+
+MVertex *MVertexOctree::find(double x, double y, double z)
+{
+  double P[3] = {x, y, z};
+  return (MVertex*)Octree_Search(P, _octree);
+}
diff --git a/Geo/MVertexOctree.h b/Geo/MVertexOctree.h
new file mode 100644
index 0000000000..e94e5b9104
--- /dev/null
+++ b/Geo/MVertexOctree.h
@@ -0,0 +1,19 @@
+#ifndef _MVERTEX_OCTREE_
+#define _MVERTEX_OCTREE_
+
+class Octree;
+class GModel;
+class MVertex;
+
+class MVertexOctree{
+ private:
+  Octree *_octree;
+ public:
+  MVertexOctree(GModel *);
+  ~MVertexOctree();
+  void insert(MVertex *);
+  void finalize();
+  MVertex *find(double x, double y, double z);
+};
+
+#endif
diff --git a/Mesh/meshGFaceExtruded.cpp b/Mesh/meshGFaceExtruded.cpp
index 8e7e254c0e..00c8761086 100644
--- a/Mesh/meshGFaceExtruded.cpp
+++ b/Mesh/meshGFaceExtruded.cpp
@@ -12,45 +12,50 @@
 #include "Context.h"
 #include "GmshMessage.h"
 
-static void addTriangle(MVertex* v1, MVertex* v2, MVertex* v3, GFace *to, MElement* source) {
+static void addTriangle(MVertex* v1, MVertex* v2, MVertex* v3,
+                        GFace *to, MElement* source) 
+{
   MTriangle* newTri = new MTriangle(v1, v2, v3);
   to->triangles.push_back(newTri);
-  to->meshAttributes.extrude->elementMap.addExtrudedElem((MElement*)source,(MElement*)newTri);
+  to->meshAttributes.extrude->elementMap.addExtrudedElem(source, (MElement*)newTri);
 }
 
-static void addQuadrangle(MVertex* v1, MVertex* v2, MVertex* v3, MVertex* v4, GFace *to, MElement* source) {
+static void addQuadrangle(MVertex* v1, MVertex* v2, MVertex* v3, MVertex* v4,
+                          GFace *to, MElement* source) 
+{
   MQuadrangle* newQuad = new MQuadrangle(v1, v2, v3, v4);
   to->quadrangles.push_back(newQuad);
-  to->meshAttributes.extrude->elementMap.addExtrudedElem((MElement*)source,(MElement*)newQuad);
+  to->meshAttributes.extrude->elementMap.addExtrudedElem(source, (MElement*)newQuad);
 }
 
 static void createQuaTri(std::vector<MVertex*> &v, GFace *to,
-                         std::set<std::pair<MVertex*, MVertex*> > *constrainedEdges,MLine* source)
+                         std::set<std::pair<MVertex*, MVertex*> > *constrainedEdges,
+                         MLine* source)
 {
   ExtrudeParams *ep = to->meshAttributes.extrude;
   if(v[0] == v[1] || v[1] == v[3])
-    addTriangle(v[0], v[3], v[2],to,source);
+    addTriangle(v[0], v[3], v[2], to, source);
   else if(v[0] == v[2] || v[2] == v[3])
-    addTriangle(v[0], v[1], v[3],to,source);
+    addTriangle(v[0], v[1], v[3], to, source);
   else if(v[0] == v[3] || v[1] == v[2])
     Msg::Error("Uncoherent extruded quadrangle in surface %d", to->tag());
   else{
     if(ep->mesh.Recombine){
-      addQuadrangle(v[0], v[1], v[3], v[2],to,source);
+      addQuadrangle(v[0], v[1], v[3], v[2], to, source);
     }
     else if(!constrainedEdges){
-      addTriangle(v[0], v[1], v[3],to,source);
-      addTriangle(v[0], v[3], v[2],to,source);
+      addTriangle(v[0], v[1], v[3], to, source);
+      addTriangle(v[0], v[3], v[2], to, source);
     }
     else{
       std::pair<MVertex*, MVertex*> p(std::min(v[1], v[2]), std::max(v[1], v[2]));
       if(constrainedEdges->count(p)){
-        addTriangle(v[2], v[1], v[0],to,source);
-        addTriangle(v[2], v[3], v[1],to,source);
+        addTriangle(v[2], v[1], v[0], to, source);
+        addTriangle(v[2], v[3], v[1], to, source);
       }
       else{
-        addTriangle(v[2], v[3], v[0],to,source);
-        addTriangle(v[0], v[3], v[1],to,source);
+        addTriangle(v[2], v[3], v[0], to, source);
+        addTriangle(v[0], v[3], v[1], to, source);
       }
     }
   }
diff --git a/Mesh/meshGRegionExtruded.cpp b/Mesh/meshGRegionExtruded.cpp
index 72dcff796e..f4d658099d 100644
--- a/Mesh/meshGRegionExtruded.cpp
+++ b/Mesh/meshGRegionExtruded.cpp
@@ -17,27 +17,37 @@
 #include "Context.h"
 #include "GmshMessage.h"
 
-static void addTetrahedron(MVertex* v1, MVertex* v2, MVertex* v3, MVertex* v4, GRegion *to, MElement* source) {
+static void addTetrahedron(MVertex* v1, MVertex* v2, MVertex* v3, MVertex* v4, 
+                           GRegion *to, MElement* source)
+{
   MTetrahedron* newElem = new MTetrahedron(v1, v2, v3, v4);
   to->tetrahedra.push_back(newElem);
-  to->meshAttributes.extrude->elementMap.addExtrudedElem((MElement*)source,(MElement*)newElem);
+  to->meshAttributes.extrude->elementMap.addExtrudedElem(source, (MElement*)newElem);
 }
 
-static void addPyramid(MVertex* v1, MVertex* v2, MVertex* v3, MVertex* v4, MVertex* v5, GRegion *to, MElement* source) {
+static void addPyramid(MVertex* v1, MVertex* v2, MVertex* v3, MVertex* v4,
+                       MVertex* v5, GRegion *to, MElement* source)
+{
   MPyramid* newElem = new MPyramid(v1, v2, v3, v4, v5);
   to->pyramids.push_back(newElem);
-  to->meshAttributes.extrude->elementMap.addExtrudedElem((MElement*)source,(MElement*)newElem);
+  to->meshAttributes.extrude->elementMap.addExtrudedElem(source, (MElement*)newElem);
 }
 
-static void addPrism(MVertex* v1, MVertex* v2, MVertex* v3, MVertex* v4, MVertex* v5, MVertex* v6, GRegion *to, MElement* source) {
+static void addPrism(MVertex* v1, MVertex* v2, MVertex* v3, MVertex* v4,
+                     MVertex* v5, MVertex* v6, GRegion *to, MElement* source)
+{
   MPrism* newElem = new MPrism(v1, v2, v3, v4, v5, v6);
   to->prisms.push_back(newElem);
-  to->meshAttributes.extrude->elementMap.addExtrudedElem((MElement*)source,(MElement*)newElem);
+  to->meshAttributes.extrude->elementMap.addExtrudedElem(source, (MElement*)newElem);
 }
-static void addHexahedron(MVertex* v1, MVertex* v2, MVertex* v3, MVertex* v4, MVertex* v5, MVertex* v6, MVertex* v7, MVertex* v8, GRegion *to, MElement* source) {
+
+static void addHexahedron(MVertex* v1, MVertex* v2, MVertex* v3, MVertex* v4,
+                          MVertex* v5, MVertex* v6, MVertex* v7, MVertex* v8,
+                          GRegion *to, MElement* source)
+{
   MHexahedron* newElem = new MHexahedron(v1, v2, v3, v4, v5, v6, v7, v8);
   to->hexahedra.push_back(newElem);
-  to->meshAttributes.extrude->elementMap.addExtrudedElem((MElement*)source,(MElement*)newElem);
+  to->meshAttributes.extrude->elementMap.addExtrudedElem(source, (MElement*)newElem);
 }
 
 static void createPriPyrTet(std::vector<MVertex*> &v, GRegion *to, MElement* source)
@@ -50,22 +60,22 @@ static void createPriPyrTet(std::vector<MVertex*> &v, GRegion *to, MElement* sou
 
   if(j == 2) {
     if(dup[0] == 0 && dup[1] == 1)
-      addTetrahedron(v[0], v[1], v[2], v[5],to,source);
+      addTetrahedron(v[0], v[1], v[2], v[5], to, source);
     else if(dup[0] == 1 && dup[1] == 2)
-      addTetrahedron(v[0], v[1], v[2], v[3],to,source);
+      addTetrahedron(v[0], v[1], v[2], v[3], to, source);
     else
-      addTetrahedron(v[0], v[1], v[2], v[4],to,source);
+      addTetrahedron(v[0], v[1], v[2], v[4], to, source);
   }
   else if(j == 1) {
     if(dup[0] == 0)
-      addPyramid(v[1], v[4], v[5], v[2], v[0],to,source);
+      addPyramid(v[1], v[4], v[5], v[2], v[0], to, source);
     else if(dup[0] == 1)
-      addPyramid(v[0], v[2], v[5], v[3], v[1],to,source);
+      addPyramid(v[0], v[2], v[5], v[3], v[1], to, source);
     else
-      addPyramid(v[0], v[1], v[4], v[3], v[2],to,source);
+      addPyramid(v[0], v[1], v[4], v[3], v[2], to, source);
   }
   else {
-    addPrism(v[0], v[1], v[2], v[3], v[4], v[5],to,source);
+    addPrism(v[0], v[1], v[2], v[3], v[4], v[5], to, source);
     if(j) Msg::Error("Degenerated prism in extrusion of volume %d", to->tag());
   }
 }
@@ -80,26 +90,27 @@ static void createHexPri(std::vector<MVertex*> &v, GRegion *to, MElement* source
   
   if(j == 2) {
     if(dup[0] == 0 && dup[1] == 1)
-      addPrism(v[0], v[3], v[7], v[1], v[2], v[6],to,source);
+      addPrism(v[0], v[3], v[7], v[1], v[2], v[6], to, source);
     else if(dup[0] == 1 && dup[1] == 2)
-      addPrism(v[0], v[1], v[4], v[3], v[2], v[7],to,source);
+      addPrism(v[0], v[1], v[4], v[3], v[2], v[7], to, source);
     else if(dup[0] == 2 && dup[1] == 3)
-      addPrism(v[0], v[3], v[4], v[1], v[2], v[5],to,source);
+      addPrism(v[0], v[3], v[4], v[1], v[2], v[5], to, source);
     else if(dup[0] == 0 && dup[1] == 3)
-      addPrism(v[0], v[1], v[5], v[3], v[2], v[6],to,source);
+      addPrism(v[0], v[1], v[5], v[3], v[2], v[6], to, source);
     else
       Msg::Error("Uncoherent hexahedron in extrusion of volume %d", to->tag());
   }
   else {
-    addHexahedron(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7],to,source);
+    addHexahedron(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], to, source);
     if(j) Msg::Error("Degenerated hexahedron in extrusion of volume %d", to->tag());
   }
 }
 
-static void createTet(MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4, GRegion *to, MElement* source)
+static void createTet(MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4, GRegion *to,
+                      MElement* source)
 {
   if(v1 != v2 && v1 != v3 && v1 != v4 && v2 != v3 && v2 != v4 && v3 != v4)
-    addTetrahedron(v1, v2, v3, v4,to,source);
+    addTetrahedron(v1, v2, v3, v4, to, source);
 }
 
 static int getExtrudedVertices(MElement *ele, ExtrudeParams *ep, int j, int k, 
diff --git a/benchmarks/extrude/degenerate.geo b/benchmarks/extrude/degenerate.geo
index 8688e37f8d..9e0ceb013a 100644
--- a/benchmarks/extrude/degenerate.geo
+++ b/benchmarks/extrude/degenerate.geo
@@ -63,4 +63,4 @@ Extrude Surface { 21, {0,1,0} , {0,0,0} , Pi/2 } {
 };
 
 
-Symmetry { 0,1,0,0 } { Duplicata{ Surface{158}; } }
+//Symmetry { 0,1,0,0 } { Duplicata{ Surface{158}; } }
-- 
GitLab