TGraphDelaunay.cxx

Go to the documentation of this file.
00001 // @(#)root/hist:$Id: TGraphDelaunay.cxx,v 1.00
00002 // Author: Olivier Couet, Luke Jones (Royal Holloway, University of London)
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include "TMath.h"
00013 #include "TGraph2D.h"
00014 #include "TGraphDelaunay.h"
00015 
00016 ClassImp(TGraphDelaunay)
00017 
00018 
00019 //______________________________________________________________________________
00020 //
00021 // TGraphDelaunay generates a Delaunay triangulation of a TGraph2D. This
00022 // triangulation code derives from an implementation done by Luke Jones
00023 // (Royal Holloway, University of London) in April 2002 in the PAW context.
00024 //
00025 // This software cannot be guaranteed to work under all circumstances. They
00026 // were originally written to work with a few hundred points in an XY space
00027 // with similar X and Y ranges.
00028 //
00029 // Definition of Delaunay triangulation (After B. Delaunay):
00030 // For a set S of points in the Euclidean plane, the unique triangulation DT(S)
00031 // of S such that no point in S is inside the circumcircle of any triangle in
00032 // DT(S). DT(S) is the dual of the Voronoi diagram of S. If n is the number of
00033 // points in S, the Voronoi diagram of S is the partitioning of the plane
00034 // containing S points into n convex polygons such that each polygon contains
00035 // exactly one point and every point in a given polygon is closer to its
00036 // central point than to any other. A Voronoi diagram is sometimes also known
00037 // as a Dirichlet tessellation.
00038 //Begin_Html
00039 /*
00040 <img src="gif/dtvd.gif">
00041 <br>
00042 <a href="http://www.cs.cornell.edu/Info/People/chew/Delaunay.html">This applet</a>
00043 gives a nice practical view of Delaunay triangulation and Voronoi diagram.
00044 */
00045 //End_Html
00046 
00047 
00048 //______________________________________________________________________________
00049 TGraphDelaunay::TGraphDelaunay()
00050             : TNamed("TGraphDelaunay","TGraphDelaunay")
00051 {
00052    // TGraphDelaunay default constructor
00053 
00054    fGraph2D      = 0;
00055    fX            = 0;
00056    fY            = 0;
00057    fZ            = 0;
00058    fNpoints      = 0;
00059    fTriedSize    = 0;
00060    fZout         = 0.;
00061    fNdt          = 0;
00062    fNhull        = 0;
00063    fHullPoints   = 0;
00064    fXN           = 0;
00065    fYN           = 0;
00066    fOrder        = 0;
00067    fDist         = 0;
00068    fPTried       = 0;
00069    fNTried       = 0;
00070    fMTried       = 0;
00071    fInit         = kFALSE;
00072    fXNmin        = 0.;
00073    fXNmax        = 0.;
00074    fYNmin        = 0.;
00075    fYNmax        = 0.;
00076    fXoffset      = 0.;
00077    fYoffset      = 0.;
00078    fXScaleFactor = 0.;
00079    fYScaleFactor = 0.;
00080 
00081    SetMaxIter();
00082 }
00083 
00084 
00085 //______________________________________________________________________________
00086 TGraphDelaunay::TGraphDelaunay(TGraph2D *g)
00087             : TNamed("TGraphDelaunay","TGraphDelaunay")
00088 {
00089    // TGraphDelaunay normal constructor
00090 
00091    fGraph2D      = g;
00092    fX            = fGraph2D->GetX();
00093    fY            = fGraph2D->GetY();
00094    fZ            = fGraph2D->GetZ();
00095    fNpoints      = fGraph2D->GetN();
00096    fTriedSize    = 0;
00097    fZout         = 0.;
00098    fNdt          = 0;
00099    fNhull        = 0;
00100    fHullPoints   = 0;
00101    fXN           = 0;
00102    fYN           = 0;
00103    fOrder        = 0;
00104    fDist         = 0;
00105    fPTried       = 0;
00106    fNTried       = 0;
00107    fMTried       = 0;
00108    fInit         = kFALSE;
00109    fXNmin        = 0.;
00110    fXNmax        = 0.;
00111    fYNmin        = 0.;
00112    fYNmax        = 0.;
00113    fXoffset      = 0.;
00114    fYoffset      = 0.;
00115    fXScaleFactor = 0.;
00116    fYScaleFactor = 0.;
00117 
00118    SetMaxIter();
00119 }
00120 
00121 
00122 //______________________________________________________________________________
00123 TGraphDelaunay::~TGraphDelaunay()
00124 {
00125    // TGraphDelaunay destructor.
00126 
00127    if (fPTried)     delete [] fPTried;
00128    if (fNTried)     delete [] fNTried;
00129    if (fMTried)     delete [] fMTried;
00130    if (fHullPoints) delete [] fHullPoints;
00131    if (fOrder)      delete [] fOrder;
00132    if (fDist)       delete [] fDist;
00133    if (fXN)         delete [] fXN;
00134    if (fYN)         delete [] fYN;
00135 
00136    fPTried     = 0;
00137    fNTried     = 0;
00138    fMTried     = 0;
00139    fHullPoints = 0;
00140    fOrder      = 0;
00141    fDist       = 0;
00142    fXN         = 0;
00143    fYN         = 0;
00144 }
00145 
00146 
00147 //______________________________________________________________________________
00148 Double_t TGraphDelaunay::ComputeZ(Double_t x, Double_t y)
00149 {
00150    // Return the z value corresponding to the (x,y) point in fGraph2D
00151 
00152    // Initialise the Delaunay algorithm if needed.
00153    // CreateTrianglesDataStructure computes fXoffset, fYoffset,
00154    // fXScaleFactor and fYScaleFactor;
00155    // needed in this function.
00156    if (!fInit) {
00157       CreateTrianglesDataStructure();
00158       FindHull();
00159       fInit = kTRUE;
00160    }
00161 
00162    // Find the z value corresponding to the point (x,y).
00163    Double_t xx, yy;
00164    xx = (x+fXoffset)*fXScaleFactor;
00165    yy = (y+fYoffset)*fYScaleFactor;
00166    Double_t zz = Interpolate(xx, yy);
00167 
00168    // Wrong zeros may appear when points sit on a regular grid.
00169    // The following lines try to avoid this problem.
00170    if (zz==0) {
00171       xx += 0.001;
00172       yy += 0.001;
00173       zz = Interpolate(xx, yy);
00174    }
00175    return zz;
00176 }
00177 
00178 
00179 //______________________________________________________________________________
00180 void TGraphDelaunay::CreateTrianglesDataStructure()
00181 {
00182    // Function used internally only. It creates the data structures needed to
00183    // compute the Delaunay triangles.
00184 
00185    // Offset fX and fY so they average zero, and scale so the average
00186    // of the X and Y ranges is one. The normalized version of fX and fY used
00187    // in Interpolate.
00188    Double_t xmax = fGraph2D->GetXmax();
00189    Double_t ymax = fGraph2D->GetYmax();
00190    Double_t xmin = fGraph2D->GetXmin();
00191    Double_t ymin = fGraph2D->GetYmin();
00192    fXoffset      = -(xmax+xmin)/2.;
00193    fYoffset      = -(ymax+ymin)/2.;
00194    fXScaleFactor  = 1./(xmax-xmin);
00195    fYScaleFactor  = 1./(ymax-ymin);
00196    fXNmax        = (xmax+fXoffset)*fXScaleFactor;
00197    fXNmin        = (xmin+fXoffset)*fXScaleFactor;
00198    fYNmax        = (ymax+fYoffset)*fYScaleFactor;
00199    fYNmin        = (ymin+fYoffset)*fYScaleFactor;
00200    fXN           = new Double_t[fNpoints+1];
00201    fYN           = new Double_t[fNpoints+1];
00202    for (Int_t n=0; n<fNpoints; n++) {
00203       fXN[n+1] = (fX[n]+fXoffset)*fXScaleFactor;
00204       fYN[n+1] = (fY[n]+fYoffset)*fYScaleFactor;
00205    }
00206 
00207    // If needed, creates the arrays to hold the Delaunay triangles.
00208    // A maximum number of 2*fNpoints is guessed. If more triangles will be
00209    // find, FillIt will automatically enlarge these arrays.
00210    fTriedSize = 2*fNpoints;
00211    fPTried    = new Int_t[fTriedSize];
00212    fNTried    = new Int_t[fTriedSize];
00213    fMTried    = new Int_t[fTriedSize];
00214 }
00215 
00216 
00217 //______________________________________________________________________________
00218 Bool_t TGraphDelaunay::Enclose(Int_t t1, Int_t t2, Int_t t3, Int_t e) const
00219 {
00220    // Is point e inside the triangle t1-t2-t3 ?
00221 
00222    Double_t x[4],y[4],xp, yp;
00223    x[0] = fXN[t1];
00224    x[1] = fXN[t2];
00225    x[2] = fXN[t3];
00226    x[3] = x[0];
00227    y[0] = fYN[t1];
00228    y[1] = fYN[t2];
00229    y[2] = fYN[t3];
00230    y[3] = y[0];
00231    xp   = fXN[e];
00232    yp   = fYN[e];
00233    return TMath::IsInside(xp, yp, 4, x, y);
00234 }
00235 
00236 
00237 //______________________________________________________________________________
00238 void TGraphDelaunay::FileIt(Int_t p, Int_t n, Int_t m)
00239 {
00240    // Files the triangle defined by the 3 vertices p, n and m into the
00241    // fxTried arrays. If these arrays are to small they are automatically
00242    // expanded.
00243 
00244    Bool_t swap;
00245    Int_t tmp, ps = p, ns = n, ms = m;
00246 
00247    // order the vertices before storing them
00248 L1:
00249    swap = kFALSE;
00250    if (ns > ps) { tmp = ps; ps = ns; ns = tmp; swap = kTRUE;}
00251    if (ms > ns) { tmp = ns; ns = ms; ms = tmp; swap = kTRUE;}
00252    if (swap) goto L1;
00253 
00254    // expand the triangles storage if needed
00255    if (fNdt> fTriedSize) {
00256       Int_t newN   = 2*fTriedSize;
00257       Int_t *savep = new Int_t [newN];
00258       Int_t *saven = new Int_t [newN];
00259       Int_t *savem = new Int_t [newN];
00260       memcpy(savep,fPTried,fTriedSize*sizeof(Int_t));
00261       memset(&savep[fTriedSize],0,(newN-fTriedSize)*sizeof(Int_t));
00262       delete [] fPTried;
00263       memcpy(saven,fNTried,fTriedSize*sizeof(Int_t));
00264       memset(&saven[fTriedSize],0,(newN-fTriedSize)*sizeof(Int_t));
00265       delete [] fNTried;
00266       memcpy(savem,fMTried,fTriedSize*sizeof(Int_t));
00267       memset(&savem[fTriedSize],0,(newN-fTriedSize)*sizeof(Int_t));
00268       delete [] fMTried;
00269       fPTried    = savep;
00270       fNTried    = saven;
00271       fMTried    = savem;
00272       fTriedSize = newN;
00273    }
00274 
00275    // store a new Delaunay triangle
00276    fNdt++;
00277    fPTried[fNdt-1] = ps;
00278    fNTried[fNdt-1] = ns;
00279    fMTried[fNdt-1] = ms;
00280 }
00281 
00282 
00283 //______________________________________________________________________________
00284 void TGraphDelaunay::FindAllTriangles()
00285 {
00286    // Attempt to find all the Delaunay triangles of the point set. It is not
00287    // guaranteed that it will fully succeed, and no check is made that it has
00288    // fully succeeded (such a check would be possible by referencing the points
00289    // that make up the convex hull). The method is to check if each triangle
00290    // shares all three of its sides with other triangles. If not, a point is
00291    // generated just outside the triangle on the side(s) not shared, and a new
00292    // triangle is found for that point. If this method is not working properly
00293    // (many triangles are not being found) it's probably because the new points
00294    // are too far beyond or too close to the non-shared sides. Fiddling with
00295    // the size of the `alittlebit' parameter may help.
00296 
00297    if (fAllTri) return; else fAllTri = kTRUE;
00298 
00299    Double_t xcntr,ycntr,xm,ym,xx,yy;
00300    Double_t sx,sy,nx,ny,mx,my,mdotn,nn,a;
00301    Int_t t1,t2,pa,na,ma,pb,nb,mb,p1=0,p2=0,m,n,p3=0;
00302    Bool_t s[3];
00303    Double_t alittlebit = 0.0001;
00304 
00305    // start with a point that is guaranteed to be inside the hull (the
00306    // centre of the hull). The starting point is shifted "a little bit"
00307    // otherwise, in case of triangles aligned on a regular grid, we may
00308    // found none of them.
00309    xcntr = 0;
00310    ycntr = 0;
00311    for (n=1; n<=fNhull; n++) {
00312       xcntr = xcntr+fXN[fHullPoints[n-1]];
00313       ycntr = ycntr+fYN[fHullPoints[n-1]];
00314    }
00315    xcntr = xcntr/fNhull+alittlebit;
00316    ycntr = ycntr/fNhull+alittlebit;
00317    // and calculate it's triangle
00318    Interpolate(xcntr,ycntr);
00319 
00320    // loop over all Delaunay triangles (including those constantly being
00321    // produced within the loop) and check to see if their 3 sides also
00322    // correspond to the sides of other Delaunay triangles, i.e. that they
00323    // have all their neighbours.
00324    t1 = 1;
00325    while (t1 <= fNdt) {
00326       // get the three points that make up this triangle
00327       pa = fPTried[t1-1];
00328       na = fNTried[t1-1];
00329       ma = fMTried[t1-1];
00330 
00331       // produce three integers which will represent the three sides
00332       s[0]  = kFALSE;
00333       s[1]  = kFALSE;
00334       s[2]  = kFALSE;
00335       // loop over all other Delaunay triangles
00336       for (t2=1; t2<=fNdt; t2++) {
00337          if (t2 != t1) {
00338             // get the points that make up this triangle
00339             pb = fPTried[t2-1];
00340             nb = fNTried[t2-1];
00341             mb = fMTried[t2-1];
00342             // do triangles t1 and t2 share a side?
00343             if ((pa==pb && na==nb) || (pa==pb && na==mb) || (pa==nb && na==mb)) {
00344                // they share side 1
00345                s[0] = kTRUE;
00346             } else if ((pa==pb && ma==nb) || (pa==pb && ma==mb) || (pa==nb && ma==mb)) {
00347                // they share side 2
00348                s[1] = kTRUE;
00349             } else if ((na==pb && ma==nb) || (na==pb && ma==mb) || (na==nb && ma==mb)) {
00350                // they share side 3
00351                s[2] = kTRUE;
00352             }
00353          }
00354          // if t1 shares all its sides with other Delaunay triangles then
00355          // forget about it
00356          if (s[0] && s[1] && s[2]) continue;
00357       }
00358       // Looks like t1 is missing a neighbour on at least one side.
00359       // For each side, take a point a little bit beyond it and calculate
00360       // the Delaunay triangle for that point, this should be the triangle
00361       // which shares the side.
00362       for (m=1; m<=3; m++) {
00363          if (!s[m-1]) {
00364             // get the two points that make up this side
00365             if (m == 1) {
00366                p1 = pa;
00367                p2 = na;
00368                p3 = ma;
00369             } else if (m == 2) {
00370                p1 = pa;
00371                p2 = ma;
00372                p3 = na;
00373             } else if (m == 3) {
00374                p1 = na;
00375                p2 = ma;
00376                p3 = pa;
00377             }
00378             // get the coordinates of the centre of this side
00379             xm = (fXN[p1]+fXN[p2])/2.;
00380             ym = (fYN[p1]+fYN[p2])/2.;
00381             // we want to add a little to these coordinates to get a point just
00382             // outside the triangle; (sx,sy) will be the vector that represents
00383             // the side
00384             sx = fXN[p1]-fXN[p2];
00385             sy = fYN[p1]-fYN[p2];
00386             // (nx,ny) will be the normal to the side, but don't know if it's
00387             // pointing in or out yet
00388             nx    = sy;
00389             ny    = -sx;
00390             nn    = TMath::Sqrt(nx*nx+ny*ny);
00391             nx    = nx/nn;
00392             ny    = ny/nn;
00393             mx    = fXN[p3]-xm;
00394             my    = fYN[p3]-ym;
00395             mdotn = mx*nx+my*ny;
00396             if (mdotn > 0) {
00397                // (nx,ny) is pointing in, we want it pointing out
00398                nx = -nx;
00399                ny = -ny;
00400             }
00401             // increase/decrease xm and ym a little to produce a point
00402             // just outside the triangle (ensuring that the amount added will
00403             // be large enough such that it won't be lost in rounding errors)
00404             a  = TMath::Abs(TMath::Max(alittlebit*xm,alittlebit*ym));
00405             xx = xm+nx*a;
00406             yy = ym+ny*a;
00407             // try and find a new Delaunay triangle for this point
00408             Interpolate(xx,yy);
00409 
00410             // this side of t1 should now, hopefully, if it's not part of the
00411             // hull, be shared with a new Delaunay triangle just calculated by Interpolate
00412          }
00413       }
00414       t1++;
00415    }
00416 }
00417 
00418 
00419 //______________________________________________________________________________
00420 void TGraphDelaunay::FindHull()
00421 {
00422    // Finds those points which make up the convex hull of the set. If the xy
00423    // plane were a sheet of wood, and the points were nails hammered into it
00424    // at the respective coordinates, then if an elastic band were stretched
00425    // over all the nails it would form the shape of the convex hull. Those
00426    // nails in contact with it are the points that make up the hull.
00427 
00428    Int_t n,nhull_tmp;
00429    Bool_t in;
00430 
00431    if (!fHullPoints) fHullPoints = new Int_t[fNpoints];
00432 
00433    nhull_tmp = 0;
00434    for(n=1; n<=fNpoints; n++) {
00435       // if the point is not inside the hull of the set of all points
00436       // bar it, then it is part of the hull of the set of all points
00437       // including it
00438       in = InHull(n,n);
00439       if (!in) {
00440          // cannot increment fNhull directly - InHull needs to know that
00441          // the hull has not yet been completely found
00442          nhull_tmp++;
00443          fHullPoints[nhull_tmp-1] = n;
00444       }
00445    }
00446    fNhull = nhull_tmp;
00447 }
00448 
00449 
00450 //______________________________________________________________________________
00451 Bool_t TGraphDelaunay::InHull(Int_t e, Int_t x) const
00452 {
00453    // Is point e inside the hull defined by all points apart from x ?
00454 
00455    Int_t n1,n2,n,m,ntry;
00456    Double_t lastdphi,dd1,dd2,dx1,dx2,dx3,dy1,dy2,dy3;
00457    Double_t u,v,vNv1,vNv2,phi1,phi2,dphi,xx,yy;
00458 
00459    Bool_t deTinhull = kFALSE;
00460 
00461    xx = fXN[e];
00462    yy = fYN[e];
00463 
00464    if (fNhull > 0) {
00465       //  The hull has been found - no need to use any points other than
00466       //  those that make up the hull
00467       ntry = fNhull;
00468    } else {
00469       //  The hull has not yet been found, will have to try every point
00470       ntry = fNpoints;
00471    }
00472 
00473    //  n1 and n2 will represent the two points most separated by angle
00474    //  from point e. Initially the angle between them will be <180 degs.
00475    //  But subsequent points will increase the n1-e-n2 angle. If it
00476    //  increases above 180 degrees then point e must be surrounded by
00477    //  points - it is not part of the hull.
00478    n1 = 1;
00479    n2 = 2;
00480    if (n1 == x) {
00481       n1 = n2;
00482       n2++;
00483    } else if (n2 == x) {
00484       n2++;
00485    }
00486 
00487    //  Get the angle n1-e-n2 and set it to lastdphi
00488    dx1  = xx-fXN[n1];
00489    dy1  = yy-fYN[n1];
00490    dx2  = xx-fXN[n2];
00491    dy2  = yy-fYN[n2];
00492    phi1 = TMath::ATan2(dy1,dx1);
00493    phi2 = TMath::ATan2(dy2,dx2);
00494    dphi = (phi1-phi2)-((Int_t)((phi1-phi2)/TMath::TwoPi())*TMath::TwoPi());
00495    if (dphi < 0) dphi = dphi+TMath::TwoPi();
00496    lastdphi = dphi;
00497    for (n=1; n<=ntry; n++) {
00498       if (fNhull > 0) {
00499          // Try hull point n
00500          m = fHullPoints[n-1];
00501       } else {
00502          m = n;
00503       }
00504       if ((m!=n1) && (m!=n2) && (m!=x)) {
00505          // Can the vector e->m be represented as a sum with positive
00506          // coefficients of vectors e->n1 and e->n2?
00507          dx1 = xx-fXN[n1];
00508          dy1 = yy-fYN[n1];
00509          dx2 = xx-fXN[n2];
00510          dy2 = yy-fYN[n2];
00511          dx3 = xx-fXN[m];
00512          dy3 = yy-fYN[m];
00513 
00514          dd1 = (dx2*dy1-dx1*dy2);
00515          dd2 = (dx1*dy2-dx2*dy1);
00516 
00517          if (dd1*dd2!=0) {
00518             u = (dx2*dy3-dx3*dy2)/dd1;
00519             v = (dx1*dy3-dx3*dy1)/dd2;
00520             if ((u<0) || (v<0)) {
00521                // No, it cannot - point m does not lie inbetween n1 and n2 as
00522                // viewed from e. Replace either n1 or n2 to increase the
00523                // n1-e-n2 angle. The one to replace is the one which makes the
00524                // smallest angle with e->m
00525                vNv1 = (dx1*dx3+dy1*dy3)/TMath::Sqrt(dx1*dx1+dy1*dy1);
00526                vNv2 = (dx2*dx3+dy2*dy3)/TMath::Sqrt(dx2*dx2+dy2*dy2);
00527                if (vNv1 > vNv2) {
00528                   n1   = m;
00529                   phi1 = TMath::ATan2(dy3,dx3);
00530                   phi2 = TMath::ATan2(dy2,dx2);
00531                } else {
00532                   n2   = m;
00533                   phi1 = TMath::ATan2(dy1,dx1);
00534                   phi2 = TMath::ATan2(dy3,dx3);
00535                }
00536                dphi = (phi1-phi2)-((Int_t)((phi1-phi2)/TMath::TwoPi())*TMath::TwoPi());
00537                if (dphi < 0) dphi = dphi+TMath::TwoPi();
00538                if (((dphi-TMath::Pi())*(lastdphi-TMath::Pi())) < 0) {
00539                   // The addition of point m means the angle n1-e-n2 has risen
00540                   // above 180 degs, the point is in the hull.
00541                   goto L10;
00542                }
00543                lastdphi = dphi;
00544             }
00545          }
00546       }
00547    }
00548    // Point e is not surrounded by points - it is not in the hull.
00549    goto L999;
00550 L10:
00551    deTinhull = kTRUE;
00552 L999:
00553    return deTinhull;
00554 }
00555 
00556 
00557 //______________________________________________________________________________
00558 Double_t TGraphDelaunay::InterpolateOnPlane(Int_t TI1, Int_t TI2, Int_t TI3, Int_t e) const
00559 {
00560    // Finds the z-value at point e given that it lies
00561    // on the plane defined by t1,t2,t3
00562 
00563    Int_t tmp;
00564    Bool_t swap;
00565    Double_t x1,x2,x3,y1,y2,y3,f1,f2,f3,u,v,w;
00566 
00567    Int_t t1 = TI1;
00568    Int_t t2 = TI2;
00569    Int_t t3 = TI3;
00570 
00571    // order the vertices
00572 L1:
00573    swap = kFALSE;
00574    if (t2 > t1) { tmp = t1; t1 = t2; t2 = tmp; swap = kTRUE;}
00575    if (t3 > t2) { tmp = t2; t2 = t3; t3 = tmp; swap = kTRUE;}
00576    if (swap) goto L1;
00577 
00578    x1 = fXN[t1];
00579    x2 = fXN[t2];
00580    x3 = fXN[t3];
00581    y1 = fYN[t1];
00582    y2 = fYN[t2];
00583    y3 = fYN[t3];
00584    f1 = fZ[t1-1];
00585    f2 = fZ[t2-1];
00586    f3 = fZ[t3-1];
00587    u  = (f1*(y2-y3)+f2*(y3-y1)+f3*(y1-y2))/(x1*(y2-y3)+x2*(y3-y1)+x3*(y1-y2));
00588    v  = (f1*(x2-x3)+f2*(x3-x1)+f3*(x1-x2))/(y1*(x2-x3)+y2*(x3-x1)+y3*(x1-x2));
00589    w  = f1-u*x1-v*y1;
00590 
00591    return u*fXN[e]+v*fYN[e]+w;
00592 }
00593 
00594 
00595 //______________________________________________________________________________
00596 Double_t TGraphDelaunay::Interpolate(Double_t xx, Double_t yy)
00597 {
00598    // Finds the Delaunay triangle that the point (xi,yi) sits in (if any) and
00599    // calculate a z-value for it by linearly interpolating the z-values that
00600    // make up that triangle.
00601 
00602    Double_t thevalue;
00603 
00604    Int_t it, ntris_tried, p, n, m;
00605    Int_t i,j,k,l,z,f,d,o1,o2,a,b,t1,t2,t3;
00606    Int_t ndegen=0,degen=0,fdegen=0,o1degen=0,o2degen=0;
00607    Double_t vxN,vyN;
00608    Double_t d1,d2,d3,c1,c2,dko1,dko2,dfo1;
00609    Double_t dfo2,sin_sum,cfo1k,co2o1k,co2o1f;
00610 
00611    Bool_t shouldbein;
00612    Double_t dx1,dx2,dx3,dy1,dy2,dy3,u,v,dxz[3],dyz[3];
00613 
00614    // initialise the Delaunay algorithm if needed
00615    if (!fInit) {
00616       CreateTrianglesDataStructure();
00617       FindHull();
00618       fInit = kTRUE;
00619    }
00620 
00621    // create vectors needed for sorting
00622    if (!fOrder) {
00623       fOrder = new Int_t[fNpoints];
00624       fDist  = new Double_t[fNpoints];
00625    }
00626 
00627    // the input point will be point zero.
00628    fXN[0] = xx;
00629    fYN[0] = yy;
00630 
00631    // set the output value to the default value for now
00632    thevalue = fZout;
00633 
00634    // some counting
00635    ntris_tried = 0;
00636 
00637    // no point in proceeding if xx or yy are silly
00638    if ((xx>fXNmax) || (xx<fXNmin) || (yy>fYNmax) || (yy<fYNmin)) return thevalue;
00639 
00640    // check existing Delaunay triangles for a good one
00641    for (it=1; it<=fNdt; it++) {
00642       p = fPTried[it-1];
00643       n = fNTried[it-1];
00644       m = fMTried[it-1];
00645       // p, n and m form a previously found Delaunay triangle, does it
00646       // enclose the point?
00647       if (Enclose(p,n,m,0)) {
00648          // yes, we have the triangle
00649          thevalue = InterpolateOnPlane(p,n,m,0);
00650          return thevalue;
00651       }
00652    }
00653 
00654    // is this point inside the convex hull?
00655    shouldbein = InHull(0,-1);
00656    if (!shouldbein) return thevalue;
00657 
00658    // it must be in a Delaunay triangle - find it...
00659 
00660    // order mass points by distance in mass plane from desired point
00661    for (it=1; it<=fNpoints; it++) {
00662       vxN = fXN[it];
00663       vyN = fYN[it];
00664       fDist[it-1] = TMath::Sqrt((xx-vxN)*(xx-vxN)+(yy-vyN)*(yy-vyN));
00665    }
00666 
00667    // sort array 'fDist' to find closest points
00668    TMath::Sort(fNpoints, fDist, fOrder, kFALSE);
00669    for (it=0; it<fNpoints; it++) fOrder[it]++;
00670 
00671    // loop over triplets of close points to try to find a triangle that
00672    // encloses the point.
00673    for (k=3; k<=fNpoints; k++) {
00674       m = fOrder[k-1];
00675       for (j=2; j<=k-1; j++) {
00676          n = fOrder[j-1];
00677          for (i=1; i<=j-1; i++) {
00678             p = fOrder[i-1];
00679             if (ntris_tried > fMaxIter) {
00680                // perhaps this point isn't in the hull after all
00681 ///            Warning("Interpolate",
00682 ///                    "Abandoning the effort to find a Delaunay triangle (and thus interpolated z-value) for point %g %g"
00683 ///                    ,xx,yy);
00684                return thevalue;
00685             }
00686             ntris_tried++;
00687             // check the points aren't colinear
00688             d1 = TMath::Sqrt((fXN[p]-fXN[n])*(fXN[p]-fXN[n])+(fYN[p]-fYN[n])*(fYN[p]-fYN[n]));
00689             d2 = TMath::Sqrt((fXN[p]-fXN[m])*(fXN[p]-fXN[m])+(fYN[p]-fYN[m])*(fYN[p]-fYN[m]));
00690             d3 = TMath::Sqrt((fXN[n]-fXN[m])*(fXN[n]-fXN[m])+(fYN[n]-fYN[m])*(fYN[n]-fYN[m]));
00691             if ((d1+d2<=d3) || (d1+d3<=d2) || (d2+d3<=d1)) goto L90;
00692 
00693             // does the triangle enclose the point?
00694             if (!Enclose(p,n,m,0)) goto L90;
00695 
00696             // is it a Delaunay triangle? (ie. are there any other points
00697             // inside the circle that is defined by its vertices?)
00698 
00699             // test the triangle for Delaunay'ness
00700 
00701             // loop over all other points testing each to see if it's
00702             // inside the triangle's circle
00703             ndegen = 0;
00704             for ( z=1; z<=fNpoints; z++) {
00705                if ((z==p) || (z==n) || (z==m)) goto L50;
00706                // An easy first check is to see if point z is inside the triangle
00707                // (if it's in the triangle it's also in the circle)
00708 
00709                // point z cannot be inside the triangle if it's further from (xx,yy)
00710                // than the furthest pointing making up the triangle - test this
00711                for (l=1; l<=fNpoints; l++) {
00712                   if (fOrder[l-1] == z) {
00713                      if ((l<i) || (l<j) || (l<k)) {
00714                         // point z is nearer to (xx,yy) than m, n or p - it could be in the
00715                         // triangle so call enclose to find out
00716 
00717                         // if it is inside the triangle this can't be a Delaunay triangle
00718                         if (Enclose(p,n,m,z)) goto L90;
00719                      } else {
00720                         // there's no way it could be in the triangle so there's no point
00721                         // calling enclose
00722                         goto L1;
00723                      }
00724                   }
00725                }
00726                // is point z colinear with any pair of the triangle points?
00727 L1:
00728                if (((fXN[p]-fXN[z])*(fYN[p]-fYN[n])) == ((fYN[p]-fYN[z])*(fXN[p]-fXN[n]))) {
00729                   // z is colinear with p and n
00730                   a = p;
00731                   b = n;
00732                } else if (((fXN[p]-fXN[z])*(fYN[p]-fYN[m])) == ((fYN[p]-fYN[z])*(fXN[p]-fXN[m]))) {
00733                   // z is colinear with p and m
00734                   a = p;
00735                   b = m;
00736                } else if (((fXN[n]-fXN[z])*(fYN[n]-fYN[m])) == ((fYN[n]-fYN[z])*(fXN[n]-fXN[m]))) {
00737                   // z is colinear with n and m
00738                   a = n;
00739                   b = m;
00740                } else {
00741                   a = 0;
00742                   b = 0;
00743                }
00744                if (a != 0) {
00745                   // point z is colinear with 2 of the triangle points, if it lies
00746                   // between them it's in the circle otherwise it's outside
00747                   if (fXN[a] != fXN[b]) {
00748                      if (((fXN[z]-fXN[a])*(fXN[z]-fXN[b])) < 0) {
00749                         goto L90;
00750                      } else if (((fXN[z]-fXN[a])*(fXN[z]-fXN[b])) == 0) {
00751                         // At least two points are sitting on top of each other, we will
00752                         // treat these as one and not consider this a 'multiple points lying
00753                         // on a common circle' situation. It is a sign something could be
00754                         // wrong though, especially if the two coincident points have
00755                         // different fZ's. If they don't then this is harmless.
00756                         Warning("Interpolate", "Two of these three points are coincident %d %d %d",a,b,z);
00757                      }
00758                   } else {
00759                      if (((fYN[z]-fYN[a])*(fYN[z]-fYN[b])) < 0) {
00760                         goto L90;
00761                      } else if (((fYN[z]-fYN[a])*(fYN[z]-fYN[b])) == 0) {
00762                         // At least two points are sitting on top of each other - see above.
00763                         Warning("Interpolate", "Two of these three points are coincident %d %d %d",a,b,z);
00764                      }
00765                   }
00766                   // point is outside the circle, move to next point
00767                   goto L50;
00768                }
00769 
00770                // if point z were to look at the triangle, which point would it see
00771                // lying between the other two? (we're going to form a quadrilateral
00772                // from the points, and then demand certain properties of that
00773                // quadrilateral)
00774                dxz[0] = fXN[p]-fXN[z];
00775                dyz[0] = fYN[p]-fYN[z];
00776                dxz[1] = fXN[n]-fXN[z];
00777                dyz[1] = fYN[n]-fYN[z];
00778                dxz[2] = fXN[m]-fXN[z];
00779                dyz[2] = fYN[m]-fYN[z];
00780                for(l=1; l<=3; l++) {
00781                   dx1 = dxz[l-1];
00782                   dx2 = dxz[l%3];
00783                   dx3 = dxz[(l+1)%3];
00784                   dy1 = dyz[l-1];
00785                   dy2 = dyz[l%3];
00786                   dy3 = dyz[(l+1)%3];
00787 
00788                   u = (dy3*dx2-dx3*dy2)/(dy1*dx2-dx1*dy2);
00789                   v = (dy3*dx1-dx3*dy1)/(dy2*dx1-dx2*dy1);
00790 
00791                   if ((u>=0) && (v>=0)) {
00792                      // vector (dx3,dy3) is expressible as a sum of the other two vectors
00793                      // with positive coefficents -> i.e. it lies between the other two vectors
00794                      if (l == 1) {
00795                         f  = m;
00796                         o1 = p;
00797                         o2 = n;
00798                      } else if (l == 2) {
00799                         f  = p;
00800                         o1 = n;
00801                         o2 = m;
00802                      } else {
00803                         f  = n;
00804                         o1 = m;
00805                         o2 = p;
00806                      }
00807                      goto L2;
00808                   }
00809                }
00810 ///            Error("Interpolate", "Should not get to here");
00811                // may as well soldier on
00812                f  = m;
00813                o1 = p;
00814                o2 = n;
00815 L2:
00816                // this is not a valid quadrilateral if the diagonals don't cross,
00817                // check that points f and z lie on opposite side of the line o1-o2,
00818                // this is true if the angle f-o1-z is greater than o2-o1-z and o2-o1-f
00819                cfo1k  = ((fXN[f]-fXN[o1])*(fXN[z]-fXN[o1])+(fYN[f]-fYN[o1])*(fYN[z]-fYN[o1]))/
00820                         TMath::Sqrt(((fXN[f]-fXN[o1])*(fXN[f]-fXN[o1])+(fYN[f]-fYN[o1])*(fYN[f]-fYN[o1]))*
00821                         ((fXN[z]-fXN[o1])*(fXN[z]-fXN[o1])+(fYN[z]-fYN[o1])*(fYN[z]-fYN[o1])));
00822                co2o1k = ((fXN[o2]-fXN[o1])*(fXN[z]-fXN[o1])+(fYN[o2]-fYN[o1])*(fYN[z]-fYN[o1]))/
00823                         TMath::Sqrt(((fXN[o2]-fXN[o1])*(fXN[o2]-fXN[o1])+(fYN[o2]-fYN[o1])*(fYN[o2]-fYN[o1]))*
00824                         ((fXN[z]-fXN[o1])*(fXN[z]-fXN[o1])  + (fYN[z]-fYN[o1])*(fYN[z]-fYN[o1])));
00825                co2o1f = ((fXN[o2]-fXN[o1])*(fXN[f]-fXN[o1])+(fYN[o2]-fYN[o1])*(fYN[f]-fYN[o1]))/
00826                         TMath::Sqrt(((fXN[o2]-fXN[o1])*(fXN[o2]-fXN[o1])+(fYN[o2]-fYN[o1])*(fYN[o2]-fYN[o1]))*
00827                         ((fXN[f]-fXN[o1])*(fXN[f]-fXN[o1]) + (fYN[f]-fYN[o1])*(fYN[f]-fYN[o1]) ));
00828                if ((cfo1k>co2o1k) || (cfo1k>co2o1f)) {
00829                   // not a valid quadrilateral - point z is definitely outside the circle
00830                   goto L50;
00831                }
00832                // calculate the 2 internal angles of the quadrangle formed by joining
00833                // points z and f to points o1 and o2, at z and f. If they sum to less
00834                // than 180 degrees then z lies outside the circle
00835                dko1    = TMath::Sqrt((fXN[z]-fXN[o1])*(fXN[z]-fXN[o1])+(fYN[z]-fYN[o1])*(fYN[z]-fYN[o1]));
00836                dko2    = TMath::Sqrt((fXN[z]-fXN[o2])*(fXN[z]-fXN[o2])+(fYN[z]-fYN[o2])*(fYN[z]-fYN[o2]));
00837                dfo1    = TMath::Sqrt((fXN[f]-fXN[o1])*(fXN[f]-fXN[o1])+(fYN[f]-fYN[o1])*(fYN[f]-fYN[o1]));
00838                dfo2    = TMath::Sqrt((fXN[f]-fXN[o2])*(fXN[f]-fXN[o2])+(fYN[f]-fYN[o2])*(fYN[f]-fYN[o2]));
00839                c1      = ((fXN[z]-fXN[o1])*(fXN[z]-fXN[o2])+(fYN[z]-fYN[o1])*(fYN[z]-fYN[o2]))/dko1/dko2;
00840                c2      = ((fXN[f]-fXN[o1])*(fXN[f]-fXN[o2])+(fYN[f]-fYN[o1])*(fYN[f]-fYN[o2]))/dfo1/dfo2;
00841                sin_sum = c1*TMath::Sqrt(1-c2*c2)+c2*TMath::Sqrt(1-c1*c1);
00842 
00843                // sin_sum doesn't always come out as zero when it should do.
00844                if (sin_sum < -1.E-6) {
00845                   // z is inside the circle, this is not a Delaunay triangle
00846                   goto L90;
00847                } else if (TMath::Abs(sin_sum) <= 1.E-6) {
00848                   // point z lies on the circumference of the circle (within rounding errors)
00849                   // defined by the triangle, so there is potential for degeneracy in the
00850                   // triangle set (Delaunay triangulation does not give a unique way to split
00851                   // a polygon whose points lie on a circle into constituent triangles). Make
00852                   // a note of the additional point number.
00853                   ndegen++;
00854                   degen   = z;
00855                   fdegen  = f;
00856                   o1degen = o1;
00857                   o2degen = o2;
00858                }
00859 L50:
00860             continue;
00861             }
00862             // This is a good triangle
00863             if (ndegen > 0) {
00864                // but is degenerate with at least one other,
00865                // haven't figured out what to do if more than 4 points are involved
00866 ///            if (ndegen > 1) {
00867 ///               Error("Interpolate",
00868 ///                     "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",
00869 ///                     p,n,m,degen);
00870 ///               return thevalue;
00871 ///            }
00872 
00873                // we have a quadrilateral which can be split down either diagonal
00874                // (d<->f or o1<->o2) to form valid Delaunay triangles. Choose diagonal
00875                // with highest average z-value. Whichever we choose we will have
00876                // verified two triangles as good and two as bad, only note the good ones
00877                d  = degen;
00878                f  = fdegen;
00879                o1 = o1degen;
00880                o2 = o2degen;
00881                if ((fZ[o1-1]+fZ[o2-1]) > (fZ[d-1]+fZ[f-1])) {
00882                   // best diagonalisation of quadrilateral is current one, we have
00883                   // the triangle
00884                   t1 = p;
00885                   t2 = n;
00886                   t3 = m;
00887                   // file the good triangles
00888                   FileIt(p, n, m);
00889                   FileIt(d, o1, o2);
00890                } else {
00891                   // use other diagonal to split quadrilateral, use triangle formed by
00892                   // point f, the degnerate point d and whichever of o1 and o2 create
00893                   // an enclosing triangle
00894                   t1 = f;
00895                   t2 = d;
00896                   if (Enclose(f,d,o1,0)) {
00897                      t3 = o1;
00898                   } else {
00899                      t3 = o2;
00900                   }
00901                   // file the good triangles
00902                   FileIt(f, d, o1);
00903                   FileIt(f, d, o2);
00904                }
00905             } else {
00906                // this is a Delaunay triangle, file it
00907                FileIt(p, n, m);
00908                t1 = p;
00909                t2 = n;
00910                t3 = m;
00911             }
00912             // do the interpolation
00913             thevalue = InterpolateOnPlane(t1,t2,t3,0);
00914             return thevalue;
00915 L90:
00916             continue;
00917          }
00918       }
00919    }
00920    if (shouldbein) {
00921       Error("Interpolate",
00922             "Point outside hull when expected inside: this point could be dodgy %g %g %d",
00923              xx, yy, ntris_tried);
00924    }
00925    return thevalue;
00926 }
00927 
00928 
00929 //______________________________________________________________________________
00930 void TGraphDelaunay::SetMaxIter(Int_t n)
00931 {
00932    // Defines the number of triangles tested for a Delaunay triangle
00933    // (number of iterations) before abandoning the search
00934 
00935    fAllTri  = kFALSE;
00936    fMaxIter = n;
00937 }
00938 
00939 
00940 //______________________________________________________________________________
00941 void TGraphDelaunay::SetMarginBinsContent(Double_t z)
00942 {
00943    // Sets the histogram bin height for points lying outside the convex hull ie:
00944    // the bins in the margin.
00945 
00946    fZout = z;
00947 }

Generated on Tue Jul 5 14:24:18 2011 for ROOT_528-00b_version by  doxygen 1.5.1