Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TGraphDelaunay.cxx
Go to the documentation of this file.
1// @(#)root/hist:$Id: TGraphDelaunay.cxx,v 1.00
2// Author: Olivier Couet, Luke Jones (Royal Holloway, University of London)
3
4/*************************************************************************
5 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
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#include "TMath.h"
13#include "TGraph2D.h"
14#include "TGraphDelaunay.h"
15
16
17
18/** \class TGraphDelaunay
19 \ingroup Graphs
20TGraphDelaunay generates a Delaunay triangulation of a TGraph2D. This
21triangulation code derives from an implementation done by Luke Jones
22(Royal Holloway, University of London) in April 2002 in the PAW context.
23
24This software cannot be guaranteed to work under all circumstances. They
25were originally written to work with a few hundred points in an XY space
26with similar X and Y ranges.
27
28Definition of Delaunay triangulation (After B. Delaunay):
29For a set S of points in the Euclidean plane, the unique triangulation DT(S)
30of S such that no point in S is inside the circumcircle of any triangle in
31DT(S). DT(S) is the dual of the Voronoi diagram of S. If n is the number of
32points in S, the Voronoi diagram of S is the partitioning of the plane
33containing S points into n convex polygons such that each polygon contains
34exactly one point and every point in a given polygon is closer to its
35central point than to any other. A Voronoi diagram is sometimes also known
36as a Dirichlet tessellation.
37
38\image html tgraph2d_delaunay.png
39
40[This applet](http://www.cs.cornell.edu/Info/People/chew/Delaunay.html) gives a nice
41practical view of Delaunay triangulation and Voronoi diagram.
42*/
43
44
45////////////////////////////////////////////////////////////////////////////////
46/// TGraphDelaunay default constructor
47
49 : TNamed("TGraphDelaunay","TGraphDelaunay")
50{
51 fGraph2D = nullptr;
52 fX = nullptr;
53 fY = nullptr;
54 fZ = nullptr;
55 fNpoints = 0;
56 fTriedSize = 0;
57 fZout = 0.;
58 fNdt = 0;
59 fNhull = 0;
60 fHullPoints = nullptr;
61 fXN = nullptr;
62 fYN = nullptr;
63 fOrder = nullptr;
64 fDist = nullptr;
65 fPTried = nullptr;
66 fNTried = nullptr;
67 fMTried = nullptr;
68 fInit = kFALSE;
69 fXNmin = 0.;
70 fXNmax = 0.;
71 fYNmin = 0.;
72 fYNmax = 0.;
73 fXoffset = 0.;
74 fYoffset = 0.;
75 fXScaleFactor = 0.;
76 fYScaleFactor = 0.;
77
78 SetMaxIter();
79}
80
81
82////////////////////////////////////////////////////////////////////////////////
83/// TGraphDelaunay normal constructor
84
86 : TNamed("TGraphDelaunay","TGraphDelaunay")
87{
88 fGraph2D = g;
89 fX = fGraph2D->GetX();
90 fY = fGraph2D->GetY();
91 fZ = fGraph2D->GetZ();
93 fTriedSize = 0;
94 fZout = 0.;
95 fNdt = 0;
96 fNhull = 0;
97 fHullPoints = nullptr;
98 fXN = nullptr;
99 fYN = nullptr;
100 fOrder = nullptr;
101 fDist = nullptr;
102 fPTried = nullptr;
103 fNTried = nullptr;
104 fMTried = nullptr;
105 fInit = kFALSE;
106 fXNmin = 0.;
107 fXNmax = 0.;
108 fYNmin = 0.;
109 fYNmax = 0.;
110 fXoffset = 0.;
111 fYoffset = 0.;
112 fXScaleFactor = 0.;
113 fYScaleFactor = 0.;
114
115 SetMaxIter();
116}
117
118
119////////////////////////////////////////////////////////////////////////////////
120/// TGraphDelaunay destructor.
121
123{
124 if (fPTried) delete [] fPTried;
125 if (fNTried) delete [] fNTried;
126 if (fMTried) delete [] fMTried;
127 if (fHullPoints) delete [] fHullPoints;
128 if (fOrder) delete [] fOrder;
129 if (fDist) delete [] fDist;
130 if (fXN) delete [] fXN;
131 if (fYN) delete [] fYN;
132
133 fPTried = nullptr;
134 fNTried = nullptr;
135 fMTried = nullptr;
136 fHullPoints = nullptr;
137 fOrder = nullptr;
138 fDist = nullptr;
139 fXN = nullptr;
140 fYN = nullptr;
141}
142
143
144////////////////////////////////////////////////////////////////////////////////
145/// Return the z value corresponding to the (x,y) point in fGraph2D
146
148{
149 // Initialise the Delaunay algorithm if needed.
150 // CreateTrianglesDataStructure computes fXoffset, fYoffset,
151 // fXScaleFactor and fYScaleFactor;
152 // needed in this function.
153 if (!fInit) {
155 FindHull();
156 fInit = kTRUE;
157 }
158
159 // Find the z value corresponding to the point (x,y).
160 Double_t xx, yy;
164
165 // Wrong zeros may appear when points sit on a regular grid.
166 // The following line try to avoid this problem.
167 if (zz==0) zz = Interpolate(xx+0.0001, yy);
168
169 return zz;
170}
171
172
173////////////////////////////////////////////////////////////////////////////////
174/// Function used internally only. It creates the data structures needed to
175/// compute the Delaunay triangles.
176
178{
179 // Offset fX and fY so they average zero, and scale so the average
180 // of the X and Y ranges is one. The normalized version of fX and fY used
181 // in Interpolate.
186 fXoffset = -(xmax+xmin)/2.;
187 fYoffset = -(ymax+ymin)/2.;
188 fXScaleFactor = 1./(xmax-xmin);
189 fYScaleFactor = 1./(ymax-ymin);
194 fXN = new Double_t[fNpoints+1];
195 fYN = new Double_t[fNpoints+1];
196 for (Int_t n=0; n<fNpoints; n++) {
197 fXN[n+1] = (fX[n]+fXoffset)*fXScaleFactor;
198 fYN[n+1] = (fY[n]+fYoffset)*fYScaleFactor;
199 }
200
201 // If needed, creates the arrays to hold the Delaunay triangles.
202 // A maximum number of 2*fNpoints is guessed. If more triangles will be
203 // find, FillIt will automatically enlarge these arrays.
205 fPTried = new Int_t[fTriedSize];
206 fNTried = new Int_t[fTriedSize];
207 fMTried = new Int_t[fTriedSize];
208}
209
210
211////////////////////////////////////////////////////////////////////////////////
212/// Is point e inside the triangle t1-t2-t3 ?
213
215{
216 Double_t x[4],y[4],xp, yp;
217 x[0] = fXN[t1];
218 x[1] = fXN[t2];
219 x[2] = fXN[t3];
220 x[3] = x[0];
221 y[0] = fYN[t1];
222 y[1] = fYN[t2];
223 y[2] = fYN[t3];
224 y[3] = y[0];
225 xp = fXN[e];
226 yp = fYN[e];
227 return TMath::IsInside(xp, yp, 4, x, y);
228}
229
230
231////////////////////////////////////////////////////////////////////////////////
232/// Files the triangle defined by the 3 vertices p, n and m into the
233/// fxTried arrays. If these arrays are to small they are automatically
234/// expanded.
235
237{
238 Bool_t swap;
239 Int_t tmp, ps = p, ns = n, ms = m;
240
241 // order the vertices before storing them
242L1:
243 swap = kFALSE;
244 if (ns > ps) { tmp = ps; ps = ns; ns = tmp; swap = kTRUE;}
245 if (ms > ns) { tmp = ns; ns = ms; ms = tmp; swap = kTRUE;}
246 if (swap) goto L1;
247
248 // expand the triangles storage if needed
249 if (fNdt>=fTriedSize) {
251 Int_t *savep = new Int_t [newN];
252 Int_t *saven = new Int_t [newN];
253 Int_t *savem = new Int_t [newN];
256 delete [] fPTried;
259 delete [] fNTried;
262 delete [] fMTried;
263 fPTried = savep;
264 fNTried = saven;
265 fMTried = savem;
267 }
268
269 // store a new Delaunay triangle
270 fNdt++;
271 fPTried[fNdt-1] = ps;
272 fNTried[fNdt-1] = ns;
273 fMTried[fNdt-1] = ms;
274}
275
276
277////////////////////////////////////////////////////////////////////////////////
278/// Attempt to find all the Delaunay triangles of the point set. It is not
279/// guaranteed that it will fully succeed, and no check is made that it has
280/// fully succeeded (such a check would be possible by referencing the points
281/// that make up the convex hull). The method is to check if each triangle
282/// shares all three of its sides with other triangles. If not, a point is
283/// generated just outside the triangle on the side(s) not shared, and a new
284/// triangle is found for that point. If this method is not working properly
285/// (many triangles are not being found) it's probably because the new points
286/// are too far beyond or too close to the non-shared sides. Fiddling with
287/// the size of the `alittlebit' parameter may help.
288
290{
291 if (fAllTri) return; else fAllTri = kTRUE;
292
295 Int_t t1,t2,pa,na,ma,pb,nb,mb,p1=0,p2=0,m,n,p3=0;
296 Bool_t s[3];
297 Double_t alittlebit = 0.0001;
298
299 // start with a point that is guaranteed to be inside the hull (the
300 // centre of the hull). The starting point is shifted "a little bit"
301 // otherwise, in case of triangles aligned on a regular grid, we may
302 // found none of them.
303 xcntr = 0;
304 ycntr = 0;
305 for (n=1; n<=fNhull; n++) {
308 }
311 // and calculate it's triangle
313
314 // loop over all Delaunay triangles (including those constantly being
315 // produced within the loop) and check to see if their 3 sides also
316 // correspond to the sides of other Delaunay triangles, i.e. that they
317 // have all their neighbours.
318 t1 = 1;
319 while (t1 <= fNdt) {
320 // get the three points that make up this triangle
321 pa = fPTried[t1-1];
322 na = fNTried[t1-1];
323 ma = fMTried[t1-1];
324
325 // produce three integers which will represent the three sides
326 s[0] = kFALSE;
327 s[1] = kFALSE;
328 s[2] = kFALSE;
329 // loop over all other Delaunay triangles
330 for (t2=1; t2<=fNdt; t2++) {
331 if (t2 != t1) {
332 // get the points that make up this triangle
333 pb = fPTried[t2-1];
334 nb = fNTried[t2-1];
335 mb = fMTried[t2-1];
336 // do triangles t1 and t2 share a side?
337 if ((pa==pb && na==nb) || (pa==pb && na==mb) || (pa==nb && na==mb)) {
338 // they share side 1
339 s[0] = kTRUE;
340 } else if ((pa==pb && ma==nb) || (pa==pb && ma==mb) || (pa==nb && ma==mb)) {
341 // they share side 2
342 s[1] = kTRUE;
343 } else if ((na==pb && ma==nb) || (na==pb && ma==mb) || (na==nb && ma==mb)) {
344 // they share side 3
345 s[2] = kTRUE;
346 }
347 }
348 // if t1 shares all its sides with other Delaunay triangles then
349 // forget about it
350 if (s[0] && s[1] && s[2]) continue;
351 }
352 // Looks like t1 is missing a neighbour on at least one side.
353 // For each side, take a point a little bit beyond it and calculate
354 // the Delaunay triangle for that point, this should be the triangle
355 // which shares the side.
356 for (m=1; m<=3; m++) {
357 if (!s[m-1]) {
358 // get the two points that make up this side
359 if (m == 1) {
360 p1 = pa;
361 p2 = na;
362 p3 = ma;
363 } else if (m == 2) {
364 p1 = pa;
365 p2 = ma;
366 p3 = na;
367 } else if (m == 3) {
368 p1 = na;
369 p2 = ma;
370 p3 = pa;
371 }
372 // get the coordinates of the centre of this side
373 xm = (fXN[p1]+fXN[p2])/2.;
374 ym = (fYN[p1]+fYN[p2])/2.;
375 // we want to add a little to these coordinates to get a point just
376 // outside the triangle; (sx,sy) will be the vector that represents
377 // the side
378 sx = fXN[p1]-fXN[p2];
379 sy = fYN[p1]-fYN[p2];
380 // (nx,ny) will be the normal to the side, but don't know if it's
381 // pointing in or out yet
382 nx = sy;
383 ny = -sx;
384 nn = TMath::Sqrt(nx*nx+ny*ny);
385 nx = nx/nn;
386 ny = ny/nn;
387 mx = fXN[p3]-xm;
388 my = fYN[p3]-ym;
389 mdotn = mx*nx+my*ny;
390 if (mdotn > 0) {
391 // (nx,ny) is pointing in, we want it pointing out
392 nx = -nx;
393 ny = -ny;
394 }
395 // increase/decrease xm and ym a little to produce a point
396 // just outside the triangle (ensuring that the amount added will
397 // be large enough such that it won't be lost in rounding errors)
399 xx = xm+nx*a;
400 yy = ym+ny*a;
401 // try and find a new Delaunay triangle for this point
403
404 // this side of t1 should now, hopefully, if it's not part of the
405 // hull, be shared with a new Delaunay triangle just calculated by Interpolate
406 }
407 }
408 t1++;
409 }
410}
411
412
413////////////////////////////////////////////////////////////////////////////////
414/// Finds those points which make up the convex hull of the set. If the xy
415/// plane were a sheet of wood, and the points were nails hammered into it
416/// at the respective coordinates, then if an elastic band were stretched
417/// over all the nails it would form the shape of the convex hull. Those
418/// nails in contact with it are the points that make up the hull.
419
421{
423 Bool_t in;
424
426
427 nhull_tmp = 0;
428 for(n=1; n<=fNpoints; n++) {
429 // if the point is not inside the hull of the set of all points
430 // bar it, then it is part of the hull of the set of all points
431 // including it
432 in = InHull(n,n);
433 if (!in) {
434 // cannot increment fNhull directly - InHull needs to know that
435 // the hull has not yet been completely found
436 nhull_tmp++;
438 }
439 }
441}
442
443
444////////////////////////////////////////////////////////////////////////////////
445/// Is point e inside the hull defined by all points apart from x ?
446
448{
449 Int_t n1,n2,n,m,ntry;
452
454
455 xx = fXN[e];
456 yy = fYN[e];
457
458 if (fNhull > 0) {
459 // The hull has been found - no need to use any points other than
460 // those that make up the hull
461 ntry = fNhull;
462 } else {
463 // The hull has not yet been found, will have to try every point
464 ntry = fNpoints;
465 }
466
467 // n1 and n2 will represent the two points most separated by angle
468 // from point e. Initially the angle between them will be <180 degs.
469 // But subsequent points will increase the n1-e-n2 angle. If it
470 // increases above 180 degrees then point e must be surrounded by
471 // points - it is not part of the hull.
472 n1 = 1;
473 n2 = 2;
474 if (n1 == x) {
475 n1 = n2;
476 n2++;
477 } else if (n2 == x) {
478 n2++;
479 }
480
481 // Get the angle n1-e-n2 and set it to lastdphi
482 dx1 = xx-fXN[n1];
483 dy1 = yy-fYN[n1];
484 dx2 = xx-fXN[n2];
485 dy2 = yy-fYN[n2];
489 if (dphi < 0) dphi = dphi+TMath::TwoPi();
490 lastdphi = dphi;
491 for (n=1; n<=ntry; n++) {
492 if (fNhull > 0) {
493 // Try hull point n
494 m = fHullPoints[n-1];
495 } else {
496 m = n;
497 }
498 if ((m!=n1) && (m!=n2) && (m!=x)) {
499 // Can the vector e->m be represented as a sum with positive
500 // coefficients of vectors e->n1 and e->n2?
501 dx1 = xx-fXN[n1];
502 dy1 = yy-fYN[n1];
503 dx2 = xx-fXN[n2];
504 dy2 = yy-fYN[n2];
505 dx3 = xx-fXN[m];
506 dy3 = yy-fYN[m];
507
508 dd1 = (dx2*dy1-dx1*dy2);
509 dd2 = (dx1*dy2-dx2*dy1);
510
511 if (dd1*dd2!=0) {
512 u = (dx2*dy3-dx3*dy2)/dd1;
513 v = (dx1*dy3-dx3*dy1)/dd2;
514 if ((u<0) || (v<0)) {
515 // No, it cannot - point m does not lie in-between n1 and n2 as
516 // viewed from e. Replace either n1 or n2 to increase the
517 // n1-e-n2 angle. The one to replace is the one which makes the
518 // smallest angle with e->m
521 if (vNv1 > vNv2) {
522 n1 = m;
525 } else {
526 n2 = m;
529 }
531 if (dphi < 0) dphi = dphi+TMath::TwoPi();
532 if (((dphi-TMath::Pi())*(lastdphi-TMath::Pi())) < 0) {
533 // The addition of point m means the angle n1-e-n2 has risen
534 // above 180 degs, the point is in the hull.
535 goto L10;
536 }
537 lastdphi = dphi;
538 }
539 }
540 }
541 }
542 // Point e is not surrounded by points - it is not in the hull.
543 goto L999;
544L10:
546L999:
547 return deTinhull;
548}
549
550
551////////////////////////////////////////////////////////////////////////////////
552/// Finds the z-value at point e given that it lies
553/// on the plane defined by t1,t2,t3
554
556{
557 Int_t tmp;
558 Bool_t swap;
559 Double_t x1,x2,x3,y1,y2,y3,f1,f2,f3,u,v,w;
560
561 Int_t t1 = TI1;
562 Int_t t2 = TI2;
563 Int_t t3 = TI3;
564
565 // order the vertices
566L1:
567 swap = kFALSE;
568 if (t2 > t1) { tmp = t1; t1 = t2; t2 = tmp; swap = kTRUE;}
569 if (t3 > t2) { tmp = t2; t2 = t3; t3 = tmp; swap = kTRUE;}
570 if (swap) goto L1;
571
572 x1 = fXN[t1];
573 x2 = fXN[t2];
574 x3 = fXN[t3];
575 y1 = fYN[t1];
576 y2 = fYN[t2];
577 y3 = fYN[t3];
578 f1 = fZ[t1-1];
579 f2 = fZ[t2-1];
580 f3 = fZ[t3-1];
581 u = (f1*(y2-y3)+f2*(y3-y1)+f3*(y1-y2))/(x1*(y2-y3)+x2*(y3-y1)+x3*(y1-y2));
582 v = (f1*(x2-x3)+f2*(x3-x1)+f3*(x1-x2))/(y1*(x2-x3)+y2*(x3-x1)+y3*(x1-x2));
583 w = f1-u*x1-v*y1;
584
585 return u*fXN[e]+v*fYN[e]+w;
586}
587
588
589////////////////////////////////////////////////////////////////////////////////
590/// Finds the Delaunay triangle that the point (xi,yi) sits in (if any) and
591/// calculate a z-value for it by linearly interpolating the z-values that
592/// make up that triangle.
593
595{
597
598 Int_t it, ntris_tried, p, n, m;
599 Int_t i,j,k,l,z,f,d,o1,o2,a,b,t1,t2,t3;
604
607
608 // initialise the Delaunay algorithm if needed
609 if (!fInit) {
611 FindHull();
612 fInit = kTRUE;
613 }
614
615 // create vectors needed for sorting
616 if (!fOrder) {
617 fOrder = new Int_t[fNpoints];
618 fDist = new Double_t[fNpoints];
619 }
620
621 // the input point will be point zero.
622 fXN[0] = xx;
623 fYN[0] = yy;
624
625 // set the output value to the default value for now
626 thevalue = fZout;
627
628 // some counting
629 ntris_tried = 0;
630
631 // no point in proceeding if xx or yy are silly
632 if ((xx>fXNmax) || (xx<fXNmin) || (yy>fYNmax) || (yy<fYNmin)) return thevalue;
633
634 // check existing Delaunay triangles for a good one
635 for (it=1; it<=fNdt; it++) {
636 p = fPTried[it-1];
637 n = fNTried[it-1];
638 m = fMTried[it-1];
639 // p, n and m form a previously found Delaunay triangle, does it
640 // enclose the point?
641 if (Enclose(p,n,m,0)) {
642 // yes, we have the triangle
644 return thevalue;
645 }
646 }
647
648 // is this point inside the convex hull?
649 shouldbein = InHull(0,-1);
650 if (!shouldbein) return thevalue;
651
652 // it must be in a Delaunay triangle - find it...
653
654 // order mass points by distance in mass plane from desired point
655 for (it=1; it<=fNpoints; it++) {
656 vxN = fXN[it];
657 vyN = fYN[it];
658 fDist[it-1] = TMath::Sqrt((xx-vxN)*(xx-vxN)+(yy-vyN)*(yy-vyN));
659 }
660
661 // sort array 'fDist' to find closest points
663 for (it=0; it<fNpoints; it++) fOrder[it]++;
664
665 // loop over triplets of close points to try to find a triangle that
666 // encloses the point.
667 for (k=3; k<=fNpoints; k++) {
668 m = fOrder[k-1];
669 for (j=2; j<=k-1; j++) {
670 n = fOrder[j-1];
671 for (i=1; i<=j-1; i++) {
672 p = fOrder[i-1];
673 if (ntris_tried > fMaxIter) {
674 // perhaps this point isn't in the hull after all
675/// Warning("Interpolate",
676/// "Abandoning the effort to find a Delaunay triangle (and thus interpolated z-value) for point %g %g"
677/// ,xx,yy);
678 return thevalue;
679 }
680 ntris_tried++;
681 // check the points aren't colinear
682 d1 = TMath::Sqrt((fXN[p]-fXN[n])*(fXN[p]-fXN[n])+(fYN[p]-fYN[n])*(fYN[p]-fYN[n]));
683 d2 = TMath::Sqrt((fXN[p]-fXN[m])*(fXN[p]-fXN[m])+(fYN[p]-fYN[m])*(fYN[p]-fYN[m]));
684 d3 = TMath::Sqrt((fXN[n]-fXN[m])*(fXN[n]-fXN[m])+(fYN[n]-fYN[m])*(fYN[n]-fYN[m]));
685 if ((d1+d2<=d3) || (d1+d3<=d2) || (d2+d3<=d1)) goto L90;
686
687 // does the triangle enclose the point?
688 if (!Enclose(p,n,m,0)) goto L90;
689
690 // is it a Delaunay triangle? (ie. are there any other points
691 // inside the circle that is defined by its vertices?)
692
693 // test the triangle for Delaunay'ness
694
695 // loop over all other points testing each to see if it's
696 // inside the triangle's circle
697 ndegen = 0;
698 for ( z=1; z<=fNpoints; z++) {
699 if ((z==p) || (z==n) || (z==m)) goto L50;
700 // An easy first check is to see if point z is inside the triangle
701 // (if it's in the triangle it's also in the circle)
702
703 // point z cannot be inside the triangle if it's further from (xx,yy)
704 // than the furthest pointing making up the triangle - test this
705 for (l=1; l<=fNpoints; l++) {
706 if (fOrder[l-1] == z) {
707 if ((l<i) || (l<j) || (l<k)) {
708 // point z is nearer to (xx,yy) than m, n or p - it could be in the
709 // triangle so call enclose to find out
710
711 // if it is inside the triangle this can't be a Delaunay triangle
712 if (Enclose(p,n,m,z)) goto L90;
713 } else {
714 // there's no way it could be in the triangle so there's no point
715 // calling enclose
716 goto L1;
717 }
718 }
719 }
720 // is point z colinear with any pair of the triangle points?
721L1:
722 if (((fXN[p]-fXN[z])*(fYN[p]-fYN[n])) == ((fYN[p]-fYN[z])*(fXN[p]-fXN[n]))) {
723 // z is colinear with p and n
724 a = p;
725 b = n;
726 } else if (((fXN[p]-fXN[z])*(fYN[p]-fYN[m])) == ((fYN[p]-fYN[z])*(fXN[p]-fXN[m]))) {
727 // z is colinear with p and m
728 a = p;
729 b = m;
730 } else if (((fXN[n]-fXN[z])*(fYN[n]-fYN[m])) == ((fYN[n]-fYN[z])*(fXN[n]-fXN[m]))) {
731 // z is colinear with n and m
732 a = n;
733 b = m;
734 } else {
735 a = 0;
736 b = 0;
737 }
738 if (a != 0) {
739 // point z is colinear with 2 of the triangle points, if it lies
740 // between them it's in the circle otherwise it's outside
741 if (fXN[a] != fXN[b]) {
742 if (((fXN[z]-fXN[a])*(fXN[z]-fXN[b])) < 0) {
743 goto L90;
744 } else if (((fXN[z]-fXN[a])*(fXN[z]-fXN[b])) == 0) {
745 // At least two points are sitting on top of each other, we will
746 // treat these as one and not consider this a 'multiple points lying
747 // on a common circle' situation. It is a sign something could be
748 // wrong though, especially if the two coincident points have
749 // different fZ's. If they don't then this is harmless.
750 Warning("Interpolate", "Two of these three points are coincident %d %d %d",a,b,z);
751 }
752 } else {
753 if (((fYN[z]-fYN[a])*(fYN[z]-fYN[b])) < 0) {
754 goto L90;
755 } else if (((fYN[z]-fYN[a])*(fYN[z]-fYN[b])) == 0) {
756 // At least two points are sitting on top of each other - see above.
757 Warning("Interpolate", "Two of these three points are coincident %d %d %d",a,b,z);
758 }
759 }
760 // point is outside the circle, move to next point
761 goto L50;
762 }
763
764 // if point z were to look at the triangle, which point would it see
765 // lying between the other two? (we're going to form a quadrilateral
766 // from the points, and then demand certain properties of that
767 // quadrilateral)
768 dxz[0] = fXN[p]-fXN[z];
769 dyz[0] = fYN[p]-fYN[z];
770 dxz[1] = fXN[n]-fXN[z];
771 dyz[1] = fYN[n]-fYN[z];
772 dxz[2] = fXN[m]-fXN[z];
773 dyz[2] = fYN[m]-fYN[z];
774 for(l=1; l<=3; l++) {
775 dx1 = dxz[l-1];
776 dx2 = dxz[l%3];
777 dx3 = dxz[(l+1)%3];
778 dy1 = dyz[l-1];
779 dy2 = dyz[l%3];
780 dy3 = dyz[(l+1)%3];
781
782 // u et v are used only to know their sign. The previous
783 // code computed them with a division which was long and
784 // might be a division by 0. It is now replaced by a
785 // multiplication.
786 u = (dy3*dx2-dx3*dy2)*(dy1*dx2-dx1*dy2);
787 v = (dy3*dx1-dx3*dy1)*(dy2*dx1-dx2*dy1);
788
789 if ((u>=0) && (v>=0)) {
790 // vector (dx3,dy3) is expressible as a sum of the other two vectors
791 // with positive coefficients -> i.e. it lies between the other two vectors
792 if (l == 1) {
793 f = m;
794 o1 = p;
795 o2 = n;
796 } else if (l == 2) {
797 f = p;
798 o1 = n;
799 o2 = m;
800 } else {
801 f = n;
802 o1 = m;
803 o2 = p;
804 }
805 goto L2;
806 }
807 }
808/// Error("Interpolate", "Should not get to here");
809 // may as well soldier on
810 f = m;
811 o1 = p;
812 o2 = n;
813L2:
814 // this is not a valid quadrilateral if the diagonals don't cross,
815 // check that points f and z lie on opposite side of the line o1-o2,
816 // this is true if the angle f-o1-z is greater than o2-o1-z and o2-o1-f
817 cfo1k = ((fXN[f]-fXN[o1])*(fXN[z]-fXN[o1])+(fYN[f]-fYN[o1])*(fYN[z]-fYN[o1]))/
818 TMath::Sqrt(((fXN[f]-fXN[o1])*(fXN[f]-fXN[o1])+(fYN[f]-fYN[o1])*(fYN[f]-fYN[o1]))*
819 ((fXN[z]-fXN[o1])*(fXN[z]-fXN[o1])+(fYN[z]-fYN[o1])*(fYN[z]-fYN[o1])));
820 co2o1k = ((fXN[o2]-fXN[o1])*(fXN[z]-fXN[o1])+(fYN[o2]-fYN[o1])*(fYN[z]-fYN[o1]))/
821 TMath::Sqrt(((fXN[o2]-fXN[o1])*(fXN[o2]-fXN[o1])+(fYN[o2]-fYN[o1])*(fYN[o2]-fYN[o1]))*
822 ((fXN[z]-fXN[o1])*(fXN[z]-fXN[o1]) + (fYN[z]-fYN[o1])*(fYN[z]-fYN[o1])));
823 co2o1f = ((fXN[o2]-fXN[o1])*(fXN[f]-fXN[o1])+(fYN[o2]-fYN[o1])*(fYN[f]-fYN[o1]))/
824 TMath::Sqrt(((fXN[o2]-fXN[o1])*(fXN[o2]-fXN[o1])+(fYN[o2]-fYN[o1])*(fYN[o2]-fYN[o1]))*
825 ((fXN[f]-fXN[o1])*(fXN[f]-fXN[o1]) + (fYN[f]-fYN[o1])*(fYN[f]-fYN[o1]) ));
826 if ((cfo1k>co2o1k) || (cfo1k>co2o1f)) {
827 // not a valid quadrilateral - point z is definitely outside the circle
828 goto L50;
829 }
830 // calculate the 2 internal angles of the quadrangle formed by joining
831 // points z and f to points o1 and o2, at z and f. If they sum to less
832 // than 180 degrees then z lies outside the circle
833 dko1 = TMath::Sqrt((fXN[z]-fXN[o1])*(fXN[z]-fXN[o1])+(fYN[z]-fYN[o1])*(fYN[z]-fYN[o1]));
834 dko2 = TMath::Sqrt((fXN[z]-fXN[o2])*(fXN[z]-fXN[o2])+(fYN[z]-fYN[o2])*(fYN[z]-fYN[o2]));
835 dfo1 = TMath::Sqrt((fXN[f]-fXN[o1])*(fXN[f]-fXN[o1])+(fYN[f]-fYN[o1])*(fYN[f]-fYN[o1]));
836 dfo2 = TMath::Sqrt((fXN[f]-fXN[o2])*(fXN[f]-fXN[o2])+(fYN[f]-fYN[o2])*(fYN[f]-fYN[o2]));
837 c1 = ((fXN[z]-fXN[o1])*(fXN[z]-fXN[o2])+(fYN[z]-fYN[o1])*(fYN[z]-fYN[o2]))/dko1/dko2;
838 c2 = ((fXN[f]-fXN[o1])*(fXN[f]-fXN[o2])+(fYN[f]-fYN[o1])*(fYN[f]-fYN[o2]))/dfo1/dfo2;
840
841 // sin_sum doesn't always come out as zero when it should do.
842 if (sin_sum < -1.E-6) {
843 // z is inside the circle, this is not a Delaunay triangle
844 goto L90;
845 } else if (TMath::Abs(sin_sum) <= 1.E-6) {
846 // point z lies on the circumference of the circle (within rounding errors)
847 // defined by the triangle, so there is potential for degeneracy in the
848 // triangle set (Delaunay triangulation does not give a unique way to split
849 // a polygon whose points lie on a circle into constituent triangles). Make
850 // a note of the additional point number.
851 ndegen++;
852 degen = z;
853 fdegen = f;
854 o1degen = o1;
855 o2degen = o2;
856 }
857L50:
858 continue;
859 }
860 // This is a good triangle
861 if (ndegen > 0) {
862 // but is degenerate with at least one other,
863 // haven't figured out what to do if more than 4 points are involved
864/// if (ndegen > 1) {
865/// Error("Interpolate",
866/// "More than 4 points lying on a circle. No decision making process formulated for triangulating this region in a non-arbitrary way %d %d %d %d",
867/// p,n,m,degen);
868/// return thevalue;
869/// }
870
871 // we have a quadrilateral which can be split down either diagonal
872 // (d<->f or o1<->o2) to form valid Delaunay triangles. Choose diagonal
873 // with highest average z-value. Whichever we choose we will have
874 // verified two triangles as good and two as bad, only note the good ones
875 d = degen;
876 f = fdegen;
877 o1 = o1degen;
878 o2 = o2degen;
879 if ((fZ[o1-1]+fZ[o2-1]) > (fZ[d-1]+fZ[f-1])) {
880 // best diagonalisation of quadrilateral is current one, we have
881 // the triangle
882 t1 = p;
883 t2 = n;
884 t3 = m;
885 // file the good triangles
886 FileIt(p, n, m);
887 FileIt(d, o1, o2);
888 } else {
889 // use other diagonal to split quadrilateral, use triangle formed by
890 // point f, the degnerate point d and whichever of o1 and o2 create
891 // an enclosing triangle
892 t1 = f;
893 t2 = d;
894 if (Enclose(f,d,o1,0)) {
895 t3 = o1;
896 } else {
897 t3 = o2;
898 }
899 // file the good triangles
900 FileIt(f, d, o1);
901 FileIt(f, d, o2);
902 }
903 } else {
904 // this is a Delaunay triangle, file it
905 FileIt(p, n, m);
906 t1 = p;
907 t2 = n;
908 t3 = m;
909 }
910 // do the interpolation
912 return thevalue;
913L90:
914 continue;
915 }
916 }
917 }
918 if (shouldbein) {
919 Error("Interpolate",
920 "Point outside hull when expected inside: this point could be dodgy %g %g %d",
921 xx, yy, ntris_tried);
922 }
923 return thevalue;
924}
925
926
927////////////////////////////////////////////////////////////////////////////////
928/// Defines the number of triangles tested for a Delaunay triangle
929/// (number of iterations) before abandoning the search
930
936
937
938////////////////////////////////////////////////////////////////////////////////
939/// Sets the histogram bin height for points lying outside the convex hull ie:
940/// the bins in the margin.
941
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define g(i)
Definition RSha256.hxx:105
#define a(i)
Definition RSha256.hxx:99
#define e(i)
Definition RSha256.hxx:103
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char x2
Option_t Option_t TPoint TPoint const char x1
Option_t Option_t TPoint TPoint const char y2
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char mx
Option_t Option_t TPoint TPoint const char y1
float xmin
float ymin
float xmax
float ymax
Graphics object made of three arrays X, Y and Z with the same number of points each.
Definition TGraph2D.h:41
Double_t * GetY() const
Definition TGraph2D.h:123
Double_t GetYmin() const
Returns the Y minimum.
Double_t * GetX() const
Definition TGraph2D.h:122
Double_t GetXmin() const
Returns the X minimum.
Double_t GetXmax() const
Returns the X maximum.
Int_t GetN() const
Definition TGraph2D.h:121
Double_t GetYmax() const
Returns the Y maximum.
Double_t * GetZ() const
Definition TGraph2D.h:124
Int_t fNpoints
! Number of data points in fGraph2D
Double_t ComputeZ(Double_t x, Double_t y)
Return the z value corresponding to the (x,y) point in fGraph2D.
Int_t * fNTried
! Delaunay triangles storage of size fNdt
Double_t * fY
! Pointer to fGraph2D->fY
Double_t fXNmax
! Maximum value of fXN
Bool_t InHull(Int_t E, Int_t X) const
Is point e inside the hull defined by all points apart from x ?
Double_t fXNmin
! Minimum value of fXN
Double_t InterpolateOnPlane(Int_t TI1, Int_t TI2, Int_t TI3, Int_t E) const
Finds the z-value at point e given that it lies on the plane defined by t1,t2,t3.
Double_t * fYN
! fGraph2D vectors normalized of size fNpoints
Double_t fYoffset
! Parameters used to normalize user data
void FindHull()
Finds those points which make up the convex hull of the set.
void SetMarginBinsContent(Double_t z=0.)
Sets the histogram bin height for points lying outside the convex hull ie: the bins in the margin.
Double_t fXoffset
!
Double_t * fDist
! Array used to order mass points by distance
void FileIt(Int_t P, Int_t N, Int_t M)
Files the triangle defined by the 3 vertices p, n and m into the fxTried arrays.
Double_t fYNmin
! Minimum value of fYN
Int_t fTriedSize
! Real size of the fxTried arrays
Double_t * fX
! Pointer to fGraph2D->fX
TGraph2D * fGraph2D
! 2D graph containing the user data
void FindAllTriangles()
Attempt to find all the Delaunay triangles of the point set.
Bool_t fAllTri
! True if FindAllTriangles() has been performed on fGraph2D
void SetMaxIter(Int_t n=100000)
Defines the number of triangles tested for a Delaunay triangle (number of iterations) before abandoni...
Int_t fMaxIter
! Maximum number of iterations to find Delaunay triangles
Bool_t fInit
! True if CreateTrianglesDataStructure() and FindHull() have been performed
Int_t * fOrder
! Array used to order mass points by distance
Bool_t Enclose(Int_t T1, Int_t T2, Int_t T3, Int_t Ex) const
Is point e inside the triangle t1-t2-t3 ?
Double_t fXScaleFactor
!
Int_t fNdt
! Number of Delaunay triangles found
Double_t * fZ
! Pointer to fGraph2D->fZ
Double_t fYNmax
! Maximum value of fYN
~TGraphDelaunay() override
TGraphDelaunay destructor.
Double_t fZout
! Histogram bin height for points lying outside the convex hull
Double_t fYScaleFactor
!
void CreateTrianglesDataStructure()
Function used internally only.
Int_t fNhull
! Number of points in the hull
Double_t Interpolate(Double_t x, Double_t y)
Finds the Delaunay triangle that the point (xi,yi) sits in (if any) and calculate a z-value for it by...
TGraphDelaunay()
TGraphDelaunay default constructor.
Int_t * fHullPoints
! Hull points of size fNhull
Double_t * fXN
! fGraph2D vectors normalized of size fNpoints
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1057
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1071
Double_t y[n]
Definition legend1.C:17
return c1
Definition legend1.C:41
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
TF1 * f1
Definition legend1.C:11
return c2
Definition legend2.C:14
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:251
Bool_t IsInside(T xp, T yp, Int_t np, T *x, T *y)
Function which returns kTRUE if point xp,yp lies inside the polygon defined by the np points in array...
Definition TMath.h:1320
Double_t ATan2(Double_t y, Double_t x)
Returns the principal value of the arc tangent of y/x, expressed in radians.
Definition TMath.h:657
Double_t Sqrt(Double_t x)
Returns the square root of x.
Definition TMath.h:673
constexpr Double_t Pi()
Definition TMath.h:40
void Sort(Index n, const Element *a, Index *index, Bool_t down=kTRUE)
Sort the n elements of the array a of generic templated type Element.
Definition TMathBase.h:432
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:124
constexpr Double_t TwoPi()
Definition TMath.h:47
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4
auto * t1
Definition textangle.C:20