From 7f33e917d7e2aa1b451424eaf3b58424599138c8 Mon Sep 17 00:00:00 2001 From: Matt Low Date: Sat, 14 Nov 2020 22:12:00 +0400 Subject: [PATCH] Add Separating Axis Theorum demo --- geom/demos/sat.py | 77 +++++++++++++++++++++++++++++++++++++++++++++++ geom/screen.py | 3 +- 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 geom/demos/sat.py diff --git a/geom/demos/sat.py b/geom/demos/sat.py new file mode 100644 index 0000000..5f94946 --- /dev/null +++ b/geom/demos/sat.py @@ -0,0 +1,77 @@ +from ..geom import Rect, Polygon +from .. import WIDTH, HEIGHT, get_cursor_pos +from ..colors import * +from ..math import * +from ..draw import * + +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 render(self, surface): + self.shape2.set_position(*get_cursor_pos()) + + 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 + + collisions = [] + 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()) + + colliding = max1 > min2 and max2 > min1 + collisions.append(colliding) + + offset = scale(*rnormal(*normal), 300) + + # axis + line(surface, WHITE, + add(*scale(*reverse(*normal), 1000), *offset), + add(*scale(*normal, 1000), *offset)) + + # shape 1 + line(surface, YELLOW if not colliding else RED, + add(*scale(*normal, min1), *offset), + add(*scale(*normal, max1), *offset), 5) + # shape 2 + line(surface, YELLOW if not colliding else RED, + add(*scale(*normal, min2), *offset), + add(*scale(*normal, max2), *offset), 5) + + + self.shape1.draw(surface, YELLOW, 4) + self.shape2.draw(surface, RED if all(collisions) else WHITE, 4) diff --git a/geom/screen.py b/geom/screen.py index 4b2a1bd..5017ce8 100644 --- a/geom/screen.py +++ b/geom/screen.py @@ -1,5 +1,5 @@ import pygame -from .demos import aabb, vec_proj +from .demos import aabb, vec_proj, sat from . import HEIGHT from .colors import * from .draw import text_screen @@ -11,6 +11,7 @@ class Screen: vec_proj.VecProj(), aabb.AABBDistance(), aabb.PointAABBDistance(), + sat.SeparatingAxisTheorem(), ] self.demo = 0