You don't really need to maintain a big empty grid, the empty cells aren't telling you anything. Instead, you can use a dictionary to store grid points that are contained by a particular circle, then just collect all of the dictionary entries with more than one reference.
@200's class is a great approach, so I'll steal it but I'm switching to itertools to generate the point lists
import itertools
from collections import namedtuple
class Circle (namedtuple('Circle', ['x', 'y', 'r'])):
def points(self):
x_range = int(self.x - self.r), int(self.x + self.r + 1)
y_range = int(self.y - self.r), int(self.y + self.r + 1)
contained = lambda xy: (xy[0] - self.x)**2 + (xy[1] - self.y)**2 <= self.r**2
return itertools.ifilter(contained, itertools.product(xrange(*x_range), xrange(*y_range)))
class CircleSet(dict):
def __init__(self):
self.intersections = set()
def add(self, circle):
for point in circle.points():
try:
self[point].append(circle)
self.intersections.add(point)
except KeyError:
self[point] = [circle]
def overlaps(self):
return [(p, self[p]) for p in self.intersections]
The main idea here is to use the dictionary CircleSet as a sparse grid: it will only have keys where a point falls into a circle. I'm using a separate set() object to track intersections so that the 'overlaps' function does not have to look at every value and see if there are multiple entries, but you could ditch that and do
def overlaps(self):
return [(p, self[p]) for p in self if len(self[p] > 1 ]
The first version will be faster but you're storing redundant copies of the indices, which might matter for big data sets
Usage:
c1 = Circle (2,2,2)
c2 = Circle(3,3,2.5)
c3 = Circle(5,5,1)
c4 = Circle(2,3,2)
test = CircleSet()
for c in [c1, c2, c3, c4]:
test.add(c)
for i in test.overlaps():
print i
The results include a printout of the point and the circles which it overlaps. Or you can just get the points which are included in more than one circle with .intersections