Sample implementation of kcsquared's algorithm. You didn't specify a language, so I chose Python since I'm familiar with it and it's short readable code. Rectangles have lower left coordinate (x,y) and upper right coordinate (X,Y).
def intersections(rects):
events = []
for A in rects:
events.append((A.x, 'insert', A.y, A.Y))
events.append((A.X, 'remove', A.y, A.Y))
intersections = 0
ys = SortedList()
Ys = SortedList()
for x, op, y, Y in sorted(events):
if op == 'insert':
intersections += ys.bisect_right(Y) - Ys.bisect_left(y)
ys.add(y)
Ys.add(Y)
else:
ys.remove(y)
Ys.remove(Y)
return intersections
Tests on lists of 5,000 random rectangles against an O(n2) reference implementation, showing the numbers of intersections and runtimes:
124257 5465 ms reference
124257 127 ms intersections
121166 5444 ms reference
121166 124 ms intersections
118980 5435 ms reference
118980 124 ms intersections
With 10,000 rectangles:
489617 22342 ms reference
489617 292 ms intersections
489346 22491 ms reference
489346 296 ms intersections
489990 22302 ms reference
489990 290 ms intersections
Full code:
def reference(rects):
intersections = 0
for A, B in combinations(rects, 2):
if A.X >= B.x and A.x <= B.X and A.Y >= B.y and A.y <= B.Y:
intersections += 1
return intersections
def intersections(rects):
events = []
for A in rects:
events.append((A.x, 'insert', A.y, A.Y))
events.append((A.X, 'remove', A.y, A.Y))
intersections = 0
ys = SortedList()
Ys = SortedList()
for x, op, y, Y in sorted(events):
if op == 'insert':
intersections += ys.bisect_right(Y) - Ys.bisect_left(y)
ys.add(y)
Ys.add(Y)
else:
ys.remove(y)
Ys.remove(Y)
return intersections
from random import randint, randrange
from itertools import combinations
from timeit import default_timer as timer
from sortedcontainers import SortedList
from collections import namedtuple
Rect = namedtuple('Rect', 'x X y Y')
for _ in range(3):
rects = [Rect(x, x + randint(1, 100), y, y + randint(1, 100))
for _ in range(5000)
for x, y in [(randrange(1000), randrange(1000))]]
for func in reference, intersections:
t0 = timer()
result = func(rects)
t1 = timer()
print(result, '%4d ms' % ((t1 - t0) * 1e3), func.__name__)
print()