Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
Delaunay2D.cxx
Go to the documentation of this file.
1// @(#)root/mathcore:$Id: Delaunay2D.h,v 1.00
2// Authors: Daniel Funke, Lorenzo Moneta, Olivier Couet
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#include "Rtypes.h"
16#include "TError.h"
17
18// workaround for https://github.com/artem-ogre/CDT/issues/228
19#if defined(__GNUC__)
20#pragma GCC diagnostic push
21#pragma GCC diagnostic ignored "-Wshadow"
22#endif
23#include "CDT/CDT.h"
24#if defined(__GNUC__)
25#pragma GCC diagnostic pop
26#endif
27
28#include <algorithm>
29#include <cstdlib>
30
31#include <iostream>
32#include <limits>
33
34
35namespace ROOT {
36
37 namespace Math {
38
39
40/// class constructor from array of data points
41Delaunay2D::Delaunay2D(int n, const double * x, const double * y, const double * z,
42 double xmin, double xmax, double ymin, double ymax)
43{
44 // Delaunay2D normal constructor
45
46 fX = x;
47 fY = y;
48 fZ = z;
49 fZout = 0.;
50 fNpoints = n;
51 fOffsetX = 0;
52 fOffsetY = 0;
53 fScaleFactorX = 0;
54 fScaleFactorY = 0;
55 fNdt = 0;
56 fXNmax = 0;
57 fXNmin = 0;
58 fYNmin = 0;
59 fYNmax = 0;
60
62
63}
64
65/// set the input points
66void Delaunay2D::SetInputPoints(int n, const double * x, const double * y, const double * z,
67 double xmin, double xmax, double ymin, double ymax) {
68
69
70 fInit = kFALSE;
71
72 if (n == 0 || !x || !y || !z ) return;
73
74 if (xmin >= xmax) {
75 xmin = *std::min_element(x, x+n);
76 xmax = *std::max_element(x, x+n);
77
78 ymin = *std::min_element(y, y+n);
79 ymax = *std::max_element(y, y+n);
80 }
81
82 fOffsetX = -(xmax+xmin)/2.;
83 fOffsetY = -(ymax+ymin)/2.;
84
85 if ( (xmax-xmin) != 0 ) {
86 fScaleFactorX = 1./(xmax-xmin);
87 fXNmax = Linear_transform(xmax, fOffsetX, fScaleFactorX); //xTransformer(xmax);
88 fXNmin = Linear_transform(xmin, fOffsetX, fScaleFactorX); //xTransformer(xmin);
89 } else {
90 // we can't find triangle in this case
91 fInit = true;
92 }
93
94 if (ymax-ymin != 0) {
95 fScaleFactorY = 1./(ymax-ymin);
96 fYNmax = Linear_transform(ymax, fOffsetY, fScaleFactorY); //yTransformer(ymax);
97 fYNmin = Linear_transform(ymin, fOffsetY, fScaleFactorY); //yTransformer(ymin);
98 } else {
99 fInit = true;
100 }
101
102 fXCellStep = 0.;
103 fYCellStep = 0.;
104}
105
106//______________________________________________________________________________
107double Delaunay2D::Interpolate(double x, double y)
108{
109 // Return the interpolated z value corresponding to the given (x,y) point
110
111 // Initialise the Delaunay algorithm if needed.
112 // CreateTrianglesDataStructure computes fXoffset, fYoffset,
113 // fXScaleFactor and fYScaleFactor;
114 // needed in this function.
116
117 // handle case no triangles are found return default value (i.e. 0)
118 // to do: if points are aligned in one direction we could return in
119 // some case the 1d interpolated value
120 if (fNdt == 0) {
121 return fZout;
122 }
123
124 // Find the z value corresponding to the point (x,y).
125 double xx, yy;
126 xx = Linear_transform(x, fOffsetX, fScaleFactorX); //xx = xTransformer(x);
127 yy = Linear_transform(y, fOffsetY, fScaleFactorY); //yy = yTransformer(y);
128 double zz = DoInterpolateNormalized(xx, yy);
129
130 // the case of points on a regular grid (i.e. points on triangle edges) it is now handles in
131 // DoInterpolateNormalized
132
133 return zz;
134}
135
136//______________________________________________________________________________
138{
139
140 if (fInit)
141 return;
142 else
143 fInit = kTRUE;
144
145 // Function used internally only. It creates the data structures needed to
146 // compute the Delaunay triangles.
147
148 // Offset fX and fY so they average zero, and scale so the average
149 // of the X and Y ranges is one. The normalized version of fX and fY used
150 // in Interpolate.
151
152 DoNormalizePoints(); // call backend specific point normalization
153
154 DoFindTriangles(); // call backend specific triangle finding
155
156 fNdt = fTriangles.size();
157}
158
159// backend specific implementations
160
161// CDT implementation (default case)
162
163/// CDT implementation for points normalization
165 for (Int_t n = 0; n < fNpoints; n++) {
168 }
169
170 //also initialize fXCellStep and FYCellStep
173}
174
175/// CDT implementation for finding all the triangles
177
178 int i;
179 std::vector<CDT::V2d<double>> points(fNpoints);
180 for (i = 0; i < fNpoints; ++i) points[i] = CDT::V2d<double>(fXN[i], fYN[i]);
181 CDT::RemoveDuplicates(points);
182 if (fNpoints-points.size() > 0)
183 Warning("DoFindTriangles",
184 "This TGraph2D has duplicated vertices. To remove them call RemoveDuplicates before drawing");
185
186 CDT::Triangulation<double> cdt;
187 cdt.insertVertices(points);
188 cdt.eraseSuperTriangle();
189
190 auto AllTriangles = cdt.triangles;
191 auto AllVertices = cdt.vertices;
192 int NumberOfTriangles = cdt.triangles.size();
193
195
196 for(i = 0; i < NumberOfTriangles; i++){
197 Triangle tri;
198 const auto& t = AllTriangles[i];
199
200 const auto& v0 = AllVertices[t.vertices[0]];
201 tri.x[0] = v0.x;
202 tri.y[0] = v0.y;
203 tri.idx[0] = t.vertices[0];
204
205 const auto& v1 = AllVertices[t.vertices[1]];
206 tri.x[1] = v1.x;
207 tri.y[1] = v1.y;
208 tri.idx[1] = t.vertices[1];
209
210 const auto& v2 = AllVertices[t.vertices[2]];
211 tri.x[2] = v2.x;
212 tri.y[2] = v2.y;
213 tri.idx[2] = t.vertices[2];
214
215 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]) );
216
217 fTriangles[i] = tri;
218
219 auto bx = std::minmax({tri.x[0], tri.x[1], tri.x[2]});
220 auto by = std::minmax({tri.y[0], tri.y[1], tri.y[2]});
221
222 unsigned int cellXmin = CellX(bx.first);
223 unsigned int cellXmax = CellX(bx.second);
224
225 unsigned int cellYmin = CellY(by.first);
226 unsigned int cellYmax = CellY(by.second);
227
228 for(unsigned int j = cellXmin; j <= cellXmax; j++) {
229 for(unsigned int k = cellYmin; k <= cellYmax; k++) {
230 fCells[Cell(j,k)].insert(i);
231 }
232 }
233 }
234}
235
236/// Triangle implementation for interpolation
237/// Finds the Delaunay triangle that the point (xi,yi) sits in (if any) and
238/// calculate a z-value for it by linearly interpolating the z-values that
239/// make up that triangle.
240/// Relay that all the triangles have been found before
241/// see comment in class description (in Delaunay2D.h) for implementation details:
242/// finding barycentric coordinates and computing the interpolation
243double Delaunay2D::DoInterpolateNormalized(double xx, double yy)
244{
245
246 // compute barycentric coordinates of a point P(xx,yy,zz)
247 auto bayCoords = [&](const unsigned int t) -> std::tuple<double, double, double> {
248 double la = ((fTriangles[t].y[1] - fTriangles[t].y[2]) * (xx - fTriangles[t].x[2]) +
249 (fTriangles[t].x[2] - fTriangles[t].x[1]) * (yy - fTriangles[t].y[2])) *
250 fTriangles[t].invDenom;
251 double lb = ((fTriangles[t].y[2] - fTriangles[t].y[0]) * (xx - fTriangles[t].x[2]) +
252 (fTriangles[t].x[0] - fTriangles[t].x[2]) * (yy - fTriangles[t].y[2])) *
253 fTriangles[t].invDenom;
254
255 return std::make_tuple(la, lb, (1 - la - lb));
256 };
257
258 // function to test if a point with barycentric coordinates (a,b,c) is inside the triangle
259 // If the point is outside one or more of the coordinate are negative.
260 // If the point is on a triangle edge, one of the coordinate (the one not part of the edge) is zero.
261 // Due to numerical error, it can happen that if the point is at the edge the result is a small negative value.
262 // Use then a tolerance (of - eps) to still consider the point within the triangle
263 auto inTriangle = [](const std::tuple<double, double, double> &coords) -> bool {
264 constexpr double eps = -4 * std::numeric_limits<double>::epsilon();
265 return std::get<0>(coords) > eps && std::get<1>(coords) > eps && std::get<2>(coords) > eps;
266 };
267
268 int cX = CellX(xx);
269 int cY = CellY(yy);
270
271 if (cX < 0 || cX > fNCells || cY < 0 || cY > fNCells)
272 return fZout; // TODO some more fancy interpolation here
273
274 for (unsigned int t : fCells[Cell(cX, cY)]) {
275
276 auto coords = bayCoords(t);
277
278 // std::cout << "result of bayCoords " << std::get<0>(coords) <<
279 // " " << std::get<1>(coords) << " " << std::get<2>(coords) << std::endl;
280
281 if (inTriangle(coords)) {
282
283 // we found the triangle -> interpolate using the barycentric interpolation
284
285 return std::get<0>(coords) * fZ[fTriangles[t].idx[0]] + std::get<1>(coords) * fZ[fTriangles[t].idx[1]] +
286 std::get<2>(coords) * fZ[fTriangles[t].idx[2]];
287 }
288 }
289
290 // no triangle found return standard value
291 return fZout;
292}
293
294} // namespace Math
295} // namespace ROOT
constexpr Bool_t kFALSE
Definition RtypesCore.h:109
constexpr Bool_t kTRUE
Definition RtypesCore.h:108
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:252
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t points
float xmin
float ymin
float xmax
float ymax
int fNpoints
! Number of data points
Definition Delaunay2D.h:158
double fXNmin
! Minimum value of fXN
Definition Delaunay2D.h:164
std::set< unsigned int > fCells[(fNCells+1) *(fNCells+1)]
! grid cells with containing triangles
Definition Delaunay2D.h:188
int fNdt
! Number of Delaunay triangles found
Definition Delaunay2D.h:157
double DoInterpolateNormalized(double x, double y)
internal method to compute the interpolation
int CellY(double y) const
Definition Delaunay2D.h:198
double Interpolate(double x, double y)
Return the Interpolated z value corresponding to the given (x,y) point.
const double * fZ
! Pointer to Z array
Definition Delaunay2D.h:162
double fXNmax
! Maximum value of fXN
Definition Delaunay2D.h:165
double fZout
! Height for points lying outside the convex hull
Definition Delaunay2D.h:175
double fOffsetY
! Normalization offset Y
Definition Delaunay2D.h:170
Triangles fTriangles
! Triangles of Triangulation
Definition Delaunay2D.h:180
double Linear_transform(double x, double offset, double factor)
Definition Delaunay2D.h:134
double fYCellStep
! inverse denominator to calculate X cell = fNCells / (fYNmax - fYNmin)
Definition Delaunay2D.h:187
std::vector< double > fYN
! normalized Y
Definition Delaunay2D.h:183
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
void FindAllTriangles()
Find all triangles.
static const int fNCells
! number of cells to divide the normalized space
Definition Delaunay2D.h:185
bool fInit
! True if FindAllTriangles() has been performed
Definition Delaunay2D.h:177
unsigned int Cell(unsigned int x, unsigned int y) const
Definition Delaunay2D.h:190
std::vector< double > fXN
! normalized X
Definition Delaunay2D.h:182
double fXCellStep
! inverse denominator to calculate X cell = fNCells / (fXNmax - fXNmin)
Definition Delaunay2D.h:186
double fYNmin
! Minimum value of fYN
Definition Delaunay2D.h:166
double fOffsetX
! Normalization offset X
Definition Delaunay2D.h:169
const double * fY
! Pointer to Y array
Definition Delaunay2D.h:161
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
const double * fX
! Pointer to X array (managed externally)
Definition Delaunay2D.h:160
void DoNormalizePoints()
internal function to normalize the points.
double fYNmax
! Maximum value of fYN
Definition Delaunay2D.h:167
int NumberOfTriangles() const
return the number of triangles
Definition Delaunay2D.h:111
double fScaleFactorY
! Normalization factor Y
Definition Delaunay2D.h:173
double fScaleFactorX
! Normalization factor X
Definition Delaunay2D.h:172
void DoFindTriangles()
internal function to find the triangle
int CellX(double x) const
Definition Delaunay2D.h:194
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
Namespace for new Math classes and functions.