Skip to content

Commit 1bb2269

Browse files
committed
Begin work on quadtree
Quadtrees need a solid rectangle class in order to work, so doing that first. * docs/Geometry.rst - Add Rectangle references + pygorithm/data_structures/quadtree.py - incomplete skeleton * pygorithm/geometry/polygon2.py - minor documentation fix + pygorithm/geometry/rect2.py - fairly complete skeleton * tests/test_geometry.py - skeleton tests for rect2
1 parent 74a8081 commit 1bb2269

File tree

5 files changed

+356
-5
lines changed

5 files changed

+356
-5
lines changed

docs/Geometry.rst

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,11 @@ Features
5050

5151
* Shapes available:
5252
- Concave Polygons (polygon2)
53+
- Rectangles (rect2)
5354

5455
* Algorithms available:
5556
- Separating Axis Theorem (polygon2)
57+
- Broad-phase (rect2)
5658

5759
Vector2
5860
-------
@@ -82,9 +84,12 @@ Concave Polygon
8284
:members:
8385
:special-members:
8486

85-
86-
87+
Axis-Aligned Rectangle
88+
----------------------
8789

90+
.. autoclass:: pygorithm.geometry.rect2.Rect2
91+
:members:
92+
:special-members:
8893

8994

9095

pygorithm/data_structures/quadtree.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""
2+
Author: Timothy Moore
3+
Created On: 31th August 2017
4+
5+
Defines a two-dimensional quadtree of arbitrary
6+
depth and bucket size.
7+
"""
8+
import inspect
9+
10+
from pygorithm.geometry import (vector2, polygon2, rect2)
11+
12+
class QuadTree(object):
13+
"""
14+
A quadtree is a sorting tool for two-dimensional space, most
15+
commonly used to reduce the number of required collision
16+
calculations in a two-dimensional scene. In this context,
17+
the scene is stepped without collision detection, then a
18+
quadtree is constructed from all of the boundaries
19+
"""
20+
@staticmethod
21+
def get_code():
22+
"""
23+
Get the code for the QuadTree class
24+
25+
:returns: code for QuadTree
26+
:rtype: string
27+
"""
28+
return inspect.getsource(QuadTree)

pygorithm/geometry/polygon2.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,8 +407,8 @@ def contains_point(polygon, offset, point):
407407
:type offset: :class:`pygorithm.geometry.vector2.Vector2` or None
408408
:param point: the point to check
409409
:type point: :class:`pygorithm.geometry.vector2.Vector2`
410-
:returns: (on edge, contained)
411-
:rtype: (bool, bool)
410+
:returns: on edge, contained
411+
:rtype: bool, bool
412412
"""
413413

414414
_previous = polygon.points[0]

