Skip to content

Instantly share code, notes, and snippets.

@zeffii
Forked from anonymous/poisson_nodescr.py
Created January 3, 2015 23:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeffii/e09220883894cb3f978b to your computer and use it in GitHub Desktop.
Save zeffii/e09220883894cb3f978b to your computer and use it in GitHub Desktop.
import numpy as np
import math
from math import sqrt, pi, sin, cos, ceil
from random import random
SQRT1_2 = 0.707106781
class poissonDiscSampler(object):
def __init__(self, width, height, radius):
# http://bl.ocks.org/mbostock/19168c663618b7f07158
# Based on https://www.jasondavies.com/poisson-disc/
self.k = 30 # maximum number of samples before rejection
self.radius2 = radius * radius
self.R = 3 * self.radius2
self.cellSize = radius * SQRT1_2
self.width = width
self.height = height
self.gridWidth = ceil(width / self.cellSize)
self.gridHeight = ceil(height / self.cellSize)
self.num_elements = self.gridWidth * self.gridHeight
self.grid = np.ndarray(shape=(self.num_elements, 3))
self.queue = []
self.queueSize = 0
self.sampleSize = 0
self.finder()
def far(self, x, y):
i = int(x / self.cellSize) | 0
j = int(y / self.cellSize) | 0
i0 = max(i - 2, 0)
j0 = max(j - 2, 0)
i1 = min(i + 3, self.gridWidth)
j1 = min(j + 3, self.gridHeight)
for j in range(j0, j1):
o = j * self.gridWidth
for i in range(i0, i1):
if (o + i) < self.num_elements:
s = 0
dx = s[0] - x
dy = s[1] - y
if ((dx * dx + dy * dy) < self.radius2):
return False
return True
def sample(self, x, y):
s = [x, y, 0]
self.queue.append(s)
self.grid[self.gridWidth * (int(y / self.cellSize) | 0) + (int(x / self.cellSize) | 0)] = s
self.sampleSize += 1
self.queueSize += 1
return s
def finder(self):
if (not self.sampleSize):
return self.sample(random() * self.width, random() * self.height)
# Pick a random existing sample and remove it from the queue.
while (self.queueSize):
i = int(random() * self.queueSize) | 0
s = self.queue[i]
# Make a new candidate between [radius, 2 * radius] from the existing sample.
for j in range(self.k):
a = 2 * pi * random()
r = sqrt(random() * self.R + self.radius2)
x = s[0] + r * cos(a)
y = s[1] + r * sin(a)
# Reject candidates that are outside the allowed extent,
# or closer than 2 * radius to any existing sample.
if (0 <= x and x < self.width and 0 <= y and y < self.height and self.far(x, y)):
return self.sample(x, y)
self.queueSize -= 1
self.queue[i] = self.queue[self.queueSize]
self.queue = self.queue[0:self.queueSize]
def get_points(self):
return self.grid
def sv_main(height=2.0, width=3.0, radius=0.3):
verts_out = []
in_sockets = [
['s', 'height', height],
['s', 'width', width],
['s', 'radius', radius]
]
out_sockets = [
['v', 'verts', [verts_out]]
]
r = max(0.01, radius)
point_gen = poissonDiscSampler(width, height, r)
grid = point_gen.get_points().tolist()
verts_out.extend(grid)
return in_sockets, out_sockets
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment