11
11
https://en.wikipedia.org/wiki/Axis-aligned_object
12
12
"""
13
13
14
+ import math
15
+
14
16
class AxisAlignedLine (object ):
15
17
"""
16
18
Define an axis aligned line.
@@ -50,32 +52,54 @@ def __init__(self, axis, point1, point2):
50
52
"""
51
53
Construct an axis aligned line with the appropriate min and max.
52
54
53
- :param axis: axis this line is on
55
+ :param axis: axis this line is on (for bookkeeping only, may be None)
54
56
:type axis: :class:`pygorithm.geometry.vector2.Vector2`
55
57
:param point1: one point on this line
56
58
:type point1: :class:`numbers.Number`
57
59
:param point2: a different point on this line
58
60
:type point2: :class:`numbers.Number`
59
61
"""
60
62
61
- pass
63
+ self .axis = axis
64
+ self .min = min (point1 , point2 )
65
+ self .max = max (point1 , point2 )
66
+
67
+ @staticmethod
68
+ def _approx (a , b ):
69
+ """
70
+ Same as math.isclose but supports python < 3.5
71
+
72
+ :param a: first numeric
73
+ :type a: :class:`numbers.Number`
74
+ :param b: second numeric
75
+ :type b: :class:`numbers.Number`
76
+ :returns: if the are close
77
+ :rtype: bool
78
+ """
79
+
80
+ if hasattr (math , 'isclose' ):
81
+ return math .isclose (a , b )
82
+ return abs (a - b ) <= 1e-09 * max (abs (a ), abs (b ))
62
83
63
84
@staticmethod
64
85
def intersects (line1 , line2 ):
65
86
"""
66
87
Determine if the two lines intersect
67
88
68
- Determine if the two lines are touching and if they are, if
69
- they are overlapping. Lines are touching if they share only
70
- one end point, whereas they are overlapping if they share
71
- infinitely many points.
89
+ Determine if the two lines are touching, if they are overlapping, or if
90
+ they are disjoint. Lines are touching if they share only one end point,
91
+ whereas they are overlapping if they share infinitely many points.
72
92
73
93
.. note::
74
94
75
95
It is rarely faster to check intersection before finding intersection if
76
96
you will need the minimum translation vector, since they do mostly
77
97
the same operations.
78
98
99
+ .. tip::
100
+
101
+ This will never return ``True, True``
102
+
79
103
:param line1: the first line
80
104
:type line1: :class:`pygorithm.geometry.axisall.AxisAlignedLine`
81
105
:param line2: the second line
@@ -84,7 +108,16 @@ def intersects(line1, line2):
84
108
:rtype: (bool, bool)
85
109
"""
86
110
87
- pass
111
+ if AxisAlignedLine ._approx (line1 .max , line2 .min ):
112
+ return True , False
113
+ elif AxisAlignedLine ._approx (line1 .min , line2 .max ):
114
+ return True , False
115
+ elif line1 .max < line2 .min :
116
+ return False , False
117
+ elif line1 .min > line2 .max :
118
+ return False , False
119
+
120
+ return False , True
88
121
89
122
@staticmethod
90
123
def find_intersection (line1 , line2 ):
@@ -97,22 +130,39 @@ def find_intersection(line1, line2):
97
130
direction of the axis by the magnitude of the result.
98
131
99
132
100
- Returns `true, None` if the lines are touching.
133
+ Returns `true, (None, touch_point_numeric, touch_point_numeric)` if the lines are touching
134
+ and not overlapping.
101
135
102
136
.. note::
103
137
104
- Ensure your program correctly handles `true, None`
138
+ Ensure your program correctly handles `true, ( None, numeric, numeric) `
105
139
106
140
107
141
:param line1: the first line
108
142
:type line1: :class:`pygorithm.geometry.axisall.AxisAlignedLine`
109
143
:param line2: the second line
110
144
:type line2: :class:`pygorithm.geometry.axisall.AxisAlignedLine`
111
- :returns: (touching, mtv against 1)
112
- :rtype: (bool, :class:`numbers.Number` or None)
145
+ :returns: (touching, ( mtv against 1, intersection min, intersection max) )
146
+ :rtype: (bool, ( :class:`numbers.Number` or None, :class:`numbers.Number`, :class:`numbers.Number`) or None)
113
147
"""
114
148
115
- pass
149
+ if AxisAlignedLine ._approx (line1 .max , line2 .min ):
150
+ return True , (None , line2 .min , line2 .min )
151
+ elif AxisAlignedLine ._approx (line1 .min , line2 .max ):
152
+ return True , (None , line1 .min , line1 .min )
153
+ elif line1 .max < line2 .min or line2 .max < line1 .min :
154
+ return False , None
155
+ else :
156
+ opt_1 = line2 .min - line1 .max
157
+ opt_2 = line2 .max - line1 .min
158
+
159
+ res_min = max (line1 .min , line2 .min )
160
+ res_max = min (line1 .max , line2 .max )
161
+
162
+ if abs (opt_1 ) < abs (opt_2 ):
163
+ return True , (opt_1 , res_min , res_max )
164
+ else :
165
+ return True , (opt_2 , res_min , res_max )
116
166
117
167
@staticmethod
118
168
def contains_point (line , point ):
@@ -132,4 +182,10 @@ def contains_point(line, point):
132
182
:returns: (if the point is an edge of the line, if the point is contained by the line)
133
183
:rtype: (bool, bool)
134
184
"""
135
- pass
185
+
186
+ if AxisAlignedLine ._approx (line .min , point ) or AxisAlignedLine ._approx (line .max , point ):
187
+ return True , False
188
+ elif point < line .min or point > line .max :
189
+ return False , False
190
+ else :
191
+ return False , True
0 commit comments