110 lines
3.5 KiB
Python
110 lines
3.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright (C) 2014 Chris Hinsley All Rights Reserved
|
|
# Copyright (C) 2022 Jeff Moe
|
|
|
|
import math, mymath
|
|
|
|
class Layer():
|
|
def __init__(self, dimensions, scale):
|
|
self.width, self.height = dimensions
|
|
self.scale = scale
|
|
self.buckets = [[] for x in range(self.width * self.height)]
|
|
self.test = 0
|
|
|
|
def aabb(self, line):
|
|
x1, y1, x2, y2, r, g = line
|
|
if x1 > x2:
|
|
x1, x2 = x2, x1
|
|
if y1 > y2:
|
|
y1, y2 = y2, y1
|
|
r += g
|
|
minx = int(math.floor((x1 - r) * self.scale))
|
|
miny = int(math.floor((y1 - r) * self.scale))
|
|
maxx = int(math.ceil((x2 + r) * self.scale))
|
|
maxy = int(math.ceil((y2 + r) * self.scale))
|
|
if minx < 0:
|
|
minx = 0
|
|
if miny < 0:
|
|
miny = 0
|
|
if maxx > self.width:
|
|
maxx = self.width
|
|
if maxy > self.height:
|
|
maxy = self.height
|
|
return (minx, miny, maxx, maxy)
|
|
|
|
def all_buckets(self, aabb):
|
|
x1, y1, x2, y2 = aabb
|
|
for y in range(y1, y2):
|
|
for x in range(x1, x2):
|
|
yield self.buckets[y * self.width + x]
|
|
|
|
def all_not_empty_buckets(self, aabb):
|
|
x1, y1, x2, y2 = aabb
|
|
for y in range(y1, y2):
|
|
for x in range(x1, x2):
|
|
bucket = self.buckets[y * self.width + x]
|
|
if bucket:
|
|
yield bucket
|
|
|
|
def add_line(self, line):
|
|
new_record = [0, line]
|
|
for bucket in self.all_buckets(self.aabb(line)):
|
|
found = False
|
|
for record in bucket:
|
|
if record[1] == line:
|
|
found = True
|
|
break
|
|
if not found:
|
|
bucket.append(new_record)
|
|
|
|
def sub_line(self, line):
|
|
for bucket in self.all_not_empty_buckets(self.aabb(line)):
|
|
for i in range(len(bucket) - 1, -1, -1):
|
|
if bucket[i][1] == line:
|
|
del bucket[i]
|
|
|
|
def hit_line(self, line):
|
|
self.test += 1
|
|
for bucket in self.all_not_empty_buckets(self.aabb(line)):
|
|
for record in bucket:
|
|
if record[0] != self.test:
|
|
record[0] = self.test
|
|
l1_p1x, l1_p1y, l1_p2x, l1_p2y, l1_r, l1_g = line
|
|
l2_p1x, l2_p1y, l2_p2x, l2_p2y, l2_r, l2_g = record[1]
|
|
r = l1_r + l2_r + max(l1_g, l2_g)
|
|
if mymath.collide_thick_lines_2d((l1_p1x, l1_p1y), (l1_p2x, l1_p2y), (l2_p1x, l2_p1y), (l2_p2x, l2_p2y), r):
|
|
return True
|
|
return False
|
|
|
|
class Layers():
|
|
def __init__(self, dimensions, scale):
|
|
width, height, self.depth = dimensions
|
|
self.layers = [Layer((width, height), scale) for z in range(self.depth)]
|
|
|
|
def all_layers(self, z1, z2):
|
|
if z1 != z2:
|
|
for z in range(self.depth):
|
|
yield self.layers[z]
|
|
else:
|
|
yield self.layers[int(z1)]
|
|
|
|
def add_line(self, p1, p2, r, g):
|
|
x1, y1, z1 = p1
|
|
x2, y2, z2 = p2
|
|
for layer in self.all_layers(z1, z2):
|
|
layer.add_line((x1, y1, x2, y2, r, g))
|
|
|
|
def sub_line(self, p1, p2, r, g):
|
|
x1, y1, z1 = p1
|
|
x2, y2, z2 = p2
|
|
for layer in self.all_layers(z1, z2):
|
|
layer.sub_line((x1, y1, x2, y2, r, g))
|
|
|
|
def hit_line(self, p1, p2, r, g):
|
|
x1, y1, z1 = p1
|
|
x2, y2, z2 = p2
|
|
for layer in self.all_layers(z1, z2):
|
|
if layer.hit_line((x1, y1, x2, y2, r, g)):
|
|
return True
|
|
return False
|