template struct Boxnode : Box { Int mom, dau1, dau2, ptlo, pthi; Boxnode() {} Boxnode(Point mylo, Point myhi, Int mymom, Int myd1, Int myd2, Int myptlo, Int mypthi) : Box(mylo, myhi), mom(mymom), dau1(myd1), dau2(myd2), ptlo(myptlo), pthi(mypthi) {} }; Int selecti(const Int k, Int *indx, Int n, Doub *arr) { Int i,ia,ir,j,l,mid; Doub a; l=0; ir=n-1; for (;;) { if (ir <= l+1) { if (ir == l+1 && arr[indx[ir]] < arr[indx[l]]) SWAP(indx[l],indx[ir]); return indx[k]; } else { mid=(l+ir) >> 1; SWAP(indx[mid],indx[l+1]); if (arr[indx[l]] > arr[indx[ir]]) SWAP(indx[l],indx[ir]); if (arr[indx[l+1]] > arr[indx[ir]]) SWAP(indx[l+1],indx[ir]); if (arr[indx[l]] > arr[indx[l+1]]) SWAP(indx[l],indx[l+1]); i=l+1; j=ir; ia = indx[l+1]; a=arr[ia]; for (;;) { do i++; while (arr[indx[i]] < a); do j--; while (arr[indx[j]] > a); if (j < i) break; SWAP(indx[i],indx[j]); } indx[l+1]=indx[j]; indx[j]=ia; if (j >= k) ir=j-1; if (j <= k) l=i; } } } template struct KDtree { static const Doub BIG; Int nboxes, npts; vector< Point > &ptss; Boxnode *boxes; VecInt ptindx, rptindx; Doub *coords; KDtree(vector< Point > &pts); ~KDtree() {delete [] boxes;} Doub disti(Int jpt, Int kpt); Int locate(Point pt); Int locate(Int jpt); Int nearest(Point pt); void nnearest(Int jpt, Int *nn, Doub *dn, Int n); static void sift_down(Doub *heap, Int *ndx, Int nn); Int locatenear(Point pt, Doub r, Int *list, Int nmax); }; template const Doub KDtree::BIG(1.0e99); template KDtree::KDtree(vector< Point > &pts) : ptss(pts), npts(pts.size()), ptindx(npts), rptindx(npts) { Int ntmp,m,k,kk,j,nowtask,jbox,np,tmom,tdim,ptlo,pthi; Int *hp; Doub *cp; Int taskmom[50], taskdim[50]; for (k=0; k>= 1) { m <<= 1; } nboxes = 2*npts - (m >> 1); if (m < nboxes) nboxes = m; nboxes--; boxes = new Boxnode[nboxes]; coords = new Doub[DIM*npts]; for (j=0, kk=0; j lo(-BIG,-BIG,-BIG), hi(BIG,BIG,BIG); boxes[0] = Boxnode(lo, hi, 0, 0, 0, 0, npts-1); jbox = 0; taskmom[1] = 0; taskdim[1] = 0; nowtask = 1; while (nowtask) { tmom = taskmom[nowtask]; tdim = taskdim[nowtask--]; ptlo = boxes[tmom].ptlo; pthi = boxes[tmom].pthi; hp = &ptindx[ptlo]; cp = &coords[tdim*npts]; np = pthi - ptlo + 1; kk = (np-1)/2; (void) selecti(kk,hp,np,cp); hi = boxes[tmom].hi; lo = boxes[tmom].lo; hi.x[tdim] = lo.x[tdim] = coords[tdim*npts + hp[kk]]; boxes[++jbox] = Boxnode(boxes[tmom].lo,hi,tmom,0,0,ptlo,ptlo+kk); boxes[++jbox] = Boxnode(lo,boxes[tmom].hi,tmom,0,0,ptlo+kk+1,pthi); boxes[tmom].dau1 = jbox-1; boxes[tmom].dau2 = jbox; if (kk > 1) { taskmom[++nowtask] = jbox-1; taskdim[nowtask] = (tdim+1) % DIM; } if (np - kk > 3) { taskmom[++nowtask] = jbox; taskdim[nowtask] = (tdim+1) % DIM; } } for (j=0; j Doub KDtree::disti(Int jpt, Int kpt) { if (jpt == kpt) return BIG; else return dist(ptss[jpt], ptss[kpt]); } template Int KDtree::locate(Point pt) { Int nb,d1,jdim; nb = jdim = 0; while (boxes[nb].dau1) { d1 = boxes[nb].dau1; if (pt.x[jdim] <= boxes[d1].hi.x[jdim]) nb=d1; else nb=boxes[nb].dau2; jdim = ++jdim % DIM; } return nb; } template Int KDtree::locate(Int jpt) { Int nb,d1,jh; jh = rptindx[jpt]; nb = 0; while (boxes[nb].dau1) { d1 = boxes[nb].dau1; if (jh <= boxes[d1].pthi) nb=d1; else nb = boxes[nb].dau2; } return nb; } template Int KDtree::nearest(Point pt) { Int i,k,nrst,ntask; Int task[50]; Doub dnrst = BIG, d; k = locate(pt); for (i=boxes[k].ptlo; i<=boxes[k].pthi; i++) { d = dist(ptss[ptindx[i]],pt); if (d < dnrst) { nrst = ptindx[i]; dnrst = d; } } task[1] = 0; ntask = 1; while (ntask) { k = task[ntask--]; if (dist(boxes[k],pt) < dnrst) { if (boxes[k].dau1) { task[++ntask] = boxes[k].dau1; task[++ntask] = boxes[k].dau2; } else { for (i=boxes[k].ptlo; i<=boxes[k].pthi; i++) { d = dist(ptss[ptindx[i]],pt); if (d < dnrst) { nrst = ptindx[i]; dnrst = d; } } } } } return nrst; } template void KDtree::nnearest(Int jpt, Int *nn, Doub *dn, Int n) { Int i,k,ntask,kp; Int task[50]; Doub d; if (n > npts-1) throw("too many neighbors requested"); for (i=0; i1) sift_down(dn,nn,n); } } task[1] = 0; ntask = 1; while (ntask) { k = task[ntask--]; if (k == kp) continue; if (dist(boxes[k],ptss[jpt]) < dn[0]) { if (boxes[k].dau1) { task[++ntask] = boxes[k].dau1; task[++ntask] = boxes[k].dau2; } else { for (i=boxes[k].ptlo; i<=boxes[k].pthi; i++) { d = disti(ptindx[i],jpt); if (d < dn[0]) { dn[0] = d; nn[0] = ptindx[i]; if (n>1) sift_down(dn,nn,n); } } } } } return; } template void KDtree::sift_down(Doub *heap, Int *ndx, Int nn) { Int n = nn - 1; Int j,jold,ia; Doub a; a = heap[0]; ia = ndx[0]; jold = 0; j = 1; while (j <= n) { if (j < n && heap[j] < heap[j+1]) j++; if (a >= heap[j]) break; heap[jold] = heap[j]; ndx[jold] = ndx[j]; jold = j; j = 2*j + 1; } heap[jold] = a; ndx[jold] = ia; } template Int KDtree::locatenear(Point pt, Doub r, Int *list, Int nmax) { Int k,i,nb,nbold,nret,ntask,jdim,d1,d2; Int task[50]; nb = jdim = nret = 0; if (r < 0.0) throw("radius must be nonnegative"); while (boxes[nb].dau1) { nbold = nb; d1 = boxes[nb].dau1; d2 = boxes[nb].dau2; if (pt.x[jdim] + r <= boxes[d1].hi.x[jdim]) nb = d1; else if (pt.x[jdim] - r >= boxes[d2].lo.x[jdim]) nb = d2; jdim = ++jdim % DIM; if (nb == nbold) break; } task[1] = nb; ntask = 1; while (ntask) { k = task[ntask--]; if (dist(boxes[k],pt) > r) continue; if (boxes[k].dau1) { task[++ntask] = boxes[k].dau1; task[++ntask] = boxes[k].dau2; } else { for (i=boxes[k].ptlo; i<=boxes[k].pthi; i++) { if (dist(ptss[ptindx[i]],pt) <= r && nret < nmax) list[nret++] = ptindx[i]; if (nret == nmax) return nmax; } } } return nret; }