pygorithm/geometry/rect2.py

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
"""
2+
Author: Timothy Moore
3+
Created On: 31th August 2017
4+
5+
Defines a 2-dimensional axis-aligned rectangle.
6+
This rectangle does not act as a polygon, but
7+
there are similar collision methods that accept
8+
polygons.
9+
10+
Unlike Polygon2s, Rect2s are very fast to construct.
11+
"""
12+
13+
import math
14+
15+
from pygorithm.geometry import (vector2, line2, axisall, polygon2)
16+
17+
def Rect2(object):
18+
"""
19+
A rectangle. Uses SAT collision against polygons and
20+
broad-phase collision against other rectangles.
21+
22+
Rectangles are fast to construct and have very fast
23+
rectangle-rectangle collision detection.
24+
25+
Rect2 is designed to have almost exactly the opposite performance
26+
characteristics as Polygon2 when doing collision against
27+
Polygon2s: Fast to construct and complex on first call with
28+
many operations incurring expensive recalculations.
29+
30+
.. caution::
31+
32+
Collision detection against a rectangle with cause
33+
initialization of the polygon representation of a
34+
rectangle. This has the noticeable performance
35+
characteristics that are seen whenever a polygon
36+
is constructed (see :py:class:~`pygorithm.geometry.polygon2.Polygon2`).
37+
This operation recurrs only if width and height
38+
were modified.
39+
40+
:ivar mincorner: the position of this polygon
41+
:vartype mincorner: :class:`pygorithm.geometry.vector2.Vector2`
42+
"""
43+
44+
def __init__(self, width, height, mincorner=None):
45+
"""
46+
Create a new rectangle of width and height.
47+
48+
If mincorner is None, the origin is assumed.
49+
50+
:param width: width of this rect
51+
:type width: :class:`numbers.Number`
52+
:param height: height of this rect
53+
:type height: :class:`numbers.Number`
54+
:param mincorner: the position of this rect
55+
:type mincorner: :class:`pygorithm.geometry.vector2.Vector2` or None
56+
"""
57+
pass
58+
59+
@property
60+
def polygon(self):
61+
"""
62+
Get the polygon representation of this rectangle, without
63+
the corners. Lazily initialized and up-to-date with width
64+
and height.
65+
66+
.. caution::
67+
68+
This does not include the mincorner (which should be passed as
69+
offset)
70+
71+
:returns: polygon representation of this rectangle
72+
:rtype: :class:`pygorithm.geometry.polygon2.Polygon2`
73+
"""
74+
pass
75+
76+
@property
77+
def width(self):
78+
"""
79+
Get or set the width of this rect.
80+
81+
.. caution::
82+
83+
Setting the width of the rectangle will remove the polygon
84+
caching required for rectangle-polygon collision.
85+
86+
:returns: width of this rect
87+
:rtype: :class:`numbers.Number`
88+
"""
89+
pass
90+
91+
@property.setter
92+
def width(self, value):
93+
pass
94+
95+
@property
96+
def height(self):
97+
"""
98+
Get or set the height of this rect
99+
100+
.. caution::
101+
102+
Setting the height of the rectangle will remove the cached
103+
operations required for rectangle-polygon collision.
104+
105+
:returns: height of this rect
106+
:rtype: :class:`numbers.Number`
107+
"""
108+
pass
109+
110+
@property.setter
111+
def height(self, value):
112+
pass
113+
114+
@property
115+
def area(self):
116+
"""
117+
Get the area of this rect
118+
119+
:returns: area of this rect
120+
:rtype: :class:`numbers.Number`
121+
"""
122+
pass
123+
124+
@staticmethod
125+
def project_onto_axis(rect, axis):
126+
"""
127+
Project the rect onto the specified axis.
128+
129+
.. tip::
130+
131+
This function is extremely fast for vertical or
132+
horizontal axises.
133+
134+
:param rect: the rect to project
135+
:type rect: :class:`pygorithm.geometry.rect2.Rect2`
136+
:param axis: the axis to project onto
137+
:type axis: :class:`pygorithm.geometry.vector2.Vector2`
138+
:returns: the projection of the rect along axis
139+
:rtype: :class:`pygorithm.geometry.axisall.AxisAlignedLine`
140+
"""
141+
pass
142+
143+
@staticmethod
144+
def contains_point(rect, point):
145+
"""
146+
Determine if the rect contains the point
147+
148+
Distinguish between points that are on the edge of the
149+
rect and those that are not.
150+
151+
.. tip::
152+
153+
This will never return True, True
154+
155+
:param rect: the rect
156+
:type rect: :class:`pygorithm.geometry.rect2.Rect2`
157+
:param point: the point
158+
:type point: :class:`pygorithm.geometry.vector2.Vector2`
159+
:returns: point on edge, point inside
160+
:rtype: bool, bool
161+
"""
162+
pass
163+
164+
@staticmethod
165+
def find_intersection(*args, find_mtv=True):
166+
"""
167+
Determine the state of intersection between a rect and a
168+
polygon.
169+
170+
For Rect-Polygon intersection:
171+
172+
Must be passed in 3 arguments - a :py:class:~`pygorithm.geometry.rect2.Rect2`,
173+
a :py:class:~`pygorithm.geometry.polygon2.Polygon2`, and a
174+
:py:class:~`pygorithm.geometry.vector2.Vector2`. The vector must come immediately
175+
after the polygon, but the rect can be either the first or last unnamed argument.
176+
If it is the first argument, the mtv is against the rectangle. If it is the last
177+
argument, the mtv is against the polygon.
178+
179+
180+
For Rect-Rect intersection:
181+
182+
Must be passed in 2 ar
183+
Examples:
184+
185+
.. code-block:: python
186+
187+
from pygorithm.geometry import (vector2, polygon2, rect2)
188+
189+
octogon = polygon2.Polygon2.from_regular(8, 1)
190+
oct_offset = vector2.Vector2(0.5, 0)
191+
192+
unit_square = rect2.Rect2(1, 1)
193+
194+
# find mtv for square against octogon
195+
touching, overlapping, mtv = rect2.Rect2.find_intersection(unit_square, octogon, oct_offset)
196+
197+
# find mtv for octogon against square
198+
touching, overlapping, mtv = rect2.Rect2.find_intersection(octogon, oct_offset, unit_square)
199+
200+
# find intersection but skip mtv (two options)
201+
touching, overlapping, alwaysNone = rect2.Rect2.find_intersection(unit_square, octogon, oct_offset, find_mtv=False)
202+
touching, overlapping, alwaysNone = rect2.Rect2.find_intersection(octogon, oct_offset, unit_square, find_mtv=False)
203+
204+
big_square = rect2.Rect2(2, 2, vector2.Vector2(-1.5, 0))
205+
206+
# find mtv for square against big square
207+
touching, overlapping, mtv = rect2.Rect2.find_intersection(unit_square, big_square)
208+
209+
# find mtv for big square against square
210+
touching, overlapping, mtv = rect2.Rect2.find_intersection(big_square, unit_square)
211+
212+
:param args: 2 arguments for rect-rect, 3 arguments for rect-polygon (see above)
213+
:type args: list
214+
:param find_mtv: if mtv should be found where possible (default ``True``)
215+
:type find_mtv: bool
216+
:returns: (touching, overlapping, (mtv distance, mtv axis))
217+
:rtype: (bool, bool, (:class:`numbers.Number`, :class:`pygorithm.geometry.vector2.Vector2`) or None)
218+
"""
219+
pass
220+
221+
def __repr__(self):
222+
"""
223+
Create an unambiguous representation of this rectangle.
224+
225+
Example:
226+
227+
.. code-block:: python
228+
229+
from pygorithm.geometry import (vector2, rect2)
230+
231+
unit_square = rect2.Rect2(1, 1, vector2.Vector2(3, 4))
232+
233+
# prints rect2(width=1, height=1, mincorner=vector2(x=3, y=4))
234+
print(repr(unit_square))
235+
236+
:returns: unambiguous representation of this rectangle
237+
:rtype: string
238+
"""
239+
pass
240+
241+
def __str__(self):
242+
"""
243+
Create a human readable representation of this rectangle
244+
245+
Example:
246+
247+
.. code-block:: python
248+
249+
from pygorithm.geometry import (vector2, rect2)
250+
251+
unit_square = rect2.Rect2(1, 1, vector2.Vector2(3, 4))
252+
ugly_Rect = rect2.Rect2(0.7071234, 0.7079876, vector2.Vector2(0.56789123, 0.876543))
253+
254+
# prints rect(1x1 at <3, 4>)
255+
print(str(unit_square))
256+
257+
# prints rect(0.707x0.708 at <0.568, 0.877>)
258+
"""
259+
pass

0 commit comments

Comments
 (0)