Skip to content

Commit ce9d89e

Browse files
committed
Skeleton for extrapolated intersection
This problem is definitely difficult and common enough to warrant its own module, but it doesn't define any new classes. * docs/Geometry.rst - autodoc the new module * pygorithm/geometry/extrapolated_intersection.py - first skeleton * tests/test_geometry.py - skeleton tests for extrap. intr
1 parent da91053 commit ce9d89e

File tree

3 files changed

+286
-2
lines changed

3 files changed

+286
-2
lines changed

docs/Geometry.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ Features
5555
* Algorithms available:
5656
- Separating Axis Theorem (polygon2)
5757
- Broad-phase (rect2)
58+
- Extrapolated intersection (extrapolated_intersection)
5859

5960
Vector2
6061
-------
@@ -92,6 +93,10 @@ Axis-Aligned Rectangle
9293
:special-members:
9394
:private-members:
9495

95-
96+
Extrapolated Intersection
97+
-------------------------
98+
99+
.. automodule:: pygorithm.geometry.extrapolated_intersection
100+
:members:
96101

97102

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
"""
2+
Author: Timothy Moore
3+
Created On: 4th September 2017
4+
5+
Contains various approaches to determining if a polygon will
6+
intersect another polygon as one or both polygons go along
7+
a a single direction at a constant speed.
8+
9+
This problem could be thought of as one of extrapolation -
10+
given these initial conditions, extrapolate to determine
11+
if intersections will occur.
12+
13+
.. note::
14+
15+
Touching is not considered intersecting in this module. Touching
16+
is determined using `math.isclose`
17+
18+
"""
19+
20+
def calculate_one_moving_and_one_stationary(poly1, poly1_offset, poly1_velocity, poly2, poly2_offset):
21+
"""
22+
Determine if the moving polygon will intersect the stationary polygon.
23+
24+
This is the simplest question. Given two polygons, one moving and one not,
25+
determine if the two polygons will ever intersect (assuming they maintain
26+
constant velocity).
27+
28+
:param poly1: the geometry of the polygon that is moving
29+
:type poly1: :class:`pygorithm.geometry.polygon2.Polygon2`
30+
:param poly1_offset: the starting location of the moving polygon
31+
:type poly1_offset: :class:`pygorithm.geometry.vector2.Vector2`
32+
:param poly1_velocity: the velocity of the moving polygon
33+
:type poly1_velocity: :class:`pygorithm.geometry.vector2.Vector2`
34+
:param poly2: the geometry of the stationary polygon
35+
:type poly2: :class:`pygorithm.geometry.polygon2.Polygon2`
36+
:param poly2_offset: the offset of the stationary polygon
37+
:type poly2_offset: :class:`pygorithm.geometry.vector2.Vector2`
38+
:returns: if they will intersect
39+
:rtype: bool
40+
"""
41+
pass
42+
43+
def calculate_one_moving_one_stationary_distancelimit(poly1, poly1_offset, poly1_velocity, poly2, poly2_offset, max_distance):
44+
"""
45+
Determine if the moving polygon will intersect the stationary polygon
46+
within some distance.
47+
48+
This is a step up, and very similar to the actual problem many any-angle
49+
pathfinding algorithms run into. Given two polygons, 1 moving and 1
50+
stationary, determine if the first polygon will intersect the second
51+
polygon before moving a specified total distance.
52+
53+
:param poly1: the geometry of the polygon that is moving
54+
:type poly1: :class:`pygorithm.geometry.polygon2.Polygon2`
55+
:param poly1_offset: the starting location of the moving polygon
56+
:type poly1_offset: :class:`pygorithm.geometry.vector2.Vector2`
57+
:param poly1_velocity: the velocity of the moving polygon
58+
:type poly1_velocity: :class:`pygorithm.geometry.vector2.Vector2`
59+
:param poly2: the geometry of the stationary polygon
60+
:type poly2: :class:`pygorithm.geometry.polygon2.Polygon2`
61+
:param poly2_offset: the offset of the stationary polygon
62+
:type poly2_offset: :class:`pygorithm.geometry.vector2.Vector2`
63+
:param max_distance: the max distance that poly1 can go
64+
:type max_distance: :class:`numbers.Number`
65+
:returns: if they will intersect
66+
:rtype: bool
67+
"""
68+
pass
69+
70+
def calculate_one_moving_one_stationary_along_path(poly1, poly1_start, poly1_end, poly2, poly2_offset):
71+
"""
72+
Determine if the moving polygon will intersect the stationary polygon as
73+
it moves from the start to the end.
74+
75+
This is a rewording of :py:func:`.calculate_one_moving_one_stationary_distancelimit`
76+
that is more common. Given two polygons, 1 moving and 1 stationary, where the
77+
moving polygon is going at some speed from one point to another, determine if
78+
the two polygons will intersect.
79+
80+
:param poly1: the geometry of the polygon that is moving
81+
:type poly1: :class:`pygorithm.geometry.polygon2.Polygon2`
82+
:param poly1_start: where the moving polygon begins moving from
83+
:type poly1_start: :class:`pygorithm.geometry.vector2.Vector2`
84+
:param poly1_end: where the moving polygon stops moving
85+
:type poly1_end: :class:`pygorithm.geometry.vector2.Vector2`
86+
:param poly2: the geometry of the stationary polygon
87+
:type poly2: :class:`pygorithm.geometry.polygon2.Polygon2`
88+
:param poly2_offset: the location of the second polygon
89+
:type poly2_offset: :class:`pygorithm.geometry.vector2.Vector2`
90+
:returns: if they will intersect
91+
:rtype: bool
92+
"""
93+
pass
94+
95+
96+
def calculate_one_moving_many_stationary(poly1, poly1_offset, poly1_velocity, other_poly_offset_tuples):
97+
"""
98+
Determine if the moving polygon will intersect anything as it
99+
moves at a constant direction and speed forever.
100+
101+
This is the simplest arrangement of this problem with a collection
102+
of stationary polygons. Given many polygons of which 1 is moving,
103+
determine if the moving polygon intersects the other polygons now or at
104+
some point in the future if it moves at some constant direction and
105+
speed forever.
106+
107+
This does not verify the stationary polygons are not intersecting.
108+
109+
:param poly1: the geometry of the polygon that is moving
110+
:type poly1: :class:`pygorithm.geometry.polygon2.Polygon2`
111+
:param poly1_offset: the starting location of the moving polygon
112+
:type poly1_offset: :class:`pygorithm.geometry.vector2.Vector2`
113+
:param poly1_velocity: the velocity of the moving polygon
114+
:type poly1_velocity: :class:`pygorithm.geometry.vector2.Vector2`
115+
:param other_poly_offset_tuples: list of (polygon, offset) of the stationary polygons
116+
:type other_poly_offset_tuples: list of (:class:`pygorithm.geometry.polygon2.Polygon2`, :class:`pygorithm.geometry.vector2.Vector2`)
117+
:returns: if an intersection will occur
118+
:rtype: bool
119+
"""
120+
pass
121+
122+
def calculate_one_moving_many_stationary_distancelimit(poly1, poly1_offset, poly1_velocity, max_distance, other_poly_offset_tuples):
123+
"""
124+
Determine if the moving polygon will intersect anyything as
125+
it moves in a constant direction and speed for a certain
126+
distance.
127+
128+
This does not verify the stationary polygons are not intersecting.
129+
130+
:param poly1: the geometry of the polygon that is moving
131+
:type poly1: :class:`pygorithm.geometry.polygon2.Polygon2`
132+
:param poly1_offset: the starting location of the moving polygon
133+
:type poly1_offset: :class:`pygorithm.geometry.vector2.Vector2`
134+
:param poly1_velocity: the velocity of the moving polygon
135+
:type poly1_velocity: :class:`pygorithm.geometry.vector2.Vector2`
136+
:param max_distance: the max distance the polygon will go
137+
:type max_distance: :class:`numbers.Number`
138+
:param other_poly_offset_tuples: list of (polygon, offset) of the stationary polygons
139+
:type other_poly_offset_tuples: list of (:class:`pygorithm.geometry.polygon2.Polygon2`, :class:`pygorithm.geometry.vector2.Vector2`)
140+
:returns: if an intersection will occur
141+
:rtype: bool
142+
"""
143+
pass
144+
145+
def calculate_one_moving_many_stationary_along_path(poly1, poly1_start, poly1_end, other_poly_offset_tuples):
146+
"""
147+
Determine if a polygon that moves from one point to another
148+
will intersect anything.
149+
150+
This is the question that the Theta* family of pathfinding
151+
algorithms require. It is simply a rewording of
152+
:py:func:`.calculate_one_moving_many_stationary_distancelimit`
153+
154+
This does not verify the stationary polygons are not intersecting.
155+
156+
:param poly1: the geometry of the polygon that is moving
157+
:type poly1: :class:`pygorithm.geometry.polygon2.Polygon2`
158+
:param poly1_start: where the polygon begins moving from
159+
:type poly1_start: :class:`pygorithm.geometry.vector2.Vector2`
160+
:param poly1_end: where the polygon stops moving at
161+
:type poly1_end: :class:`pygorithm.geometry.vector2.Vector2`
162+
:param other_poly_offset_tuples: list of (polygon, offset) of the stationary polygons
163+
:type other_poly_offset_tuples: list of (:class:`pygorithm.geometry.polygon2.Polygon2`, :class:`pygorithm.geometry.vector2.Vector2`)
164+
:returns: if an intersection will occur
165+
:rtype: bool
166+
"""
167+
168+
def calculate_two_moving(poly1, poly1_offset, poly1_vel, poly2, poly2_offset, poly2_vel):
169+
"""
170+
Determine if two moving polygons will intersect at some point.
171+
172+
This is the simplest question when there are multiple moving polygons.
173+
Given two polygons moving at a constant velocity and direction forever,
174+
determine if an intersection will occur.
175+
176+
It should be possible for the reader to extrapolate from this function
177+
and the process for stationary polygons to create similar functions to
178+
above where all or some polygons are moving.
179+
180+
:param poly1: the first polygon
181+
:type poly1: :class:`pygorithm.geometry.polygon2.Polygon2`
182+
:param poly1_offset: where the first polygon starts at
183+
:type poly1_offset: :class:`pygorithm.geometry.vector2.Vector2`
184+
:param poly1_vel: the velocity of the first polygon
185+
:type poly1_vel: :class:`pygorithm.geometry.vector2.Vector2`
186+
:param poly2: the second polygon
187+
:type poly2: :class:`pygorithm.geometry.polygon2.Polygon2`
188+
:param poly2_offset: where the second polygon starts at
189+
:type poly2_offset: :class:`pygorithm.geometry.vector2.Vector2`
190+
:param poly2_vel: the velocity of the second polygon
191+
:type poly2_vel: :class:`pygorithm.geometry.vector2.Vector2`
192+
:returns: if an intersectino will occur
193+
:rtype: bool
194+
"""
195+
pass

tests/test_geometry.py

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1423,6 +1423,90 @@ def test_str(self):
14231423

14241424
self.assertEqual("rect(1x1 at <3, 4>)", str(unit_square))
14251425
self.assertEqual("rect(0.707x0.708 at <0.568, 0.877>)", str(ugly_rect))
1426-
1426+
1427+
class TestExtrapolatedIntersection(unittest.TestCase):
1428+
def test_one_moving_one_stationary_no_intr(self):
1429+
pass
1430+
def test_one_moving_one_stationary_touching(self):
1431+
pass
1432+
def test_one_moving_one_stationary_intr_at_start(self):
1433+
pass
1434+
def test_one_moving_one_stationary_intr_later(self):
1435+
pass
1436+
1437+
def test_one_moving_one_stationary_distlimit_no_intr(self):
1438+
pass
1439+
def test_one_moving_one_stationary_distlimit_touching(self):
1440+
pass
1441+
def test_one_moving_one_stationary_distlimit_intr_at_start(self):
1442+
pass
1443+
def test_one_moving_one_stationary_distlimit_intr_later(self):
1444+
pass
1445+
def test_one_moving_one_stationary_distlimit_touch_at_limit(self):
1446+
pass
1447+
def test_one_moving_one_stationary_distlimit_intr_after_limit(self):
1448+
1449+
def test_one_moving_one_stationary_along_path_no_intr(self):
1450+
pass
1451+
def test_one_moving_one_stationary_along_path_touching(self):
1452+
pass
1453+
def test_one_moving_one_stationary_along_path_intr_at_start(self):
1454+
pass
1455+
def test_one_moving_one_stationary_along_path_intr_later(self):
1456+
pass
1457+
def test_one_moving_one_stationary_distlimit_touch_at_end(self):
1458+
pass
1459+
def test_one_moving_one_stationary_distlimit_intr_after_end(self):
1460+
1461+
def test_one_moving_many_stationary_no_intr(self):
1462+
pass
1463+
def test_one_moving_many_stationary_touching(self):
1464+
pass
1465+
def test_one_moving_many_stationary_intr_at_start(self):
1466+
pass
1467+
def test_one_moving_many_stationary_intr_later(self):
1468+
pass
1469+
1470+
def test_one_moving_many_stationary_distlimit_no_intr(self):
1471+
pass
1472+
def test_one_moving_many_stationary_distlimit_touching(self):
1473+
pass
1474+
def test_one_moving_many_stationary_distlimit_intr_at_start(self):
1475+
pass
1476+
def test_one_moving_many_stationary_distlimit_intr_later(self):
1477+
pass
1478+
def test_one_moving_many_stationary_distlimit_touch_at_limit(self):
1479+
pass
1480+
def test_one_moving_many_stationary_distlimit_intr_after_limit(self):
1481+
pass
1482+
1483+
def test_one_moving_many_stationary_along_path_no_intr(self):
1484+
pass
1485+
def test_one_moving_many_stationary_along_path_touching(self):
1486+
pass
1487+
def test_one_moving_many_stationary_along_path_intr_at_start(self):
1488+
pass
1489+
def test_one_moving_many_stationary_along_path_intr_later(self):
1490+
pass
1491+
def test_one_moving_many_stationary_along_path_touch_at_limit(self):
1492+
pass
1493+
def test_one_moving_many_stationary_along_path_intr_after_limit(self):
1494+
pass
1495+
1496+
def test_two_moving_no_intr(self):
1497+
pass
1498+
def test_two_moving_touching_miss(self):
1499+
pass
1500+
def test_two_moving_touching_miss_diff_vel(self):
1501+
pass
1502+
def test_two_moving_intr_ones_start_but_later(self):
1503+
pass
1504+
def test_two_moving_intr_at_start(self):
1505+
pass
1506+
def test_two_moving_intr_later(self):
1507+
pass
1508+
def test_two_moving_intr_later_diff_vel(self):
1509+
pass
1510+
14271511
if __name__ == '__main__':
14281512
unittest.main()

0 commit comments

Comments
 (0)