struct Triel { Point<2> *pts; Int p[3]; Int d[3]; Int stat; void setme(Int a, Int b, Int c, Point<2> *ptss) { pts = ptss; p[0] = a; p[1] = b; p[2] = c; d[0] = d[1] = d[2] = -1; stat = 1; } Int contains(Point<2> point) { Doub d; Int i,j,ztest = 0; for (i=0; i<3; i++) { j = (i+1) %3; d = (pts[p[j]].x[0]-pts[p[i]].x[0])*(point.x[1]-pts[p[i]].x[1]) - (pts[p[j]].x[1]-pts[p[i]].x[1])*(point.x[0]-pts[p[i]].x[0]); if (d < 0.0) return -1; if (d == 0.0) ztest = 1; } return (ztest? 0 : 1); } }; Doub incircle(Point<2> d, Point<2> a, Point<2> b, Point<2> c) { Circle cc = circumcircle(a,b,c); Doub radd = SQR(d.x[0]-cc.center.x[0]) + SQR(d.x[1]-cc.center.x[1]); return (SQR(cc.radius) - radd); } struct Nullhash { Nullhash(Int nn) {} inline Ullong fn(const void *key) const { return *((Ullong *)key); } }; struct Delaunay { Int npts,ntri,ntree,ntreemax,opt; Doub delx,dely; vector< Point<2> > pts; vector thelist; Hash *linehash; Hash *trihash; Int *perm; Delaunay(vector > &pvec, Int options = 0); Ranhash hashfn; Doub interpolate(const Point<2> &p, const vector &fnvals, Doub defaultval=0.0); void insertapoint(Int r); Int whichcontainspt(const Point<2> &p, Int strict = 0); Int storetriangle(Int a, Int b, Int c); void erasetriangle(Int a, Int b, Int c, Int d0, Int d1, Int d2); static Uint jran; static const Doub fuzz, bigscale; }; const Doub Delaunay::fuzz = 1.0e-6; const Doub Delaunay::bigscale = 1000.0; Uint Delaunay::jran = 14921620; Delaunay::Delaunay(vector< Point<2> > &pvec, Int options) : npts(pvec.size()), ntri(0), ntree(0), ntreemax(10*npts+1000), opt(options), pts(npts+3), thelist(ntreemax) { Int j; Doub xl,xh,yl,yh; linehash = new Hash(6*npts+12,6*npts+12); trihash = new Hash(2*npts+6,2*npts+6); perm = new Int[npts]; xl = xh = pvec[0].x[0]; yl = yh = pvec[0].x[1]; for (j=0; j xh) xh = pvec[j].x[0]; if (pvec[j].x[1] < yl) yl = pvec[j].x[1]; if (pvec[j].x[1] > yh) yh = pvec[j].x[1]; } delx = xh - xl; dely = yh - yl; pts[npts] = Point<2>(0.5*(xl + xh), yh + bigscale*dely); pts[npts+1] = Point<2>(xl - 0.5*bigscale*delx,yl - 0.5*bigscale*dely); pts[npts+2] = Point<2>(xh + 0.5*bigscale*delx,yl - 0.5*bigscale*dely); storetriangle(npts,npts+1,npts+2); for (j=npts; j>0; j--) SWAP(perm[j-1],perm[hashfn.int64(jran++) % j]); for (j=0; j 0) { if (thelist[j].p[0] >= npts || thelist[j].p[1] >= npts || thelist[j].p[2] >= npts) { thelist[j].stat = -1; ntri--; } } } if (!(opt & 1)) { delete [] perm; delete trihash; delete linehash; } } void Delaunay::insertapoint(Int r) { Int i,j,k,l,s,tno,ntask,d0,d1,d2; Ullong key; Int tasks[50], taski[50], taskj[50]; for (j=0; j<3; j++) { tno = whichcontainspt(pts[r],1); if (tno >= 0) break; pts[r].x[0] += fuzz * delx * (hashfn.doub(jran++)-0.5); pts[r].x[1] += fuzz * dely * (hashfn.doub(jran++)-0.5); } if (j == 3) throw("points degenerate even after fuzzing"); ntask = 0; i = thelist[tno].p[0]; j = thelist[tno].p[1]; k = thelist[tno].p[2]; if (opt & 2 && i < npts && j < npts && k < npts) return; d0 =storetriangle(r,i,j); tasks[++ntask] = r; taski[ntask] = i; taskj[ntask] = j; d1 = storetriangle(r,j,k); tasks[++ntask] = r; taski[ntask] = j; taskj[ntask] = k; d2 = storetriangle(r,k,i); tasks[++ntask] = r; taski[ntask] = k; taskj[ntask] = i; erasetriangle(i,j,k,d0,d1,d2); while (ntask) { s=tasks[ntask]; i=taski[ntask]; j=taskj[ntask--]; key = hashfn.int64(j) - hashfn.int64(i); if ( ! linehash->get(key,l) ) continue; if (incircle(pts[l],pts[j],pts[s],pts[i]) > 0.0){ d0 = storetriangle(s,l,j); d1 = storetriangle(s,i,l); erasetriangle(s,i,j,d0,d1,-1); erasetriangle(l,j,i,d0,d1,-1); key = hashfn.int64(i)-hashfn.int64(j); linehash->erase(key); key = 0 - key; linehash->erase(key); tasks[++ntask] = s; taski[ntask] = l; taskj[ntask] = j; tasks[++ntask] = s; taski[ntask] = i; taskj[ntask] = l; } } } Int Delaunay::whichcontainspt(const Point<2> &p, Int strict) { Int i,j,k=0; while (thelist[k].stat <= 0) { for (i=0; i<3; i++) { if ((j = thelist[k].d[i]) < 0) continue; if (strict) { if (thelist[j].contains(p) > 0) break; } else { if (thelist[j].contains(p) >= 0) break; } } if (i == 3) return -1; k = j; } return k; } void Delaunay::erasetriangle(Int a, Int b, Int c, Int d0, Int d1, Int d2) { Ullong key; Int j; key = hashfn.int64(a) ^ hashfn.int64(b) ^ hashfn.int64(c); if (trihash->get(key,j) == 0) throw("nonexistent triangle"); trihash->erase(key); thelist[j].d[0] = d0; thelist[j].d[1] = d1; thelist[j].d[2] = d2; thelist[j].stat = 0; ntri--; } Int Delaunay::storetriangle(Int a, Int b, Int c) { Ullong key; thelist[ntree].setme(a,b,c,&pts[0]); key = hashfn.int64(a) ^ hashfn.int64(b) ^ hashfn.int64(c); trihash->set(key,ntree); key = hashfn.int64(b)-hashfn.int64(c); linehash->set(key,a); key = hashfn.int64(c)-hashfn.int64(a); linehash->set(key,b); key = hashfn.int64(a)-hashfn.int64(b); linehash->set(key,c); if (++ntree == ntreemax) throw("thelist is sized too small"); ntri++; return (ntree-1); } Doub Delaunay::interpolate(const Point<2> &p, const vector &fnvals, Doub defaultval) { Int n,i,j,k; Doub wgts[3]; Int ipts[3]; Doub sum, ans = 0.0; n = whichcontainspt(p); if (n < 0) return defaultval; for (i=0; i<3; i++) ipts[i] = thelist[n].p[i]; for (i=0,j=1,k=2; i<3; i++,j++,k++) { if (j == 3) j=0; if (k == 3) k=0; wgts[k]=(pts[ipts[j]].x[0]-pts[ipts[i]].x[0])*(p.x[1]-pts[ipts[i]].x[1]) - (pts[ipts[j]].x[1]-pts[ipts[i]].x[1])*(p.x[0]-pts[ipts[i]].x[0]); } sum = wgts[0] + wgts[1] + wgts[2]; if (sum == 0) throw("degenerate triangle"); for (i=0; i<3; i++) ans += wgts[i]*fnvals[ipts[i]]/sum; return ans; } struct Convexhull : Delaunay { Int nhull; Int *hullpts; Convexhull(vector< Point<2> > pvec); }; Convexhull::Convexhull(vector< Point<2> > pvec) : Delaunay(pvec,2), nhull(0) { Int i,j,k,pstart; vector nextpt(npts); for (j=0; j > pvec); }; Minspantree::Minspantree(vector< Point<2> > pvec) : Delaunay(pvec,0), nspan(npts-1), minsega(nspan), minsegb(nspan) { Int i,j,k,jj,kk,m,tmp,nline,n = 0; Triel tt; nline = ntri + npts -1; VecInt sega(nline); VecInt segb(nline); VecDoub segd(nline); VecInt mo(npts); for (j=0; j tt.p[k]) continue; if (tt.p[i] >= npts || tt.p[k] >= npts) continue; sega[n] = tt.p[i]; segb[n] = tt.p[k]; segd[n] = dist(pts[sega[n]],pts[segb[n]]); n++; } } Indexx idx(segd); for (j=0; j