Skip to content

Instantly share code, notes, and snippets.

@nat-n
Created June 11, 2012 12:41
Show Gist options
  • Save nat-n/2909907 to your computer and use it in GitHub Desktop.
Save nat-n/2909907 to your computer and use it in GitHub Desktop.
largest circle fitting onto jax picking regions with debugging visualisation, also uses Raphael and https://github.com/gorhill/Javascript-Voronoi
Jax.getGlobal().ApplicationHelper = Jax.Helper.create
patch_world: ->
Jax.World.prototype.find_region_centers = () ->
context = this.context
w = context.canvas.width
h = context.canvas.height
f = 4
wf = w*f
data = new Uint8Array(w*h*4)
pickBuffer = new Jax.Framebuffer
width: w
height: h
depth: true
pickBuffer.bind context, () ->
pickBuffer.viewport(context)
context.gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
context.gl.disable(GL_BLEND)
context.world.render({material:"picking"})
context.gl.readPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data)
data = data.data if data.data
# restore the visible viewport and blending
context.gl.viewport 0, 0, w, h
context.gl.enable GL_BLEND
# find visible border pixels by region (randomly select half of one side of each border to speed things up a little)
borders_sites = []
for i in [0...data.length] by f
gi = i+1
if data[gi] and data[gi-f] != data[gi] or data[gi] != data[gi+wf] && Math.random()<0.5 # is border
quater_i = Math.floor(i/4)
borders_sites.push {x:quater_i%w, y:Math.ceil(quater_i/w)}
V = new Voronoi()
bbox = {xl:0, xr:w, yt:0, yb:h}
diagram = V.compute(borders_sites, bbox)
debug_paper = Raphael(648,8,w,h)
console.log diagram
centers = {}
# extract intersection points keeping only the best one for each region
for edge in diagram.edges
x = edge.va.x
y = edge.va.y
# skip borders
continue if x == bbox.xl || x == bbox.xr || y == bbox.yt || y == bbox.yb || !edge.lSite
# determine site distance (all sites should be at the same distance)
d = Math.sqrt(Math.pow(x-edge.lSite.x,2)+Math.pow(y-edge.lSite.y,2))
# determine region (green value) at this point
continue unless r = data[Math.floor(y)*w*f + Math.floor(x)*f + 1]
debug_paper.rect(edge.lSite.x-0.5,h-edge.lSite.y-0.5,1,1).attr(opacity: 0.2) # draw border pixel over debug canvas
continue unless d > 5 # skip tiny edges
#debug_paper.path([["M", edge.va.x, h-edge.va.y], ["L", edge.vb.x, h-edge.vb.y]]).attr(opacity: 0.1, fill: "red")
centers[r] = centers[r] || {x:x, y:h-y, d:d}
if d > centers[r].d
centers[r] = {x:x, y:h-y, d:d}
for r of centers
debug_paper.circle(centers[r].x,centers[r].y,centers[r].d) # draw largest circle over debug canvas
centers[r].region = this.getObject(r)
# show pickBuffer
debug_context = document.getElementById("debug").getContext('2d')
imagedata = debug_context.getImageData 0, 0, w, h
# data needs to be flipped vertically as it's loaded into imagedata
bytesPerLine = w*4
dr = data.length
for r in [0...data.length] by bytesPerLine
dr -= bytesPerLine
for c in [0...w*4] by 4
di = dr+c
i = r+c
imagedata.data[i] = data[di]
imagedata.data[i+1] = data[di+1]
imagedata.data[i+2] = data[di+2]*2
imagedata.data[i+3] = data[di+3]
debug_context.putImageData imagedata, 0, 0
return centers
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment