from math import pi, sin, cos, hypot, floor
import random

class Grid(object):
    def __init__(self, r):
        self.r = r
        self.size = r / 2 ** 0.5
        self.cells = {}
    def points(self):
        return self.cells.values()
    def normalize(self, x, y):
        i = int(floor(x / self.size))
        j = int(floor(y / self.size))
        return (i, j)
    def nearby(self, x, y):
        result = []
        i, j = self.normalize(x, y)
        for p in xrange(i - 2, i + 3):
            for q in xrange(j - 2, j + 3):
                if (p, q) in self.cells:
                    result.append(self.cells[(p, q)])
        return result
    def insert(self, x, y):
        for bx, by in self.nearby(x, y):
            if hypot(x - bx, y - by) < self.r:
                return False
        i, j = self.normalize(x, y)
        self.cells[(i, j)] = (x, y)
        return True

def poisson_disc(x1, y1, x2, y2, r, n):
    x = x1 + (x2 - x1) / 2.0
    y = y1 + (y2 - y1) / 2.0
    active = [(x, y)]
    grid = Grid(r)
    grid.insert(x, y)
    while active:
        ax, ay = random.choice(active)
        for i in xrange(n):
            a = random.random() * 2 * pi
            d = random.random() * r + r
            x = ax + cos(a) * d
            y = ay + sin(a) * d
            if x < x1 or y < y1 or x > x2 or y > y2:
                continue
            if not grid.insert(x, y):
                continue
            active.append((x, y))
            break
        else:
            active.remove((ax, ay))
    return grid.points()
