Quaternary Tree
# "Spatial Tessellations: Concepts and Applications of Voronoi Diagrams," 2nd Ed. # A. Okabe, B. Boots, K, Sugihara, S.N. Chiu, Wiley 2000 # p.245 Algorithm 4.3.1, Ch4 Algorithms for Computing Voronoi Diagram # Given randomly generated 2D points pi (i=0..n) in the unit square # Find the closest generator pi to a point p # construction: define mapping g: qtree -> generators (k = ceil(log(n)/log(4))) # [1] assign a root bucket u0 to p0: g(u0) = [p0] # [2] append pj to list of points that fall in a k-level bucket u: g(u) << pj # [3] assign unassigned parent nodes u' of u to pj: g(u') = [pj] # application [1]: distributed navigation # visit in breadth-first search order and output g(u) iff g(u)!=g(u'), u': parent # application [2]: the nearest neighbor at level l <= k # find a nearest node u of any given point p, then g(u) is the nearest at level l.
Graphics modules not shown below (see "Maximum Distance Bisectors" as of 2007-02-25)
require 'geom' # 2D point in the normalized [] square S[0..1, 0..1] class QPoint < Point attr_accessor :nx, :ny def initialize nx, ny, *args @nx, @ny = nx, ny super((ScrHgt*@nx).to_i, (ScrHgt*@ny).to_i, *args) end def index level i = 2**level [(@nx*i).to_i, (@ny*i).to_i] end end # quaternary tree class QTree attr_accessor :lvl, :idx, :hsh def initialize n @lvl = n @idx = Array.new n (0..n).each {|i| @idx[i] = (4**i - 1)/3} @hsh = Hash.new end def index level, i, j return 0 if level == 0 @idx[level] + i + j*2**level end def add level, pnt i, j = pnt.index level key = index level, i, j ary = @hsh[key] if ary @hsh[key] = ary << pnt else @hsh[key] = [pnt] end until level == 0 level = level - 1 i = i/2 j = j/2 key = index level, i, j break if @hsh[key] @hsh[key] = [pnt] end end def out k = 0 (0..@lvl).each {|l| n = 2**l (0...n).each {|i| (0...n).each {|j| ary = @hsh[index(l, i, j)] next unless ary mom = @hsh[index(l-1, i/2, j/2)][0] if l>0 (0..ary.size).each {|m| pnt = ary[m] next if (!pnt or (l>0 && mom == pnt)) p pnt k = k + 1 } } } } end end if __FILE__ == $0 N = 3 qt = QTree.new N (4**N).times { p = QPoint.new(rand, rand) qt.add(N, p) } qt.out end
I have a little doubt on the claim of "uniformly distributed", since we see the points are arranged rather into slab patterns.