Skip to main content
added 34 characters in body
Source Link
theodox
  • 1.8k
  • 9
  • 9

@200's class is a great approach, so I'll steal it but I'm switching to itertoolsitertools to generate the point lists

@200's class is a great approach, so I'll steal it but I'm switching to itertools to generate the point lists

@200's class is a great approach, so I'll steal it but I'm switching to itertools to generate the point lists

added 195 characters in body
Source Link
theodox
  • 1.8k
  • 9
  • 9

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 Note that there are no bounds on the grid, although it would be trivial to add them (probably by setting a range on the CircleSet and rejecting points outside that range in the add method).

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

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 Note that there are no bounds on the grid, although it would be trivial to add them (probably by setting a range on the CircleSet and rejecting points outside that range in the add method).

Source Link
theodox
  • 1.8k
  • 9
  • 9

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