geom-demo/geom/demos/sat.py

95 lines
2.8 KiB
Python
Raw Normal View History

2020-11-14 11:12:00 -07:00
from ..geom import Rect, Polygon
from .. import WIDTH, HEIGHT, get_cursor_pos, get_inputs
2020-11-14 11:12:00 -07:00
from ..colors import *
from ..math import *
from ..draw import *
2020-11-14 11:12:00 -07:00
class SeparatingAxisTheorem:
title = "Separating Axis Theorem"
def __init__(self):
self.shape1 = Polygon(0, 0, [
(0, 60),
(60, 0),
(0, -60),
(-60, 0)
])
self.shape2 = Polygon(*get_cursor_pos(), [
(60, 60),
(60, -60),
(-60, -60),
(-60, 60)
])
def handle_input(self):
2020-11-14 11:12:00 -07:00
self.shape2.set_position(*get_cursor_pos())
inputs = get_inputs()
if inputs[pygame.K_q]:
self.shape2.rotate((1/60) * -90)
if inputs[pygame.K_e]:
self.shape2.rotate((1/60) * 90)
def draw_axis(self, surface, normal, colliding, min1, max1, min2, max2):
offset = scale(*rnormal(*normal), 300)
# axis
line(surface, WHITE,
add(*scale(*reverse(*normal), 1000), *offset),
add(*scale(*normal, 1000), *offset))
# shape 1
line(surface, GREEN if not colliding else RED,
add(*scale(*normal, min1), *offset),
add(*scale(*normal, max1), *offset), 8)
# shape 2
line(surface, GREEN if not colliding else RED,
add(*scale(*normal, min2), *offset),
add(*scale(*normal, max2), *offset), 8)
def render(self, surface):
self.handle_input()
2020-11-14 11:12:00 -07:00
normals = []
def add_if_not_exists(normal):
for existing in normals:
if is_equal(*existing, *normal):
return
normals.append(normal)
for normal in self.shape1.get_normals() + self.shape2.get_normals():
add_if_not_exists(normal)
def get_min_max(normal, vertices):
_min = float('inf')
_max = float('-inf')
for vertex in vertices:
proj = dot(*normal, *vertex)
_min = min(_min, proj)
_max = max(_max, proj)
return _min, _max
overlaps = []
2020-11-14 11:12:00 -07:00
for normal in normals:
min1, max1 = get_min_max(normal,
self.shape1.get_translated_vertices())
min2, max2 = get_min_max(normal,
self.shape2.get_translated_vertices())
overlap = max(min2 - max1, min1 - max2)
overlaps.append(overlap)
2020-11-14 11:12:00 -07:00
self.draw_axis(surface, normal, overlap < 0, min1, max1, min2, max2)
2020-11-14 11:12:00 -07:00
colliding = all(overlap < 0 for overlap in overlaps)
if colliding:
text_screen(surface, WHITE, (10, HEIGHT - 20),
f"Min Distance to Resolve: {max(overlaps)}")
2020-11-14 11:12:00 -07:00
self.shape1.draw(surface, YELLOW, 4)
self.shape2.draw(surface, RED if colliding else WHITE, 4)