ROOT  6.06/09
Reference Guide
Delaunay2D.cxx
Go to the documentation of this file.
1 // @(#)root/mathcore:$Id: Delaunay2D.h,v 1.00
2 // Author: Daniel Funke, Lorenzo Moneta
3 
4 /*************************************************************************
5  * Copyright (C) 2015 ROOT Math Team *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 // Implementation file for class Delaunay2D
13 
14 #include "Math/Delaunay2D.h"
15 
16 //#include <thread>
17 
18 // in case we do not use CGAL
19 #ifndef HAS_CGAL
20 // use the triangle library
21 #include "triangle.h"
22 #endif
23 
24 #include <algorithm>
25 
26 namespace ROOT {
27 
28  namespace Math {
29 
30 
31 /// class constructor from array of data points
32 Delaunay2D::Delaunay2D(int n, const double * x, const double * y, const double * z,
33  double xmin, double xmax, double ymin, double ymax)
34 {
35  // Delaunay2D normal constructor
36 
37  fX = x;
38  fY = y;
39  fZ = z;
40  fNpoints = n;
41  fOffsetX = 0;
42  fOffsetY = 0;
43  fScaleFactorX = 0;
44  fScaleFactorY = 0;
45  fNdt = 0;
46  fXNmax = 0;
47  fXNmin = 0;
48  fYNmin = 0;
49  fYNmax = 0;
50 
51  SetInputPoints(n,x,y,z,xmin,xmax,ymin,ymax);
52 
53 }
54 
55 /// set the input points
56 void Delaunay2D::SetInputPoints(int n, const double * x, const double * y, const double * z,
57  double xmin, double xmax, double ymin, double ymax) {
58 
59 
60 #ifdef THREAD_SAFE
62 #else
63  fInit = kFALSE;
64 #endif
65 
66  if (n == 0 || !x || !y || !z ) return;
67 
68  if (xmin >= xmax) {
69  xmin = *std::min_element(x, x+n);
70  xmax = *std::max_element(x, x+n);
71 
72  ymin = *std::min_element(y, y+n);
73  ymax = *std::max_element(y, y+n);
74  }
75 
76  fOffsetX = -(xmax+xmin)/2.;
77  fOffsetY = -(ymax+ymin)/2.;
78 
79  fScaleFactorX = 1./(xmax-xmin);
80  fScaleFactorY = 1./(ymax-ymin);
81 
82  //xTransformer = std::bind(linear_transform, std::placeholders::_1, Xoffset, XScaleFactor);
83  //yTransformer = std::bind(linear_transform, std::placeholders::_1, Yoffset, YScaleFactor);
84 
85  fXNmax = Linear_transform(xmax, fOffsetX, fScaleFactorX); //xTransformer(xmax);
86  fXNmin = Linear_transform(xmin, fOffsetX, fScaleFactorX); //xTransformer(xmin);
87 
88  fYNmax = Linear_transform(ymax, fOffsetY, fScaleFactorY); //yTransformer(ymax);
89  fYNmin = Linear_transform(ymin, fOffsetY, fScaleFactorY); //yTransformer(ymin);
90 
91  //printf("Normalized space extends from (%f,%f) to (%f,%f)\n", fXNmin, fYNmin, fXNmax, fYNmax);
92 
93 
94 #ifndef HAS_CGAL
95  fXCellStep = 0.;
96  fYCellStep = 0.;
97 #endif
98 }
99 
100 //______________________________________________________________________________
101 double Delaunay2D::Interpolate(double x, double y)
102 {
103  // Return the z value corresponding to the (x,y) point in fGraph2D
104 
105  // Initialise the Delaunay algorithm if needed.
106  // CreateTrianglesDataStructure computes fXoffset, fYoffset,
107  // fXScaleFactor and fYScaleFactor;
108  // needed in this function.
110 
111  // Find the z value corresponding to the point (x,y).
112  double xx, yy;
113  xx = Linear_transform(x, fOffsetX, fScaleFactorX); //xx = xTransformer(x);
114  yy = Linear_transform(y, fOffsetY, fScaleFactorY); //yy = yTransformer(y);
115  double zz = DoInterpolateNormalized(xx, yy);
116 
117  // Wrong zeros may appear when points sit on a regular grid.
118  // The following line try to avoid this problem.
119  if (zz==0) zz = DoInterpolateNormalized(xx+0.0001, yy);
120 
121  return zz;
122 }
123 
124 //______________________________________________________________________________
126 {
127 
128 #ifdef THREAD_SAFE
129  //treat the common case first
130  if(fInit.load(std::memory_order::memory_order_relaxed) == Initialization::INITIALIZED)
131  return;
132 
133  Initialization cState = Initialization::UNINITIALIZED;
134  if(fInit.compare_exchange_strong(cState, Initialization::INITIALIZING,
135  std::memory_order::memory_order_release, std::memory_order::memory_order_relaxed))
136  {
137  // the value of fInit was indeed UNINIT, we replaced it atomically with initializing
138  // performing the initialzing now
139 #else
140  if (fInit) return; else fInit = kTRUE;
141 #endif
142 
143  // Function used internally only. It creates the data structures needed to
144  // compute the Delaunay triangles.
145 
146  // Offset fX and fY so they average zero, and scale so the average
147  // of the X and Y ranges is one. The normalized version of fX and fY used
148  // in Interpolate.
149 
150  DoNormalizePoints(); // call backend specific point normalization
151 
152  DoFindTriangles(); // call backend specific triangle finding
153 
154  fNdt = fTriangles.size();
155 
156 #ifdef THREAD_SAFE
157  fInit = Initialization::INITIALIZED;
158  } else while(cState != Initialization::INITIALIZED) {
159  //the value of fInit was NOT UNINIT, so we have to spin until we reach INITIALEZED
160  cState = fInit.load(std::memory_order::memory_order_relaxed);
161  }
162 #endif
163 
164 }
165 
166 
167 // backend specific implementations
168 
169 #ifdef HAS_CGAL
170 /// CGAL implementation of normalize points
171 void Delaunay2D::DonormalizePoints() {
172  for (Int_t n = 0; n < fNpoints; n++) {
173  //Point p(xTransformer(fX[n]), yTransformer(fY[n]));
174  Point p(linear_transform(fX[n], fOffsetX, fScaleFactorX),
175  linear_transform(fY[n], fOffsetY, fScaleFactorY));
176 
177  fNormalizedPoints.insert(std::make_pair(p, n));
178  }
179 }
180 
181 /// CGAL implementation for finding triangles
183  fCGALdelaunay.insert(fNormalizedPoints.begin(), fNormalizedPoints.end());
184 
185  std::transform(fCGALdelaunay.finite_faces_begin(),
186  fCGALdelaunay.finite_faces_end(), std::back_inserter(fTriangles),
187  [] (const Delaunay::Face face) -> Triangle {
188 
189  Triangle tri;
190 
191  auto transform = [&] (const unsigned int i) {
192  tri.x[i] = face.vertex(i)->point().x();
193  tri.y[i] = face.vertex(i)->point().y();
194  tri.idx[i] = face.vertex(i)->info();
195  };
196 
197  transform(0);
198  transform(1);
199  transform(2);
200 
201  return tri;
202 
203  });
204 }
205 
206 /// CGAL implementation for interpolation
207 double Delaunay2D::DoInterpolateNormalized(double xx, double yy)
208 {
209  // Finds the Delaunay triangle that the point (xi,yi) sits in (if any) and
210  // calculate a z-value for it by linearly interpolating the z-values that
211  // make up that triangle.
212 
213  // initialise the Delaunay algorithm if needed
215 
216  //coordinate computation
217  Point p(xx, yy);
218 
219  std::vector<std::pair<Point, Coord_type> > coords;
220  auto nn = CGAL::natural_neighbor_coordinates_2(fCGALdelaunay, p,
221  std::back_inserter(coords));
222 
223  //std::cout << std::this_thread::get_id() << ": Found " << coords.size() << " points" << std::endl;
224 
225  if(!nn.third) //neighbor finding was NOT successfull, return standard value
226  return fZout;
227 
228  //printf("found neighbors %u\n", coords.size());
229 
230  Coord_type res = CGAL::linear_interpolation(coords.begin(), coords.end(),
231  nn.second, Value_access(fNormalizedPoints, fZ));
232 
233  //std::cout << std::this_thread::get_id() << ": Result " << res << std::endl;
234 
235  return res;
236 }
237 
238 #else // HAS_CGAL
239 
240 /// Triangle implementation for normalizing the points
242  for (Int_t n = 0; n < fNpoints; n++) {
243  fXN.push_back(Linear_transform(fX[n], fOffsetX, fScaleFactorX));
244  fYN.push_back(Linear_transform(fY[n], fOffsetY, fScaleFactorY));
245  }
246 
247  //also initialize fXCellStep and FYCellStep
250 }
251 
252 /// Triangle implementation for finding all the triangles
254 
255  auto initStruct = [] (triangulateio & s) {
256  s.pointlist = nullptr; /* In / out */
257  s.pointattributelist = nullptr; /* In / out */
258  s.pointmarkerlist = nullptr; /* In / out */
259  s.numberofpoints = 0; /* In / out */
260  s.numberofpointattributes = 0; /* In / out */
261 
262  s.trianglelist = nullptr; /* In / out */
263  s.triangleattributelist = nullptr; /* In / out */
264  s.trianglearealist = nullptr; /* In only */
265  s.neighborlist = nullptr; /* Out only */
266  s.numberoftriangles = 0; /* In / out */
267  s.numberofcorners = 0; /* In / out */
268  s.numberoftriangleattributes = 0; /* In / out */
269 
270  s.segmentlist = nullptr; /* In / out */
271  s.segmentmarkerlist = nullptr; /* In / out */
272  s.numberofsegments = 0; /* In / out */
273 
274  s.holelist = nullptr; /* In / pointer to array copied out */
275  s.numberofholes = 0; /* In / copied out */
276 
277  s.regionlist = nullptr; /* In / pointer to array copied out */
278  s.numberofregions = 0; /* In / copied out */
279 
280  s.edgelist = nullptr; /* Out only */
281  s.edgemarkerlist = nullptr; /* Not used with Voronoi diagram; out only */
282  s.normlist = nullptr; /* Used only with Voronoi diagram; out only */
283  s.numberofedges = 0; /* Out only */
284  };
285 
286  auto freeStruct = [] (triangulateio & s) {
287  if(s.pointlist != nullptr) free(s.pointlist); /* In / out */
288  if(s.pointattributelist != nullptr) free(s.pointattributelist); /* In / out */
289  if(s.pointmarkerlist != nullptr) free(s.pointmarkerlist); /* In / out */
290 
291  if(s.trianglelist != nullptr) free(s.trianglelist); /* In / out */
292  if(s.triangleattributelist != nullptr) free(s.triangleattributelist); /* In / out */
293  if(s.trianglearealist != nullptr) free(s.trianglearealist); /* In only */
294  if(s.neighborlist != nullptr) free(s.neighborlist); /* Out only */
295 
296  if(s.segmentlist != nullptr) free(s.segmentlist); /* In / out */
297  if(s.segmentmarkerlist != nullptr) free(s.segmentmarkerlist); /* In / out */
298 
299  if(s.holelist != nullptr) free(s.holelist); /* In / pointer to array copied out */
300 
301  if(s.regionlist != nullptr) free(s.regionlist); /* In / pointer to array copied out */
302 
303  if(s.edgelist != nullptr) free(s.edgelist); /* Out only */
304  if(s.edgemarkerlist != nullptr) free(s.edgemarkerlist); /* Not used with Voronoi diagram; out only */
305  if(s.normlist != nullptr) free(s.normlist); /* Used only with Voronoi diagram; out only */
306  };
307 
308  struct triangulateio in, out;
309  initStruct(in); initStruct(out);
310 
311  /* Define input points. */
312 
314  in.pointlist = (REAL *) malloc(in.numberofpoints * 2 * sizeof(REAL));
315 
316  for (Int_t i = 0; i < fNpoints; ++i) {
317  in.pointlist[2 * i] = fXN[i];
318  in.pointlist[2 * i + 1] = fYN[i];
319  }
320 
321  triangulate((char *) "zQN", &in, &out, nullptr);
322 
323  fTriangles.resize(out.numberoftriangles);
324  for(int t = 0; t < out.numberoftriangles; ++t){
325  Triangle tri;
326 
327  auto transform = [&] (const unsigned int v) {
328  //each triangle as numberofcorners vertices ( = 3)
329  tri.idx[v] = out.trianglelist[t*out.numberofcorners + v];
330 
331  //printf("triangle %u vertex %u: point %u/%i\n", t, v, tri.idx[v], out.numberofpoints);
332 
333  //pointlist is [x0 y0 x1 y1 ...]
334  tri.x[v] = in.pointlist[tri.idx[v] * 2 + 0];
335 
336  //printf("\t x: %f\n", tri.x[v]);
337 
338  tri.y[v] = in.pointlist[tri.idx[v] * 2 + 1];
339 
340  //printf("\t y: %f\n", tri.y[v]);
341  };
342 
343  transform(0);
344  transform(1);
345  transform(2);
346 
347  //see comment in header for CGAL fallback section
348  tri.invDenom = 1 / ( (tri.y[1] - tri.y[2])*(tri.x[0] - tri.x[2]) + (tri.x[2] - tri.x[1])*(tri.y[0] - tri.y[2]) );
349 
350  fTriangles[t] = tri;
351 
352  auto bx = std::minmax({tri.x[0], tri.x[1], tri.x[2]});
353  auto by = std::minmax({tri.y[0], tri.y[1], tri.y[2]});
354 
355  unsigned int cellXmin = CellX(bx.first);
356  unsigned int cellXmax = CellX(bx.second);
357 
358  unsigned int cellYmin = CellY(by.first);
359  unsigned int cellYmax = CellY(by.second);
360 
361  for(unsigned int i = cellXmin; i <= cellXmax; ++i)
362  for(unsigned int j = cellYmin; j <= cellYmax; ++j){
363  //printf("(%u,%u) = %u\n", i, j, Cell(i,j));
364  fCells[Cell(i,j)].insert(t);
365  }
366 
367  }
368 
369  freeStruct(in); freeStruct(out);
370 }
371 
372 /// Triangle implementation for interpolation
373 /// Finds the Delaunay triangle that the point (xi,yi) sits in (if any) and
374 /// calculate a z-value for it by linearly interpolating the z-values that
375 /// make up that triangle.
376 double Delaunay2D::DoInterpolateNormalized(double xx, double yy)
377 {
378 
379  // relay that ll the triangles have been found
380  /// FindAllTriangles();
381 
382  //see comment in header for CGAL fallback section
383  auto bayCoords = [&] (const unsigned int t) -> std::tuple<double, double, double> {
384  double la = ( (fTriangles[t].y[1] - fTriangles[t].y[2])*(xx - fTriangles[t].x[2])
385  + (fTriangles[t].x[2] - fTriangles[t].x[1])*(yy - fTriangles[t].y[2]) ) * fTriangles[t].invDenom;
386  double lb = ( (fTriangles[t].y[2] - fTriangles[t].y[0])*(xx - fTriangles[t].x[2])
387  + (fTriangles[t].x[0] - fTriangles[t].x[2])*(yy - fTriangles[t].y[2]) ) * fTriangles[t].invDenom;
388 
389  return std::make_tuple(la, lb, (1 - la - lb));
390  };
391 
392  auto inTriangle = [] (const std::tuple<double, double, double> & coords) -> bool {
393  return std::get<0>(coords) >= 0 && std::get<1>(coords) >= 0 && std::get<2>(coords) >= 0;
394  };
395 
396  int cX = CellX(xx);
397  int cY = CellY(yy);
398 
399  if(cX < 0 || cX > fNCells || cY < 0 || cY > fNCells)
400  return fZout; //TODO some more fancy interpolation here
401 
402  for(unsigned int t : fCells[Cell(cX, cY)]){
403  auto coords = bayCoords(t);
404 
405  if(inTriangle(coords)){
406  //we found the triangle -> interpolate using the barycentric interpolation
407  return std::get<0>(coords) * fZ[fTriangles[t].idx[0]]
408  + std::get<1>(coords) * fZ[fTriangles[t].idx[1]]
409  + std::get<2>(coords) * fZ[fTriangles[t].idx[2]];
410 
411  }
412  }
413 
414  //debugging
415 
416  /*for(unsigned int t = 0; t < fNdt; ++t){
417  auto coords = bayCoords(t);
418 
419  if(inTriangle(coords)){
420 
421  //brute force found a triangle -> grid not
422  printf("Found triangle %u for (%f,%f) -> (%u,%u)\n", t, xx,yy, cX, cY);
423  printf("Triangles in grid cell: ");
424  for(unsigned int x : fCells[Cell(cX, cY)])
425  printf("%u ", x);
426  printf("\n");
427 
428  printf("Triangle %u is in cells: ", t);
429  for(unsigned int i = 0; i <= fNCells; ++i)
430  for(unsigned int j = 0; j <= fNCells; ++j)
431  if(fCells[Cell(i,j)].count(t))
432  printf("(%u,%u) ", i, j);
433  printf("\n");
434  for(unsigned int i = 0; i < 3; ++i)
435  printf("\tpoint %u (%u): (%f,%f) -> (%u,%u)\n", i, fTriangles[t].idx[i], fTriangles[t].x[i], fTriangles[t].y[i], CellX(fTriangles[t].x[i]), CellY(fTriangles[t].y[i]));
436 
437  //we found the triangle -> interpolate using the barycentric interpolation
438  return std::get<0>(coords) * fZ[fTriangles[t].idx[0]]
439  + std::get<1>(coords) * fZ[fTriangles[t].idx[1]]
440  + std::get<2>(coords) * fZ[fTriangles[t].idx[2]];
441 
442  }
443  }
444 
445  printf("Could not find a triangle for point (%f,%f)\n", xx, yy);
446  */
447 
448  //no triangle found return standard value
449  return fZout;
450 }
451 
452 } // namespace Math
453 } // namespace ROOT
454 
455 
456 #endif //HAS_CGAL
unsigned int Cell(UInt_t x, UInt_t y) const
grid cells with containing triangles
Definition: Delaunay2D.h:276
double fZout
Normalization factor Y.
Definition: Delaunay2D.h:173
void DoNormalizePoints()
internal function to normalize the points
Definition: Delaunay2D.cxx:241
float xmin
Definition: THbookFile.cxx:93
Namespace for new ROOT classes and functions.
Definition: ROOT.py:1
int * trianglelist
Definition: triangle.h:295
float ymin
Definition: THbookFile.cxx:93
Bool_t fInit
Height for points lying outside the convex hull.
Definition: Delaunay2D.h:181
int Int_t
Definition: RtypesCore.h:41
const Bool_t kFALSE
Definition: Rtypes.h:92
void FindAllTriangles()
Find all triangles.
Definition: Delaunay2D.cxx:125
double fScaleFactorX
Normalization offset Y.
Definition: Delaunay2D.h:170
#define REAL
Definition: triangle.h:277
double DoInterpolateNormalized(double x, double y)
internal method to compute the interpolation
Definition: Delaunay2D.cxx:376
Double_t x[n]
Definition: legend1.C:17
Vc_ALWAYS_INLINE void free(T *p)
Frees memory that was allocated with Vc::malloc.
Definition: memory.h:94
double fOffsetY
Normalization offset X.
Definition: Delaunay2D.h:168
double fScaleFactorY
Normalization factor X.
Definition: Delaunay2D.h:171
double fOffsetX
Maximum value of fYN.
Definition: Delaunay2D.h:167
void SetInputPoints(int n, const double *x, const double *y, const double *z, double xmin=0, double xmax=0, double ymin=0, double ymax=0)
set the input points for building the graph
Definition: Delaunay2D.cxx:56
std::set< UInt_t > fCells[(fNCells+1)*(fNCells+1)]
inverse denominator to calculate X cell = fNCells / (fYNmax - fYNmin)
Definition: Delaunay2D.h:274
double fXNmin
Pointer to Z array.
Definition: Delaunay2D.h:159
float ymax
Definition: THbookFile.cxx:93
SVector< double, 2 > v
Definition: Dict.h:5
const double * fY
Pointer to X array (managed externally)
Definition: Delaunay2D.h:156
int CellX(double x) const
Definition: Delaunay2D.h:280
double fXNmax
Minimum value of fXN.
Definition: Delaunay2D.h:160
int numberofcorners
Definition: triangle.h:300
std::vector< double > fYN
normalized X
Definition: Delaunay2D.h:264
float xmax
Definition: THbookFile.cxx:93
double fYNmax
Minimum value of fYN.
Definition: Delaunay2D.h:162
double fXCellStep
number of cells to divide the normalized space
Definition: Delaunay2D.h:272
int numberofpoints
Definition: triangle.h:292
Int_t fNpoints
Number of Delaunay triangles found.
Definition: Delaunay2D.h:153
double fYCellStep
inverse denominator to calculate X cell = fNCells / (fXNmax - fXNmin)
Definition: Delaunay2D.h:273
Double_t y[n]
Definition: legend1.C:17
Namespace for new Math classes and functions.
static const Int_t UNINITIALIZED
static const int fNCells
normalized Y
Definition: Delaunay2D.h:271
void DoFindTriangles()
internal function to find the triangle use Triangle or CGAL if flag is set
Definition: Delaunay2D.cxx:253
std::vector< double > fXN
Triangles of Triangulation.
Definition: Delaunay2D.h:263
void triangulate(char *triswitches, struct triangulateio *in, struct triangulateio *out, struct triangulateio *vorout)
Definition: triangle.c:15651
const double * fX
Number of data points.
Definition: Delaunay2D.h:155
double fYNmin
Maximum value of fXN.
Definition: Delaunay2D.h:161
int CellY(double y) const
Definition: Delaunay2D.h:284
const Bool_t kTRUE
Definition: Rtypes.h:91
REAL * pointlist
Definition: triangle.h:289
Vc_ALWAYS_INLINE_L T *Vc_ALWAYS_INLINE_R malloc(size_t n)
Allocates memory on the Heap with alignment and padding suitable for vectorized access.
Definition: memory.h:67
double Interpolate(double x, double y)
Return the Interpolated z value corresponding to the (x,y) point.
Definition: Delaunay2D.cxx:101
const Int_t n
Definition: legend1.C:16
Delaunay2D(int n, const double *x, const double *y, const double *z, double xmin=0, double xmax=0, double ymin=0, double ymax=0)
class constructor from array of data points
Definition: Delaunay2D.cxx:32
double Linear_transform(double x, double offset, double factor)
Definition: Delaunay2D.h:127
const double * fZ
Pointer to Y array.
Definition: Delaunay2D.h:157
Triangles fTriangles
True if FindAllTriangels() has been performed.
Definition: Delaunay2D.h:185
int numberoftriangles
Definition: triangle.h:299