Skip to content

Fix #771 by replacing collision-tests with shapely #788

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 12 additions & 51 deletions arcade/geometry.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
"""
Functions for calculating geometry.
"""
from shapely import speedups
from shapely.geometry import LineString, Polygon, Point

from typing import cast
from arcade import PointList
import math

_PRECISION = 2

speedups.enable()


def are_polygons_intersecting(poly_a: PointList,
poly_b: PointList) -> bool:
Expand All @@ -21,38 +25,10 @@ def are_polygons_intersecting(poly_a: PointList,
:rtype bool:
"""

for polygon in (poly_a, poly_b):

for i1 in range(len(polygon)):
i2 = (i1 + 1) % len(polygon)
projection_1 = polygon[i1]
projection_2 = polygon[i2]

normal = (projection_2[1] - projection_1[1],
projection_1[0] - projection_2[0])

min_a, max_a, min_b, max_b = (None,) * 4

for poly in poly_a:
projected = normal[0] * poly[0] + normal[1] * poly[1]
shapely_polygon_a = Polygon(poly_a)
shapely_polygon_b = Polygon(poly_b)

if min_a is None or projected < min_a:
min_a = projected
if max_a is None or projected > max_a:
max_a = projected

for poly in poly_b:
projected = normal[0] * poly[0] + normal[1] * poly[1]

if min_b is None or projected < min_b:
min_b = projected
if max_b is None or projected > max_b:
max_b = projected

if cast(float, max_a) <= cast(float, min_b) or cast(float, max_b) <= cast(float, min_a):
return False

return True
return shapely_polygon_a.intersects(shapely_polygon_b)


def is_point_in_polygon(x, y, polygon_point_list):
Expand All @@ -67,27 +43,12 @@ def is_point_in_polygon(x, y, polygon_point_list):
Returns: bool

"""
n = len(polygon_point_list)
inside = False
if n == 0:
return False

p1x, p1y = polygon_point_list[0]
for i in range(n+1):
p2x, p2y = polygon_point_list[i % n]
if y > min(p1y, p2y):
if y <= max(p1y, p2y):
if x <= max(p1x, p2x):
if p1y != p2y:
xints = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
# noinspection PyUnboundLocalVariable
if p1x == p2x or x <= xints:
inside = not inside
p1x, p1y = p2x, p2y

return inside
shapely_point = Point(x, y)
shapely_polygon = Polygon(polygon_point_list)

return shapely_polygon.contains(shapely_point)


def get_distance(x1: float, y1: float, x2: float, y2: float):
""" Get the distance between two points. """
return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
return math.hypot(x1 - x2, y1 - y2)
15 changes: 4 additions & 11 deletions arcade/sprite_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -1168,7 +1168,7 @@ def check_for_collision_with_list(sprite: Sprite,
sprite_list_to_check = sprite_list

# print(len(sprite_list_to_check.sprite_list))
collision_list = [sprite2
return [sprite2
for sprite2 in sprite_list_to_check
if sprite is not sprite2 and _check_for_collision(sprite, sprite2)]

Expand All @@ -1177,7 +1177,6 @@ def check_for_collision_with_list(sprite: Sprite,
# if sprite1 is not sprite2 and sprite2 not in collision_list:
# if _check_for_collision(sprite1, sprite2):
# collision_list.append(sprite2)
return collision_list


def get_sprites_at_point(point: Point,
Expand All @@ -1200,11 +1199,9 @@ def get_sprites_at_point(point: Point,
else:
sprite_list_to_check = sprite_list

collision_list = [sprite2
for sprite2 in sprite_list_to_check
if is_point_in_polygon(point[0], point[1], sprite2.get_adjusted_hit_box())]
return [s for s in sprite_list_to_check if
is_point_in_polygon(point[0], point[1], s.get_adjusted_hit_box())]

return collision_list

def get_sprites_at_exact_point(point: Point,
sprite_list: SpriteList) -> List[Sprite]:
Expand All @@ -1226,8 +1223,4 @@ def get_sprites_at_exact_point(point: Point,
else:
sprite_list_to_check = sprite_list

collision_list = [sprite2
for sprite2 in sprite_list_to_check
if point[0] == sprite2.center_x and point[1] == sprite2.center_y]

return collision_list
return [s for s in sprite_list_to_check if s.position == point]