1
1
import unittest
2
2
import math
3
+ import random
3
4
4
5
from pygorithm .geometry import (
5
6
rect_broad_phase ,
@@ -213,6 +214,193 @@ def test_magnitude(self):
213
214
magn = vec1 .magnitude ()
214
215
self .assertEqual (5 , magn )
215
216
217
+ class TestLine2 (unittest .TestCase ):
218
+ def setUp (self ):
219
+ random .seed ()
220
+
221
+ self .vec_origin = vector2 .Vector2 (0 , 0 )
222
+ self .vec_1_1 = vector2 .Vector2 (1 , 1 )
223
+ self .vec_2_1 = vector2 .Vector2 (2 , 1 )
224
+ self .vec_1_2 = vector2 .Vector2 (1 , 2 )
225
+ self .vec_3_4 = vector2 .Vector2 (3 , 4 )
226
+ self .vec_neg_1_neg_1 = vector2 .Vector2 (- 1 , - 1 )
227
+
228
+ self .line_origin_1_1 = line2 .Line2 (self .vec_origin , self .vec_1_1 )
229
+ self .line_1_1_3_4 = line2 .Line2 (self .vec_1_1 , self .vec_3_4 )
230
+ self .line_1_1_2_1 = line2 .Line2 (self .vec_1_1 , self .vec_2_1 )
231
+ self .line_1_1_1_2 = line2 .Line2 (self .vec_1_1 , self .vec_1_2 )
232
+
233
+ def test_constructor (self ):
234
+ _line = self .line_origin_1_1
235
+
236
+ self .assertIsNotNone (_line .start )
237
+ self .assertIsNotNone (_line .end )
238
+
239
+ self .assertEqual (0 , _line .start .x )
240
+ self .assertEqual (0 , _line .start .y )
241
+ self .assertEqual (1 , _line .end .x )
242
+ self .assertEqual (1 , _line .end .y )
243
+
244
+ with self .assertRaises (ValueError ):
245
+ _line2 = line2 .Line2 (self .vec_origin , self .vec_origin )
246
+
247
+ def test_delta (self ):
248
+ self .assertEqual (1 , self .line_origin_1_1 .delta .x )
249
+ self .assertEqual (1 , self .line_origin_1_1 .delta .y )
250
+ self .assertEqual (2 , self .line_1_1_3_4 .delta .x )
251
+ self .assertEqual (3 , self .line_1_1_3_4 .delta .y )
252
+
253
+ def test_axis (self ):
254
+ self .assertAlmostEqual (0.70710678118 , self .line_origin_1_1 .axis .x )
255
+ self .assertAlmostEqual (0.70710678118 , self .line_origin_1_1 .axis .y )
256
+ self .assertAlmostEqual (0.55470019622 , self .line_1_1_3_4 .axis .x )
257
+ self .assertAlmostEqual (0.83205029433 , self .line_1_1_3_4 .axis .y )
258
+ self .assertEqual (1 , self .line_1_1_2_1 .axis .x )
259
+ self .assertEqual (0 , self .line_1_1_2_1 .axis .y )
260
+ self .assertEqual (0 , self .line_1_1_1_2 .axis .x )
261
+ self .assertEqual (1 , self .line_1_1_1_2 .axis .y )
262
+
263
+ def test_normal (self ):
264
+ self .assertAlmostEqual (- 0.70710678118 , self .line_origin_1_1 .normal .x )
265
+ self .assertAlmostEqual (0.70710678118 , self .line_origin_1_1 .normal .y )
266
+ self .assertAlmostEqual (- 0.83205029433 , self .line_1_1_3_4 .normal .x )
267
+ self .assertAlmostEqual (0.55470019622 , self .line_1_1_3_4 .normal .y )
268
+ self .assertEqual (0 , self .line_1_1_2_1 .normal .x )
269
+ self .assertEqual (1 , self .line_1_1_2_1 .normal .y )
270
+ self .assertEqual (- 1 , self .line_1_1_1_2 .normal .x )
271
+ self .assertEqual (0 , self .line_1_1_1_2 .normal .y )
272
+
273
+ def test_magnitude_squared (self ):
274
+ self .assertAlmostEqual (2 , self .line_origin_1_1 .magnitude_squared )
275
+ self .assertAlmostEqual (13 , self .line_1_1_3_4 .magnitude_squared )
276
+ self .assertEqual (1 , self .line_1_1_2_1 .magnitude_squared )
277
+ self .assertEqual (1 , self .line_1_1_1_2 .magnitude_squared )
278
+
279
+ def test_magnitude (self ):
280
+ self .assertAlmostEqual (1.41421356237 , self .line_origin_1_1 .magnitude )
281
+ self .assertAlmostEqual (3.60555127546 , self .line_1_1_3_4 .magnitude )
282
+ self .assertEqual (1 , self .line_1_1_2_1 .magnitude )
283
+ self .assertEqual (1 , self .line_1_1_1_2 .magnitude )
284
+
285
+ def test_line_boundaries_x (self ): # min_x, min_y, max_x, max_y
286
+ _line = line2 .Line2 (vector2 .Vector2 (- 2 , 3 ), vector2 .Vector2 (1 , - 1 ))
287
+ self .assertEqual (- 2 , _line .min_x )
288
+ self .assertEqual (1 , _line .max_x )
289
+ self .assertEqual (- 1 , _line .min_y )
290
+ self .assertEqual (3 , _line .max_y )
291
+
292
+ def test_slope (self ):
293
+ self .assertEqual (1 , self .line_origin_1_1 .slope )
294
+ self .assertAlmostEqual (1.5 , self .line_1_1_3_4 .slope )
295
+ self .assertEqual (0 , self .line_1_1_1_2 .slope )
296
+ self .assertEqual (float ('+inf' ), self .line_1_1_2_1 .slope )
297
+
298
+ def test_y_intercept (self ):
299
+ self .assertEqual (0 , self .line_origin_1_1 .y_intercept )
300
+ self .assertAlmostEqual (- 0.5 , self .line_1_1_3_4 .y_intercept )
301
+ self .assertTrue (math .isnan (self .line_1_1_1_2 .y_intercept ))
302
+ self .assertEqul (1 , self .line_1_1_2_1 .y_intercept )
303
+
304
+ def test_horizontal (self ):
305
+ self .assertFalse (self .line_origin_1_1 .horizontal )
306
+ self .assertFalse (self .line_1_1_3_4 .horizontal )
307
+ self .assertFalse (self .line_1_1_1_2 .horizontal )
308
+ self .assertTrue (self .line_1_1_2_1 .horizontal )
309
+
310
+ def test_vertical (self ):
311
+ self .assertFalse (self .line_origin_1_1 .vertical )
312
+ self .assertFalse (self .line_1_1_3_4 .vertical )
313
+ self .assertTrue (self .line_1_1_1_2 .vertical )
314
+ self .assertFalse (self .line_1_1_2_1 .vertical )
315
+
316
+ def test_repr (self ):
317
+ self .assertEqual ('line2(start=vector2(x=1, y=1), end=vector2(x=3, y=4))' , repr (self .line_1_1_3_4 ))
318
+
319
+ def test_str (self ):
320
+ self .assertEqual ('<1, 1> -> <3, 4>' , str (self .line_1_1_3_4 ))
321
+
322
+ def test_calculate_y_intercept (self ):
323
+ self .assertAlmostEqual (0.66666666667 , self .line_1_1_3_4 .calculate_y_intercept (self .vec_1_1 ))
324
+
325
+ def test_are_parallel (self ):
326
+ self .assertFalse (line2 .Line2 .are_parallel (self .line_origin_1_1 , self .line_1_1_3_4 ))
327
+
328
+ _line = line2 .Line2 (vector2 .Vector2 (5 , 4 ), vector2 .Vector2 (3 , 1 ))
329
+ self .assertTrue (line2 .Line2 .are_parallel (self .line_1_1_3_4 , _line ))
330
+
331
+ @staticmethod
332
+ def _find_intr_fuzzer (v1 , v2 , v3 , v4 , exp_touching , exp_overlap , exp_intr , number_fuzzes = 3 ):
333
+ for i in range (number_fuzzes ):
334
+ offset1 = vector2 .Vector2 (random .randrange (- 1000 , 1000 , 0.01 ), random .randrange (- 1000 , 1000 , 0.01 ))
335
+ offset2 = vector2 .Vector2 (random .randrange (- 1000 , 1000 , 0.01 ), random .randrange (- 1000 , 1000 , 0.01 ))
336
+
337
+ _line1 = line2 .Line2 (v1 - offset1 , v2 - offset1 )
338
+ _line2 = line2 .Line2 (v3 - offset2 , v4 - offset2 )
339
+
340
+ help_msg = 'v1={}, v2={}, offset1={}\n _line1={}\n v3={}, v4={}, offset2={}\n _line2={}' .format (repr (v1 ), \
341
+ repr (v2 ), repr (offset1 ), repr (_line1 ), repr (v3 ), repr (v4 ), repr (offset2 ), repr (_line2 ))
342
+
343
+ touching , overlap , intr = line2 .Line2 .find_intersection (_line1 , _line2 , offset1 , offset2 )
344
+ self .assertEqual (exp_touching , touching , help_msg )
345
+ self .assertEqual (exp_overlap , overlap , help_msg )
346
+
347
+ if exp_intr is None :
348
+ self .assertIsNone (intr , help_msg )
349
+ else :
350
+ self .assertIsNotNone (intr , help_msg )
351
+
352
+ if isinstance (exp_intr , vector2 .Vector2 ):
353
+ self .assertIsInstance (intr , vector2 .Vector2 , help_msg )
354
+
355
+ self .assertAlmostEqual (exp_intr .x , intr .x )
356
+ self .assertAlmostEqual (exp_intr .y , intr .y )
357
+ else :
358
+ self .assertIsInstance (exp_intr , line2 .Line2 , help_msg )
359
+ self .assertIsInstance (intr , line2 .Line2 , help_msg )
360
+
361
+ self .assertAlmostEqual (exp_intr .start .x , intr .start .x )
362
+ self .assertAlmostEqual (exp_intr .start .y , intr .start .y )
363
+ self .assertAlmostEqual (exp_intr .end .x , intr .end .x )
364
+ self .assertAlmostEqual (exp_intr .end .y , itnr .end .y )
365
+
366
+
367
+ def test_find_intersection_non_parallel_no_intersection (self ):
368
+ self ._find_intr_fuzzer (vector2 .Vector2 (3 , 4 ), vector2 .Vector2 (5 , 6 ),
369
+ vector2 .Vector2 (5 , 4 ), vector2 .Vector2 (7 , 3 ),
370
+ False , False , None )
371
+
372
+ def test_find_intersection_parallel_no_intersection (self ):
373
+ self ._find_intr_fuzzer (vector2 .Vector2 (1 , 1 ), vector2 .Vector2 (3 , 3 ),
374
+ vector2 .Vector2 (2 , 1 ), vector2 .Vector2 (4 , 3 ),
375
+ False , False , None )
376
+
377
+ def test_find_intersection_non_parallel_intersect_at_edge (self ):
378
+ self ._find_intr_fuzzer (vector2 .Vector2 (3 , 4 ), vector2 .Vector2 (5 , 6 ),
379
+ vector2 .Vector2 (1 , 6 ), vector2 .Vector2 (5 , 2 ),
380
+ True , False , vector2 .Vector2 (3 , 4 ))
381
+
382
+ def test_find_intersection_non_parallel_intersect_not_edge (self ):
383
+ self ._find_intr_fuzzer (vector2 .Vector2 (3 , 4 ), vector2 .Vector2 (5 , 6 ),
384
+ vector2 .Vector2 (3.5 , 7 ), vector2 .Vector2 (4.5 , 4 ),
385
+ False , True , vector2 .Vector2 (4.125 , 5.125 ))
386
+
387
+ def test_find_intersection_parallel_intersect_at_edge (self ):
388
+ self ._find_intr_fuzzer (vector2 .Vector2 (3 , 4 ), vector2 .Vector2 (5 , 6 ),
389
+ vector2 .Vector2 (5 , 6 ), vector2 .Vector2 (7 , 8 ),
390
+ True , False , vector2 .Vector2 (5 , 6 ))
391
+
392
+ def test_find_intersection_parallel_intersect_overlap (self ):
393
+ self ._find_intr_fuzzer (vector2 .Vector2 (3 , 4 ), vector2 .Vector2 (5 , 6 ),
394
+ vector2 .Vector2 (4 , 5 ), vector2 .Vector2 (7 , 8 ),
395
+ False , True , line2 .Line2 (vector2 .Vector2 (4 , 5 ), vector2 .Vector2 (5 , 6 )))
396
+
397
+ def test_find_intersection_parallel_overlap_compeletely (self ):
398
+ self ._find_intr_fuzzer (vector2 .Vector2 (3 , 4 ), vector2 .Vector2 (5 , 6 ),
399
+ vector2 .Vector2 (2 , 3 ), vector2 .Vector2 (7 , 8 ),
400
+ False , True , line2 .Line2 (vector2 .Vector2 (3 , 4 ), vector2 .Vector2 (5 , 6 )))
401
+
402
+
403
+
216
404
217
405
if __name__ == '__main__' :
218
406
unittest .main ()
0 commit comments