block by mpmckenna8 0d582d86a59444e3f0411030f9ef2f4f

Poisson disc distribution image sample of a tacocat

Full Screen

So this show how to basically do https://bl.ocks.org/mbostock/22fd67be72552774736d using d3 v4. It basically use an imlementation of a Poisson disk distribution to do some sampling and then uses the pixel color to color in a polygon generated by a voronoi algorithm on all the sampled points.

The original picture of the taco cat I used can be found https://c1.staticflickr.com/7/6046/6303841970_a9f081904c.jpg

Put more taco cats on the internet pls

index.html

<!DOCTYPE html>
<html>
    <head>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.7.4/d3.js"></script>
  </head>
  <body>
    <div id="heap">
    </div>
  <script src="main.js"></script>

  </body>

</html>

main.js

// needed if using a build tool like browserify
// var d3 = require('d3');

console.log('ready to get sampling')
var width = 300
let height = 400

var sample = poissonDiscSampler(width, height, 3.45)
let samples = []
let s

while (s = sample()) samples.push(s)

console.log(samples)

var voronoi = d3.voronoi()
  .extent([[0, 0], [width, height]])

var canvas = d3.select('body').append('canvas')
    .attr('width', width)
        .attr('height', height)
var context = canvas.node().getContext('2d')

var image = new Image()
image.src = 'tacocatlit.jpg'
image.onload = start

function start () {
  context.drawImage(image, 0, 0)
  image = context.getImageData(0, 0, width, height)
  var diagram = voronoi(samples)
  var links = diagram.links()
  polygons = diagram.polygons()

  console.log('diagram, ', diagram)


  context.fillStyle = 'green' // "#f00"; context.fill() 
  for (var i = 0, n = polygons.length; i < n; ++i) {
    context.beginPath()
    drawCell(polygons[i])
    var x = Math.floor(polygons[i].data[0]),
      y = Math.floor(polygons[i].data[1]),
      q = (y * width + x) << 2
    var color = d3.rgb(image.data[q + 0], image.data[q + 1], image.data[q + 2]) + ''
//    console.log(color)
    context.fillStyle = color 
	context.fill()
  }


}

// Based on https://www.jasondavies.com/poisson-disc/
function poissonDiscSampler (width, height, radius) {
  var k = 30, // maximum number of samples before rejection
    radius2 = radius * radius,
    R = 3 * radius2,
    cellSize = radius * Math.SQRT1_2,
    gridWidth = Math.ceil(width / cellSize),
    gridHeight = Math.ceil(height / cellSize),
    grid = new Array(gridWidth * gridHeight),
    queue = [],
    queueSize = 0,
    sampleSize = 0

  return function () {
    if (!sampleSize) return sample(Math.random() * width, Math.random() * height)

    // Pick a random existing sample and remove it from the queue.
    while (queueSize) {
      var i = Math.random() * queueSize | 0,
        s = queue[i]

      // Make a new candidate between [radius, 2 * radius] from the existing sample.
      for (var j = 0; j < k; ++j) {
        var a = 2 * Math.PI * Math.random(),
          r = Math.sqrt(Math.random() * R + radius2),
          x = s[0] + r * Math.cos(a),
          y = s[1] + r * Math.sin(a)

        // Reject candidates that are outside the allowed extent,
        // or closer than 2 * radius to any existing sample.
        if (x >= 0 && x < width && y >= 0 && y < height && far(x, y)) return sample(x, y)
      }

      queue[i] = queue[--queueSize]
      queue.length = queueSize
    }
  }

  function far (x, y) {
    var i = x / cellSize | 0,
      j = y / cellSize | 0,
      i0 = Math.max(i - 2, 0),
      j0 = Math.max(j - 2, 0),
      i1 = Math.min(i + 3, gridWidth),
      j1 = Math.min(j + 3, gridHeight)

    for (j = j0; j < j1; ++j) {
      var o = j * gridWidth
      for (i = i0; i < i1; ++i) {
        if (s = grid[o + i]) {
          var s,
            dx = s[0] - x,
            dy = s[1] - y
          if (dx * dx + dy * dy < radius2) return false
        }
      }
    }

    return true
  }

  function sample (x, y) {
    var s = [x, y]
    queue.push(s)
    grid[gridWidth * (y / cellSize | 0) + (x / cellSize | 0)] = s
    ++sampleSize
    ++queueSize
    return s
  }
}

function drawSite (site) {
  context.moveTo(site[0] + 2.5, site[1])
  context.arc(site[0], site[1], 2.5, 0, 2 * Math.PI, false)
}

function drawLink (link) {
  context.moveTo(link.source[0], link.source[1])
  context.lineTo(link.target[0], link.target[1])
}

function drawCell (cell) {
  if (!cell) return false
  context.moveTo(cell[0][0], cell[0][1])
  for (var j = 1, m = cell.length; j < m; ++j) {
    context.lineTo(cell[j][0], cell[j][1])
  }
  context.closePath()
  return true
}