source: trunk/anuga_core/source/anuga/geometry/test_polygon.py @ 7858

Last change on this file since 7858 was 7858, checked in by hudson, 13 years ago

Refactorings to increase code quality, fixed missing log import from sww_interrogate.

File size: 67.4 KB
Line 
1#!/usr/bin/env python
2
3import unittest
4import numpy as num
5from math import sqrt, pi
6from anuga.utilities.numerical_tools import ensure_numeric
7from anuga.utilities.system_tools import get_pathname_from_package
8
9from polygon import *
10from polygon import _poly_xy
11from polygon_function import Polygon_function
12from anuga.coordinate_transforms.geo_reference import Geo_reference
13from anuga.geospatial_data.geospatial_data import Geospatial_data
14
15
16def test_function(x, y):
17    return x+y
18
19
20class Test_Polygon(unittest.TestCase):
21    def setUp(self):
22        pass
23
24    def tearDown(self):
25        pass
26
27    def test_that_C_extension_compiles(self):
28        FN = 'polygon_ext.c'
29        try:
30            import polygon_ext
31        except:
32            from compile import compile
33
34            try:
35                compile(FN)
36            except:
37                raise Exception, 'Could not compile %s' %FN
38            else:
39                import polygon_ext
40
41    # Polygon stuff
42    def test_polygon_function_constants(self):
43        p1 = [[0,0], [10,0], [10,10], [0,10]]
44        p2 = [[0,0], [10,10], [15,5], [20, 10], [25,0], [30,10], [40,-10]]
45
46        f = Polygon_function([(p1, 1.0)])
47        z = f([5, 5, 27, 35], [5, 9, 8, -5])    # Two first inside p1
48        assert num.allclose(z, [1, 1, 0, 0])
49
50        f = Polygon_function([(p2, 2.0)])
51        z = f([5, 5, 27, 35], [5, 9, 8, -5])    # First and last inside p2
52        assert num.allclose(z, [2, 0, 0, 2])
53
54        # Combined
55        f = Polygon_function([(p1, 1.0), (p2, 2.0)])
56        z = f([5, 5, 27, 35], [5, 9, 8, -5])
57        assert num.allclose(z, [2, 1, 0, 2])
58
59    def test_polygon_function_csvfile(self):
60        from os import sep, getenv
61
62        # Get path where this test is run
63        path = get_pathname_from_package('anuga.utilities')
64
65        # Form absolute filename and read
66        filename = path + sep + 'mainland_only.csv'
67        p1 = read_polygon(filename)
68
69        f = Polygon_function([(p1, 10.0)])
70        z = f([430000, 480000], [490000, 7720000]) # 1st outside, 2nd inside
71
72        assert num.allclose(z, [0, 10])
73
74    def test_polygon_function_georef(self):
75        """Check that georeferencing works"""
76
77        from anuga.coordinate_transforms.geo_reference import Geo_reference
78
79        geo = Geo_reference(56, 200, 1000)
80
81        # Make points 'absolute'
82        p1 = [[200,1000], [210,1000], [210,1010], [200,1010]]
83        p2 = [[200,1000], [210,1010], [215,1005], [220, 1010], [225,1000],
84              [230,1010], [240,990]]
85
86        f = Polygon_function([(p1, 1.0)], geo_reference=geo)
87        z = f([5, 5, 27, 35], [5, 9, 8, -5]) # Two first inside p1
88
89        assert num.allclose(z, [1, 1, 0, 0])
90
91        f = Polygon_function([(p2, 2.0)], geo_reference=geo)
92        z = f([5, 5, 27, 35], [5, 9, 8, -5]) # First and last inside p2
93        assert num.allclose(z, [2, 0, 0, 2])
94
95        # Combined
96        f = Polygon_function([(p1, 1.0), (p2, 2.0)], geo_reference=geo)
97        z = f([5, 5, 27, 35], [5, 9, 8, -5])
98        assert num.allclose(z, [2, 1, 0, 2])
99
100        # Check that it would fail without geo
101        f = Polygon_function([(p1, 1.0), (p2, 2.0)])
102        z = f([5, 5, 27, 35], [5, 9, 8, -5])
103        assert not num.allclose(z, [2, 1, 0, 2])
104
105    def test_polygon_function_callable(self):
106        """Check that values passed into Polygon_function can be callable."""
107
108        p1 = [[0,0], [10,0], [10,10], [0,10]]
109        p2 = [[0,0], [10,10], [15,5], [20, 10], [25,0], [30,10], [40,-10]]
110
111        f = Polygon_function([(p1, test_function)])
112        z = f([5, 5, 27, 35], [5, 9, 8, -5]) # Two first inside p1
113        assert num.allclose(z, [10, 14, 0, 0])
114
115        # Combined
116        f = Polygon_function([(p1, test_function), (p2, 2.0)])
117        z = f([5, 5, 27, 35], [5, 9, 8, -5])
118        assert num.allclose(z, [2, 14, 0, 2])
119
120        # Combined w default
121        f = Polygon_function([(p1, test_function), (p2, 2.0)], default = 3.14)
122        z = f([5, 5, 27, 35], [5, 9, 8, -5])
123        assert num.allclose(z, [2, 14, 3.14, 2])
124
125        # Combined w default func
126        f = Polygon_function([(p1, test_function), (p2, 2.0)],
127                             default=test_function)
128        z = f([5, 5, 27, 35], [5, 9, 8, -5])
129        assert num.allclose(z, [2, 14, 35, 2])
130
131    def test_point_on_line(self):
132        # Endpoints first
133        assert point_on_line([0,0], [[0,0], [1,0]])
134        assert point_on_line([1,0], [[0,0], [1,0]])
135
136        # Endpoints first - non-simple
137        assert point_on_line([-0.1,0.0], [[-0.1,0.0], [1.5,0.6]])
138        assert point_on_line([1.5,0.6], [[-0.1,0.0], [1.5,0.6]])
139
140        # Then points on line
141        assert point_on_line([0.5,0], [[0,0], [1,0]])
142        assert point_on_line([0,0.5], [[0,1], [0,0]])
143        assert point_on_line([1,0.5], [[1,1], [1,0]])
144        assert point_on_line([0.5,0.5], [[0,0], [1,1]])
145
146        # Then points not on line
147        assert not point_on_line([0.5,0], [[0,1], [1,1]])
148        assert not point_on_line([0,0.5], [[0,0], [1,1]])
149
150        # From real example that failed
151        assert not point_on_line([40,50], [[40,20], [40,40]])
152
153        # From real example that failed
154        assert not point_on_line([40,19], [[40,20], [40,40]])
155
156        # Degenerate line
157        assert point_on_line([40,19], [[40,19], [40,19]])
158        assert not point_on_line([40,19], [[40,40], [40,40]])
159
160    def test_is_inside_polygon_main(self):
161        # Simplest case: Polygon is the unit square
162        polygon = [[0,0], [1,0], [1,1], [0,1]]
163
164        assert is_inside_polygon((0.5, 0.5), polygon)
165        assert not is_inside_polygon((0.5, 1.5), polygon)
166        assert not is_inside_polygon((0.5, -0.5), polygon)
167        assert not is_inside_polygon((-0.5, 0.5), polygon)
168        assert not is_inside_polygon((1.5, 0.5), polygon)
169
170        # Try point on borders
171        assert is_inside_polygon((1., 0.5), polygon, closed=True)
172        assert is_inside_polygon((0.5, 1.), polygon, closed=True)
173        assert is_inside_polygon((0., 0.5), polygon, closed=True)
174        assert is_inside_polygon((0.5, 0.), polygon, closed=True)
175
176        assert not is_inside_polygon((0.5, 1.), polygon, closed=False)
177        assert not is_inside_polygon((0., 0.5), polygon, closed=False)
178        assert not is_inside_polygon((0.5, 0.), polygon, closed=False)
179        assert not is_inside_polygon((1., 0.5), polygon, closed=False)
180
181    def test_inside_polygon_main(self):
182        """test_is_inside_polygon
183       
184        Test fast version of of is_inside_polygon
185        """
186
187        # Simplest case: Polygon is the unit square
188        polygon = [[0,0], [1,0], [1,1], [0,1]]
189
190        assert is_inside_polygon( (0.5, 0.5), polygon )
191        assert not is_inside_polygon( (0.5, 1.5), polygon )
192        assert not is_inside_polygon( (0.5, -0.5), polygon )
193        assert not is_inside_polygon( (-0.5, 0.5), polygon )
194        assert not is_inside_polygon( (1.5, 0.5), polygon )
195
196        # Try point on borders
197        assert is_inside_polygon( (1., 0.5), polygon, closed=True)
198        assert is_inside_polygon( (0.5, 1), polygon, closed=True)
199        assert is_inside_polygon( (0., 0.5), polygon, closed=True)
200        assert is_inside_polygon( (0.5, 0.), polygon, closed=True)
201
202        assert not is_inside_polygon( (0.5, 1), polygon, closed=False)
203        assert not is_inside_polygon( (0., 0.5), polygon, closed=False)
204        assert not is_inside_polygon( (0.5, 0.), polygon, closed=False)
205        assert not is_inside_polygon( (1., 0.5), polygon, closed=False)
206
207
208    def test_inside_polygon_main(self):
209        # Simplest case: Polygon is the unit square
210        polygon = [[0,0], [1,0], [1,1], [0,1]]
211
212        # From real example (that failed)
213        polygon = [[20,20], [40,20], [40,40], [20,40]]
214        points = [[40, 50]]
215        res = inside_polygon(points, polygon)
216        assert len(res) == 0
217
218        polygon = [[20,20], [40,20], [40,40], [20,40]]
219        points = [[25, 25], [30, 20], [40, 50], [90, 20], [40, 90]]
220        res = inside_polygon(points, polygon)
221        assert len(res) == 2
222        assert num.allclose(res, [0,1])
223
224        # More convoluted and non convex polygon
225        polygon = [[0,0], [1,0], [0.5,-1], [2, -1], [2,1], [0,1]]
226        assert is_inside_polygon( (0.5, 0.5), polygon )
227        assert is_inside_polygon( (1, -0.5), polygon )
228        assert is_inside_polygon( (1.5, 0), polygon )
229
230        assert not is_inside_polygon( (0.5, 1.5), polygon )
231        assert not is_inside_polygon( (0.5, -0.5), polygon )
232
233        assert is_inside_polygon( (0.5, 0.5), polygon )
234        assert is_inside_polygon( (1, -0.5), polygon )
235        assert is_inside_polygon( (1.5, 0), polygon )
236
237        assert not is_inside_polygon( (0.5, 1.5), polygon )
238        assert not is_inside_polygon( (0.5, -0.5), polygon )
239
240        # Very convoluted polygon
241        polygon = [[0,0], [10,10], [15,5], [20, 10], [25,0], [30,10], [40,-10]]
242        assert is_inside_polygon((5, 5), polygon)
243        assert is_inside_polygon((17, 7), polygon)
244        assert is_inside_polygon((27, 2), polygon)
245        assert is_inside_polygon((35, -5), polygon)
246        assert not is_inside_polygon((15, 7), polygon)
247        assert not is_inside_polygon((24, 3), polygon)
248        assert not is_inside_polygon((25, -10), polygon)
249
250        # Another combination (that failed)
251        polygon = [[0,0], [10,0], [10,10], [0,10]]
252        assert is_inside_polygon((5, 5), polygon)
253        assert is_inside_polygon((7, 7), polygon)
254        assert not is_inside_polygon((-17, 7), polygon)
255        assert not is_inside_polygon((7, 17), polygon)
256        assert not is_inside_polygon((17, 7), polygon)
257        assert not is_inside_polygon((27, 8), polygon)
258        assert not is_inside_polygon((35, -5), polygon)
259
260        # Multiple polygons
261        polygon = [[0,0], [1,0], [1,1], [0,1], [0,0], [10,10],
262                   [11,10], [11,11], [10,11], [10,10]]
263        assert is_inside_polygon((0.5, 0.5), polygon)
264        assert is_inside_polygon((10.5, 10.5), polygon)
265
266        # FIXME: Fails if point is 5.5, 5.5
267        assert not is_inside_polygon((0, 5.5), polygon)
268
269        # Polygon with a hole
270        polygon = [[-1,-1], [2,-1], [2,2], [-1,2], [-1,-1],
271                   [0,0], [1,0], [1,1], [0,1], [0,0]]
272
273        assert is_inside_polygon((0, -0.5), polygon)
274        assert not is_inside_polygon((0.5, 0.5), polygon)
275
276    def test_duplicate_points_being_ok(self):
277        # Simplest case: Polygon is the unit square
278        polygon = [[0,0], [1,0], [1,0], [1,0], [1,1], [0,1], [0,0]]
279
280        assert is_inside_polygon((0.5, 0.5), polygon)
281        assert not is_inside_polygon((0.5, 1.5), polygon)
282        assert not is_inside_polygon((0.5, -0.5), polygon)
283        assert not is_inside_polygon((-0.5, 0.5), polygon)
284        assert not is_inside_polygon((1.5, 0.5), polygon)
285
286        # Try point on borders
287        assert is_inside_polygon((1., 0.5), polygon, closed=True)
288        assert is_inside_polygon((0.5, 1), polygon, closed=True)
289        assert is_inside_polygon((0., 0.5), polygon, closed=True)
290        assert is_inside_polygon((0.5, 0.), polygon, closed=True)
291
292        assert not is_inside_polygon((0.5, 1), polygon, closed=False)
293        assert not is_inside_polygon((0., 0.5), polygon, closed=False)
294        assert not is_inside_polygon((0.5, 0.), polygon, closed=False)
295        assert not is_inside_polygon((1., 0.5), polygon, closed=False)
296
297        # From real example
298        polygon = [[20,20], [40,20], [40,40], [20,40]]
299        points = [[40, 50]]
300        res = inside_polygon(points, polygon)
301        assert len(res) == 0
302
303    def test_inside_polygon_vector_version(self):
304        # Now try the vector formulation returning indices
305        polygon = [[0,0], [1,0], [0.5,-1], [2, -1], [2,1], [0,1]]
306        points = [[0.5, 0.5], [1, -0.5], [1.5, 0], [0.5, 1.5], [0.5, -0.5]]
307        res = inside_polygon( points, polygon, verbose=False )
308        assert num.allclose(res, [0,1,2])
309
310    def test_outside_polygon(self):
311        # unit square
312        U = [[0,0], [1,0], [1,1], [0,1]]
313
314        # evaluate to False as the point 0.5, 0.5 is inside the unit square
315        assert not is_outside_polygon([0.5, 0.5], U)
316
317        # evaluate to True as the point 1.5, 0.5 is outside the unit square
318        assert is_outside_polygon([1.5, 0.5], U)
319
320        indices = outside_polygon([[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U)
321        assert num.allclose(indices, [1])
322
323        # One more test of vector formulation returning indices
324        polygon = [[0,0], [1,0], [0.5,-1], [2, -1], [2,1], [0,1]]
325        points = [[0.5, 0.5], [1, -0.5], [1.5, 0], [0.5, 1.5], [0.5, -0.5]]
326        res = outside_polygon(points, polygon)
327        assert num.allclose(res, [3, 4])
328
329        polygon = [[0,0], [1,0], [0.5,-1], [2, -1], [2,1], [0,1]]
330        points = [[0.5, 1.4], [0.5, 0.5], [1, -0.5], [1.5, 0],
331                  [0.5, 1.5], [0.5, -0.5]]
332        res = outside_polygon(points, polygon)
333
334        assert num.allclose(res, [0, 4, 5])
335
336    def test_outside_polygon2(self):
337        # unit square
338        U = [[0,0], [1,0], [1,1], [0,1]]
339
340        # evaluate to False as the point 0.5, 1.0 is inside the unit square
341        assert not outside_polygon([0.5, 1.0], U, closed = True)
342
343        # evaluate to True as the point 0.5, 1.0 is outside the unit square
344        assert is_outside_polygon([0.5, 1.0], U, closed = False)
345
346    def test_all_outside_polygon(self):
347        """Test case where all points are outside poly"""
348
349        # unit square
350        U = [[0,0], [1,0], [1,1], [0,1]]
351
352        points = [[2,2], [1,3], [-1,1], [0,2]]      # All outside
353
354        indices, count = separate_points_by_polygon(points, U)
355        assert count == 0                           # None inside
356        assert num.allclose(indices, [3, 2, 1, 0])
357
358        indices = outside_polygon(points, U, closed = True)
359        assert num.allclose(indices, [0, 1, 2, 3])
360
361        indices = inside_polygon(points, U, closed = True)
362        assert num.allclose(indices, [])
363
364    def test_all_inside_polygon(self):
365        """Test case where all points are inside poly"""
366
367        # unit square
368        U = [[0,0], [1,0], [1,1], [0,1]]
369
370        points = [[0.5,0.5], [0.2,0.3], [0,0.5]]    # All inside (or on edge)
371
372        indices, count = separate_points_by_polygon(points, U)
373        assert count == 3       # All inside
374        assert num.allclose(indices, [0, 1, 2])
375
376        indices = outside_polygon(points, U, closed=True)
377        assert num.allclose(indices, [])
378
379        indices = inside_polygon(points, U, closed=True)
380        assert num.allclose(indices, [0, 1, 2])
381
382
383    def test_separate_points_by_polygon(self):
384        # unit square
385        U = [[0,0], [1,0], [1,1], [0,1]]
386
387        indices, count = separate_points_by_polygon([[0.5, 0.5],
388                                                     [1, -0.5],
389                                                     [0.3, 0.2]],
390                                                    U)
391        assert num.allclose( indices, [0, 2, 1] )
392        assert count == 2
393
394        # One more test of vector formulation returning indices
395        polygon = [[0,0], [1,0], [0.5,-1], [2, -1], [2,1], [0,1]]
396        points = [[0.5, 0.5], [1, -0.5], [1.5, 0], [0.5, 1.5], [0.5, -0.5]]
397        res, count = separate_points_by_polygon(points, polygon)
398
399        assert num.allclose(res, [0, 1, 2, 4, 3])
400        assert count == 3
401
402        polygon = [[0,0], [1,0], [0.5,-1], [2, -1], [2,1], [0,1]]
403        points = [ [0.5, 1.4], [0.5, 0.5], [1, -0.5], [1.5, 0], [0.5, 1.5], [0.5, -0.5]]
404        res, count = separate_points_by_polygon( points, polygon )
405
406        assert num.allclose( res, [1,2,3,5,4,0] )
407        assert count == 3
408
409
410    def test_is_inside_triangle(self):
411        # Simplest case:
412        triangle = [[0, 0], [1, 0], [0.5, 1]]
413
414        assert is_inside_triangle((0.5, 0.5), triangle)
415        assert is_inside_triangle((0.9, 0.1), triangle)
416        assert not is_inside_triangle((0.5, 1.5), triangle)
417        assert not is_inside_triangle((0.5, -0.5), triangle)
418        assert not is_inside_triangle((-0.5, 0.5), triangle)
419        assert not is_inside_triangle((1.5, 0.5), triangle)
420
421        # Try point on borders
422        assert is_inside_triangle((0.5, 0), triangle, closed=True)
423        assert is_inside_triangle((1, 0), triangle, closed=True)
424
425        assert not is_inside_triangle((0.5, 0), triangle, closed=False)
426        assert not is_inside_triangle((1, 0), triangle, closed=False)
427
428        # Try vertices
429        for P in triangle:
430            assert is_inside_triangle(P, triangle, closed=True)
431            assert not is_inside_triangle(P, triangle, closed=False)
432
433        # Slightly different
434        triangle = [[0, 0.1], [1, -0.2], [0.5, 1]]
435        assert is_inside_triangle((0.5, 0.5), triangle)
436        assert is_inside_triangle((0.4, 0.1), triangle)
437        assert not is_inside_triangle((1, 1), triangle)
438
439        # Try vertices
440        for P in triangle:
441            assert is_inside_triangle(P, triangle, closed=True)
442            assert not is_inside_triangle(P, triangle, closed=False)
443
444
445    def test_populate_polygon(self):
446        polygon = [[0,0], [1,0], [1,1], [0,1]]
447        points = populate_polygon(polygon, 5)
448
449        assert len(points) == 5
450        for point in points:
451            assert is_inside_polygon(point, polygon)
452
453            assert is_inside_polygon(point, polygon)
454
455
456        # Very convoluted polygon
457        polygon = [[0,0], [10,10], [15,5], [20, 10], [25,0], [30,10], [40,-10]]
458        points = populate_polygon(polygon, 5)
459        assert len(points) == 5
460        for point in points:
461            assert is_inside_polygon(point, polygon)
462            assert is_inside_polygon(point, polygon)
463
464
465    def test_populate_polygon_with_exclude(self):
466        polygon = [[0,0], [1,0], [1,1], [0,1]]
467        ex_poly = [[0,0], [0.5,0], [0.5, 0.5], [0,0.5]]     # SW quarter
468        points = populate_polygon(polygon, 5, exclude=[ex_poly])
469
470        assert len(points) == 5
471        for point in points:
472            assert is_inside_polygon(point, polygon)
473            assert not is_inside_polygon(point, ex_poly)
474
475        # overlap
476        polygon = [[0,0], [1,0], [1,1], [0,1]]
477        ex_poly = [[-1,-1], [0.5,0], [0.5, 0.5], [-1,0.5]]
478        points = populate_polygon(polygon, 5, exclude=[ex_poly])
479
480        assert len(points) == 5
481        for point in points:
482            assert is_inside_polygon(point, polygon)
483            assert not is_inside_polygon(point, ex_poly)
484
485        # Multiple
486        polygon = [[0,0], [1,0], [1,1], [0,1]]
487        ex_poly1 = [[0,0], [0.5,0], [0.5, 0.5], [0,0.5]]    # SW quarter
488        ex_poly2 = [[0.5,0.5], [0.5,1], [1, 1], [1,0.5]]    # NE quarter
489
490        points = populate_polygon(polygon, 20, exclude=[ex_poly1, ex_poly2])
491
492        assert len(points) == 20
493        for point in points:
494            assert is_inside_polygon(point, polygon)
495            assert not is_inside_polygon(point, ex_poly1)
496            assert not is_inside_polygon(point, ex_poly2)
497
498        # Very convoluted polygon
499        polygon = [[0,0], [10,10], [15,5], [20, 10], [25,0], [30,10], [40,-10]]
500        ex_poly = [[-1,-1], [5,0], [5, 5], [-1,5]]
501        points = populate_polygon(polygon, 20, exclude=[ex_poly])
502
503        assert len(points) == 20
504        for point in points:
505            assert is_inside_polygon(point, polygon)
506            assert not is_inside_polygon(point, ex_poly), '%s' % str(point)
507
508    def test_populate_polygon_with_exclude2(self):
509        min_outer = 0
510        max_outer = 1000
511        polygon_outer = [[min_outer,min_outer], [max_outer,min_outer],
512                         [max_outer,max_outer], [min_outer,max_outer]]
513
514        delta = 10
515        min_inner1 = min_outer + delta
516        max_inner1 = max_outer - delta
517        inner1_polygon = [[min_inner1,min_inner1], [max_inner1,min_inner1],
518                          [max_inner1,max_inner1], [min_inner1,max_inner1]]
519
520        density_inner2 = 1000
521        min_inner2 = min_outer + 2*delta
522        max_inner2 = max_outer - 2*delta
523        inner2_polygon = [[min_inner2,min_inner2], [max_inner2,min_inner2],
524                          [max_inner2,max_inner2], [min_inner2,max_inner2]]
525
526        points = populate_polygon(polygon_outer, 20,
527                                  exclude=[inner1_polygon, inner2_polygon])
528
529        assert len(points) == 20
530        for point in points:
531            assert is_inside_polygon(point, polygon_outer)
532            assert not is_inside_polygon(point, inner1_polygon)
533            assert not is_inside_polygon(point, inner2_polygon)
534
535        # Very convoluted polygon
536        polygon = [[0,0], [10,10], [15,5], [20, 10], [25,0], [30,10], [40,-10]]
537        ex_poly = [[-1,-1], [5,0], [5, 5], [-1,5]]
538        points = populate_polygon(polygon, 20, exclude=[ex_poly])
539
540        assert len(points) == 20
541        for point in points:
542            assert is_inside_polygon(point, polygon)
543            assert not is_inside_polygon(point, ex_poly), '%s' % str(point)
544
545    def test_point_in_polygon(self):
546        polygon = [[0,0], [1,0], [1,1], [0,1]]
547        point = point_in_polygon(polygon)
548        assert is_inside_polygon(point, polygon)
549
550        # this may get into a vicious loop
551        # polygon = [[1e32,1e54], [1,0], [1,1], [0,1]]
552
553        polygon = [[1e15,1e7], [1,0], [1,1], [0,1]]
554        point = point_in_polygon(polygon)
555        assert is_inside_polygon(point, polygon)
556
557        polygon = [[0,0], [1,0], [1,1], [1e8,1e8]]
558        point = point_in_polygon(polygon)
559        assert is_inside_polygon(point, polygon)
560
561        polygon = [[1e32,1e54], [-1e32,1e54], [1e32,-1e54]]
562        point = point_in_polygon(polygon)
563        assert is_inside_polygon(point, polygon)
564
565        polygon = [[1e18,1e15], [1,0], [0,1]]
566        point = point_in_polygon(polygon)
567        assert is_inside_polygon(point, polygon)
568
569    def test_in_and_outside_polygon_main(self):
570        # Simplest case: Polygon is the unit square
571        polygon = [[0,0], [1,0], [1,1], [0,1]]
572
573        inside, outside = in_and_outside_polygon((0.5, 0.5), polygon)
574        assert inside[0] == 0
575        assert len(outside) == 0
576
577        inside, outside = in_and_outside_polygon((1., 0.5), polygon,
578                                                 closed=True)
579        assert inside[0] == 0
580        assert len(outside) == 0
581
582        inside, outside = in_and_outside_polygon((1., 0.5), polygon,
583                                                 closed=False)
584        assert len(inside) == 0
585        assert outside[0] == 0
586
587        points = [(1., 0.25),(1., 0.75)]
588        inside, outside = in_and_outside_polygon(points, polygon, closed=True)
589        assert num.alltrue(inside == [0,1])
590        assert len(outside) == 0
591
592        inside, outside = in_and_outside_polygon(points, polygon, closed=False)
593        assert len(inside) == 0
594        assert num.alltrue(outside == [0,1])
595
596        points = [(100., 0.25), (0.5, 0.5) ]
597        inside, outside = in_and_outside_polygon(points, polygon)
598        assert num.alltrue(inside == [1])
599        assert outside[0] == 0
600
601        points = [(100., 0.25),(0.5, 0.5), (39,20), (0.6,0.7),(56,43),(67,90)]
602        inside, outside = in_and_outside_polygon(points, polygon)
603        assert num.alltrue(inside == [1, 3])
604        assert num.alltrue(outside == [0, 2, 4, 5])
605
606    def test_intersection1(self):
607        line0 = [[-1,0], [1,0]]
608        line1 = [[0,-1], [0,1]]
609
610        status, value = intersection(line0, line1)
611        assert status == 1
612        assert num.allclose(value, [0.0, 0.0])
613
614    def test_intersection2(self):
615        line0 = [[0,0], [24,12]]
616        line1 = [[0,12], [24,0]]
617
618        status, value = intersection(line0, line1)
619        assert status == 1
620        assert num.allclose(value, [12.0, 6.0])
621
622        # Swap direction of one line
623        line1 = [[24,0], [0,12]]
624
625        status, value = intersection(line0, line1)
626        assert status == 1
627        assert num.allclose(value, [12.0, 6.0])
628
629        # Swap order of lines
630        status, value = intersection(line1, line0)
631        assert status == 1
632        assert num.allclose(value, [12.0, 6.0])
633
634    def test_intersection3(self):
635        line0 = [[0,0], [24,12]]
636        line1 = [[0,17], [24,0]]
637
638        status, value = intersection(line0, line1)
639        assert status == 1
640        assert num.allclose(value, [14.068965517, 7.0344827586])
641
642        # Swap direction of one line
643        line1 = [[24,0], [0,17]]
644
645        status, value = intersection(line0, line1)
646        assert status == 1
647        assert num.allclose(value, [14.068965517, 7.0344827586])
648
649        # Swap order of lines
650        status, value = intersection(line1, line0)
651        assert status == 1
652        assert num.allclose(value, [14.068965517, 7.0344827586])
653
654    def test_intersection_endpoints(self):
655        """test_intersection_endpoints(self):
656
657        Test that coinciding endpoints are picked up
658        """
659
660        line0 = [[0,0], [1,1]]
661        line1 = [[1,1], [2,1]]
662
663        status, value = intersection(line0, line1)
664        assert status == 1
665        assert num.allclose(value, [1.0, 1.0])
666
667        line0 = [[1,1], [2,0]]
668        line1 = [[1,1], [2,1]]
669
670        status, value = intersection(line0, line1)
671        assert status == 1
672        assert num.allclose(value, [1.0, 1.0])
673
674    # This function is a helper function for
675    # the test_intersection_bug_20081110_?() set of tests.
676    # This function tests all parallel line cases for 4 collinear points.
677    # This function should never be run directly by the unittest code.
678    def helper_test_parallel_intersection_code(self, P1, P2, P3, P4):
679        # lines in same direction, no overlap
680        # 0:         ---->----
681        # 1:                     --------->-----------
682        line0 = [P1, P2]
683        line1 = [P3, P4]
684        status, value = intersection(line0, line1)
685        self.failIf(status!=3, 'Expected status 3, got status=%s, value=%s' %
686                               (str(status), str(value)))
687        self.failUnless(value is None, 'Expected value of None, got %s' %
688                                       str(value))
689
690        # lines in same direction, no overlap
691        # 0:         ----<----
692        # 1:                     ---------<-----------
693        line0 = [P2, P1]
694        line1 = [P4, P3]
695        status, value = intersection(line0, line1)
696        self.failIf(status!=3, 'Expected status 3, got status=%s, value=%s' %
697                               (str(status), str(value)))
698        self.failUnless(value is None, 'Expected value of None, got %s' %
699                                       str(value))
700
701        # lines in opposite direction, no overlap
702        # 0:         ----<----
703        # 1:                     --------->-----------
704        line0 = [P2, P1]
705        line1 = [P3, P4]
706        status, value = intersection(line0, line1)
707        self.failIf(status!=3, 'Expected status 3, got status=%s, value=%s' %
708                               (str(status), str(value)))
709        self.failUnless(value is None, 'Expected value of None, got %s' %
710                                       str(value))
711
712        # lines in opposite direction, no overlap
713        # 0:         ---->----
714        # 1:                     ---------<-----------
715        line0 = [P1, P2]
716        line1 = [P4, P3]
717        status, value = intersection(line0, line1)
718        self.failIf(status!=3, 'Expected status 3, got status=%s, value=%s' %
719                               (str(status), str(value)))
720        self.failUnless(value is None, 'Expected value of None, got %s' %
721                                       str(value))
722
723        # ----------------------------------------------------------------------
724
725        # line0 fully within line1, same direction
726        # 0:         ---->----
727        # 1:    --------->-----------
728        # value should be line0:
729        #            ---->----
730        line0 = [P2, P3]
731        line1 = [P1, P4]
732        status, value = intersection(line0, line1)
733        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
734                               (str(status), str(value)))
735        self.failUnless(num.allclose(value, line0))
736
737        # line0 fully within line1, same direction
738        # 0:         ----<----
739        # 1:    ---------<-----------
740        # value should be line0:
741        #            ----<----
742        line0 = [P3, P2]
743        line1 = [P4, P1]
744        status, value = intersection(line0, line1)
745        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
746                               (str(status), str(value)))
747        self.failUnless(num.allclose(value, line0))
748
749        # line0 fully within line1, opposite direction
750        # 0:         ----<----
751        # 1:    --------->-----------
752        # value should be line0:
753        #            ----<----
754        line0 = [P3, P2]
755        line1 = [P1, P4]
756        status, value = intersection(line0, line1)
757        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
758                               (str(status), str(value)))
759        self.failUnless(num.allclose(value, line0))
760
761        # line0 fully within line1, opposite direction
762        # 0:         ---->----
763        # 1:    ---------<-----------
764        # value should be line0:
765        #            ---->----
766        line0 = [P2, P3]
767        line1 = [P4, P1]
768        status, value = intersection(line0, line1)
769        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
770                               (str(status), str(value)))
771        self.failUnless(num.allclose(value, line0))
772
773        # ----------------------------------------------------------------------
774
775        # line1 fully within line0, same direction
776        # 0:    --------->-----------
777        # 1:         ---->----
778        # value should be line1:
779        #            ---->----
780        line0 = [P1, P4]
781        line1 = [P2, P3]
782        status, value = intersection(line0, line1)
783        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
784                               (str(status), str(value)))
785        self.failUnless(num.allclose(value, line1))
786
787        # line1 fully within line0, same direction
788        # 0:    ---------<-----------
789        # 1:         ----<----
790        # value should be line1:
791        #            ----<----
792        line0 = [P4, P1]
793        line1 = [P3, P2]
794        status, value = intersection(line0, line1)
795        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
796                               (str(status), str(value)))
797        self.failUnless(num.allclose(value, line1))
798
799        # line1 fully within line0, opposite direction
800        # 0:    ---------<-----------
801        # 1:         ---->----
802        # value should be line1:
803        #            ---->----
804        line0 = [P4, P1]
805        line1 = [P2, P3]
806        status, value = intersection(line0, line1)
807        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
808                               (str(status), str(value)))
809        self.failUnless(num.allclose(value, line1))
810
811        # line1 fully within line0, opposite direction
812        # 0:    --------->-----------
813        # 1:         ----<----
814        # value should be line1:
815        #            ----<----
816        line0 = [P1, P4]
817        line1 = [P3, P2]
818        status, value = intersection(line0, line1)
819        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
820                               (str(status), str(value)))
821        self.failUnless(num.allclose(value, line1))
822
823        # ----------------------------------------------------------------------
824
825        # line in same direction, partial overlap
826        # 0:    ----->-----
827        # 1:       ------->--------
828        # value should be segment line1_start->line0_end:
829        #          --->----
830        line0 = [P1, P3]
831        line1 = [P2, P4]
832        status, value = intersection(line0, line1)
833        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
834                               (str(status), str(value)))
835        self.failUnless(num.allclose(value, [line1[0],line0[1]]))
836
837        # line in same direction, partial overlap
838        # 0:    -----<-----
839        # 1:       -------<--------
840        # value should be segment line0_start->line1_end:
841        #          ---<----
842        line0 = [P3, P1]
843        line1 = [P4, P2]
844        status, value = intersection(line0, line1)
845        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
846                               (str(status), str(value)))
847        self.failUnless(num.allclose(value, [line0[0],line1[1]]))
848
849        # line in opposite direction, partial overlap
850        # 0:    -----<-----
851        # 1:       ------->--------
852        # value should be segment line0_start->line1_start:
853        #          ---<----
854        line0 = [P3, P1]
855        line1 = [P2, P4]
856        status, value = intersection(line0, line1)
857        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
858                               (str(status), str(value)))
859        self.failUnless(num.allclose(value, [line0[0],line1[0]]))
860
861        # line in opposite direction, partial overlap
862        # 0:    ----->-----
863        # 1:       -------<--------
864        # value should be segment line1_end->line0_end:
865        #          --->----
866        line0 = [P1, P3]
867        line1 = [P4, P2]
868        status, value = intersection(line0, line1)
869        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
870                               (str(status), str(value)))
871        self.failUnless(num.allclose(value, [line1[1],line0[1]]))
872
873        # ----------------------------------------------------------------------
874
875        # line in same direction, partial overlap
876        # 0:       ------>------
877        # 1:    ------>------
878        # value should be segment line0_start->line1_end:
879        #          --->----
880        line0 = [P2, P4]
881        line1 = [P1, P3]
882        status, value = intersection(line0, line1)
883        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
884                               (str(status), str(value)))
885        self.failUnless(num.allclose(value, [line0[0],line1[1]]))
886
887        # line in same direction, partial overlap
888        # 0:       ------<------
889        # 1:    ------<------
890        # value should be segment line1_start->line0_end:
891        #          ----<-----
892        line0 = [P4, P2]
893        line1 = [P3, P1]
894        status, value = intersection(line0, line1)
895        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
896                               (str(status), str(value)))
897        self.failUnless(num.allclose(value, [line1[0],line0[1]]))
898
899        # line in opposite direction, partial overlap
900        # 0:       ------<------
901        # 1:    ----->------
902        # value should be segment line1_end->line0_end:
903        #          --->----
904        line0 = [P4, P2]
905        line1 = [P1, P3]
906        status, value = intersection(line0, line1)
907        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
908                               (str(status), str(value)))
909        self.failUnless(num.allclose(value, [line1[1],line0[1]]))
910
911        # line in opposite direction, partial overlap
912        # 0:       ------>------
913        # 1:    -----<------
914        # value should be segment line0_start->line1_start:
915        #          ---<----
916        line0 = [P2, P4]
917        line1 = [P3, P1]
918        status, value = intersection(line0, line1)
919        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
920                               (str(status), str(value)))
921        self.failUnless(num.allclose(value, [line0[0],line1[0]]))
922
923        # ----------------------------------------------------------------------
924
925        # line in same direction, same left point, line1 longer
926        # 0:    ----->------
927        # 1:    ------->--------
928        # value should be line0:
929        #       ----->------
930        line0 = [P1, P3]
931        line1 = [P1, P4]
932        status, value = intersection(line0, line1)
933        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
934                               (str(status), str(value)))
935        self.failUnless(num.allclose(value, line0))
936
937        # line in same direction, same left point, line1 longer
938        # 0:    -----<------
939        # 1:    -------<--------
940        # value should be line0:
941        #       -----<------
942        line0 = [P3, P1]
943        line1 = [P4, P1]
944        status, value = intersection(line0, line1)
945        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
946                               (str(status), str(value)))
947        self.failUnless(num.allclose(value, line0))
948
949        # line in opposite direction, same left point, line1 longer
950        # 0:    ----->------
951        # 1:    -------<--------
952        # value should be line0:
953        #       ----->------
954        line0 = [P1, P3]
955        line1 = [P4, P1]
956        status, value = intersection(line0, line1)
957        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
958                               (str(status), str(value)))
959        self.failUnless(num.allclose(value, line0))
960
961        # line in opposite direction, same start point, line1 longer
962        # 0:    -----<------
963        # 1:    ------->--------
964        # value should be line0:
965        #       -----<------
966        line0 = [P3, P1]
967        line1 = [P1, P4]
968        status, value = intersection(line0, line1)
969        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
970                               (str(status), str(value)))
971        self.failUnless(num.allclose(value, line0))
972
973        # ----------------------------------------------------------------------
974
975        # line in same direction, same left point, same right point
976        # 0:    ------->--------
977        # 1:    ------->--------
978        # value should be line0 or line1:
979        #       ------->--------
980        line0 = [P1, P3]
981        line1 = [P1, P3]
982        status, value = intersection(line0, line1)
983        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
984                               (str(status), str(value)))
985        self.failUnless(num.allclose(value, line0))
986
987        # line in same direction, same left point, same right point
988        # 0:    -------<--------
989        # 1:    -------<--------
990        # value should be line0 (or line1):
991        #       -------<--------
992        line0 = [P3, P1]
993        line1 = [P3, P1]
994        status, value = intersection(line0, line1)
995        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
996                               (str(status), str(value)))
997        self.failUnless(num.allclose(value, line0))
998
999        # line in opposite direction, same left point, same right point
1000        # 0:    ------->--------
1001        # 1:    -------<--------
1002        # value should be line0:
1003        #       ------->--------
1004        line0 = [P1, P3]
1005        line1 = [P3, P1]
1006        status, value = intersection(line0, line1)
1007        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
1008                               (str(status), str(value)))
1009        self.failUnless(num.allclose(value, line0))
1010
1011        # line in opposite direction, same left point, same right point
1012        # 0:    -------<--------
1013        # 1:    ------->--------
1014        # value should be line0:
1015        #       -------<--------
1016        line0 = [P3, P1]
1017        line1 = [P1, P3]
1018        status, value = intersection(line0, line1)
1019        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
1020                               (str(status), str(value)))
1021        self.failUnless(num.allclose(value, line0))
1022
1023        # ----------------------------------------------------------------------
1024
1025        # line in same direction, same right point, line1 longer
1026        # 0:        ----->------
1027        # 1:    ------->--------
1028        # value should be line0:
1029        #           ----->------
1030        line0 = [P2, P4]
1031        line1 = [P1, P4]
1032        status, value = intersection(line0, line1)
1033        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
1034                               (str(status), str(value)))
1035        self.failUnless(num.allclose(value, line0))
1036
1037        # line in same direction, same right point, line1 longer
1038        # 0:        -----<------
1039        # 1:    -------<--------
1040        # value should be line0:
1041        #           -----<------
1042        line0 = [P4, P2]
1043        line1 = [P4, P1]
1044        status, value = intersection(line0, line1)
1045        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
1046                               (str(status), str(value)))
1047        self.failUnless(num.allclose(value, line0))
1048
1049        # line in opposite direction, same right point, line1 longer
1050        # 0:        ----->------
1051        # 1:    -------<--------
1052        # value should be line0:
1053        #           ----->------
1054        line0 = [P2, P4]
1055        line1 = [P4, P1]
1056        status, value = intersection(line0, line1)
1057        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
1058                               (str(status), str(value)))
1059        self.failUnless(num.allclose(value, line0))
1060
1061        # line in opposite direction, same right point, line1 longer
1062        # 0:        -----<------
1063        # 1:    ------->--------
1064        # value should be line0:
1065        #           -----<------
1066        line0 = [P4, P2]
1067        line1 = [P1, P4]
1068        status, value = intersection(line0, line1)
1069        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
1070                               (str(status), str(value)))
1071        self.failUnless(num.allclose(value, line0))
1072
1073        # ----------------------------------------------------------------------
1074
1075        # line in same direction, same left point, line0 longer
1076        # 0:    ------->--------
1077        # 1:    ----->------
1078        # value should be line1:
1079        #       ----->------
1080        line0 = [P1, P4]
1081        line1 = [P1, P3]
1082        status, value = intersection(line0, line1)
1083        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
1084                               (str(status), str(value)))
1085        self.failUnless(num.allclose(value, line1))
1086
1087        # line in same direction, same left point, line0 longer
1088        # 0:    -------<--------
1089        # 1:    -----<------
1090        # value should be line1:
1091        #       -----<------
1092        line0 = [P4, P1]
1093        line1 = [P3, P1]
1094        status, value = intersection(line0, line1)
1095        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
1096                               (str(status), str(value)))
1097        self.failUnless(num.allclose(value, line1))
1098
1099        # line in opposite direction, same left point, line0 longer
1100        # 0:    ------->--------
1101        # 1:    -----<------
1102        # value should be line1:
1103        #       -----<------
1104        line0 = [P1, P4]
1105        line1 = [P3, P1]
1106        status, value = intersection(line0, line1)
1107        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
1108                               (str(status), str(value)))
1109        self.failUnless(num.allclose(value, line1))
1110
1111        # line in opposite direction, same left point, line0 longer
1112        # 0:    -------<--------
1113        # 1:    ----->------
1114        # value should be line1:
1115        #       ----->------
1116        line0 = [P4, P1]
1117        line1 = [P1, P3]
1118        status, value = intersection(line0, line1)
1119        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
1120                               (str(status), str(value)))
1121        self.failUnless(num.allclose(value, line1))
1122
1123        # ----------------------------------------------------------------------
1124
1125        # line in same direction, same right point, line0 longer
1126        # 0:    ------->--------
1127        # 1:        ----->------
1128        # value should be line1:
1129        #           ----->------
1130        line0 = [P1, P4]
1131        line1 = [P2, P4]
1132        status, value = intersection(line0, line1)
1133        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
1134                               (str(status), str(value)))
1135        self.failUnless(num.allclose(value, line1))
1136
1137        # line in same direction, same right point, line0 longer
1138        # 0:    -------<--------
1139        # 1:        -----<------
1140        # value should be line1:
1141        #           -----<------
1142        line0 = [P4, P1]
1143        line1 = [P4, P2]
1144        status, value = intersection(line0, line1)
1145        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
1146                               (str(status), str(value)))
1147        self.failUnless(num.allclose(value, line1))
1148
1149        # line in opposite direction, same right point, line0 longer
1150        # 0:    ------->--------
1151        # 1:        -----<------
1152        # value should be line1:
1153        #           -----<------
1154        line0 = [P1, P4]
1155        line1 = [P4, P2]
1156        status, value = intersection(line0, line1)
1157        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
1158                               (str(status), str(value)))
1159        self.failUnless(num.allclose(value, line1))
1160
1161        # line in opposite direction, same right point, line0 longer
1162        # 0:    -------<--------
1163        # 1:        ----->------
1164        # value should be line1:
1165        #           ----->------
1166        line0 = [P4, P1]
1167        line1 = [P2, P4]
1168        status, value = intersection(line0, line1)
1169        self.failIf(status!=2, 'Expected status 2, got status=%s, value=%s' %
1170                               (str(status), str(value)))
1171        self.failUnless(num.allclose(value, line1))
1172
1173
1174    def test_intersection_bug_20081110_TR(self):
1175        """test_intersection_bug_20081110(self)
1176
1177        Test all cases in top-right quadrant
1178        """
1179
1180        # define 4 collinear points in top-right quadrant
1181        #    P1---P2---P3---P4
1182        P1 = [1.0, 1.0]
1183        P2 = [2.0, 2.0]
1184        P3 = [3.0, 3.0]
1185        P4 = [4.0, 4.0]
1186
1187        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1188        P1 = [1.0, 1.0+1.0e-9]
1189        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1190        P1 = [1.0, 1.0]
1191        P2 = [2.0, 2.0+1.0e-9]
1192        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1193        P2 = [2.0, 2.0]
1194        P3 = [3.0, 3.0+1.0e-9]
1195        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1196        P3 = [3.0, 3.0]
1197        P4 = [4.0, 4.0+1.0e-9]
1198        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1199
1200    def test_intersection_bug_20081110_TL(self):
1201        """test_intersection_bug_20081110(self)
1202
1203        Test all cases in top-left quadrant
1204        """
1205
1206        # define 4 collinear points in top-left quadrant
1207        #    P1---P2---P3---P4
1208        P1 = [-1.0, 1.0]
1209        P2 = [-2.0, 2.0]
1210        P3 = [-3.0, 3.0]
1211        P4 = [-4.0, 4.0]
1212
1213        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1214        P1 = [-1.0, 1.0+1.0e-9]
1215        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1216        P1 = [-1.0, 1.0]
1217        P2 = [-2.0, 2.0+1.0e-9]
1218        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1219        P2 = [-2.0, 2.0]
1220        P3 = [-3.0, 3.0+1.0e-9]
1221        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1222        P3 = [-3.0, 3.0]
1223        P4 = [-4.0, 4.0+1.0e-9]
1224        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1225
1226    def test_intersection_bug_20081110_BL(self):
1227        """test_intersection_bug_20081110(self)
1228
1229        Test all cases in bottom-left quadrant
1230        """
1231
1232        # define 4 collinear points in bottom-left quadrant
1233        #    P1---P2---P3---P4
1234        P1 = [-1.0, -1.0]
1235        P2 = [-2.0, -2.0]
1236        P3 = [-3.0, -3.0]
1237        P4 = [-4.0, -4.0]
1238
1239        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1240        P1 = [-1.0, -1.0+1.0e-9]
1241        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1242        P1 = [-1.0, -1.0]
1243        P2 = [-2.0, -2.0+1.0e-9]
1244        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1245        P2 = [-2.0, -2.0]
1246        P3 = [-3.0, -3.0+1.0e-9]
1247        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1248        P3 = [-3.0, -3.0]
1249        P4 = [-4.0, -4.0+1.0e-9]
1250        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1251
1252    def test_intersection_bug_20081110_BR(self):
1253        """test_intersection_bug_20081110(self)
1254
1255        Test all cases in bottom-right quadrant
1256        """
1257
1258        # define 4 collinear points in bottom-right quadrant
1259        #    P1---P2---P3---P4
1260        P1 = [1.0, -1.0]
1261        P2 = [2.0, -2.0]
1262        P3 = [3.0, -3.0]
1263        P4 = [4.0, -4.0]
1264
1265        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1266        P1 = [1.0, -1.0+1.0e-9]
1267        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1268        P1 = [1.0, -1.0]
1269        P2 = [2.0, -2.0+1.0e-9]
1270        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1271        P2 = [2.0, -2.0]
1272        P3 = [3.0, -3.0+1.0e-9]
1273        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1274        P3 = [3.0, -3.0]
1275        P4 = [4.0, -4.0+1.0e-9]
1276        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1277
1278    def test_intersection_bug_20081110_TR_TL(self):
1279        """test_intersection_bug_20081110(self)
1280
1281        Test all cases in top-right & top-left quadrant
1282        """
1283
1284        # define 4 collinear points, 1 in TL, 3 in TR
1285        #    P1-+-P2---P3---P4
1286        P1 = [-3.0, 1.0]
1287        P2 = [ 1.0, 5.0]
1288        P3 = [ 2.0, 6.0]
1289        P4 = [ 3.0, 7.0]
1290        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1291
1292        # define 4 collinear points, 2 in TL, 2 in TR
1293        #    P1---P2-+-P3---P4
1294        P1 = [-3.0, 1.0]
1295        P2 = [-2.0, 2.0]
1296        P3 = [ 2.0, 6.0]
1297        P4 = [ 3.0, 7.0]
1298        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1299
1300        # define 4 collinear points, 3 in TL, 1 in TR
1301        #    P1---P2---P3-+-P4
1302        P1 = [-3.0, 1.0]
1303        P2 = [-2.0, 2.0]
1304        P3 = [-1.0, 3.0]
1305        P4 = [ 3.0, 7.0]
1306        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1307
1308    def test_intersection_bug_20081110_TR_BL(self):
1309        """test_intersection_bug_20081110(self)
1310
1311        Test all cases in top-right & bottom-left quadrant
1312        """
1313
1314        # define 4 collinear points, 1 in BL, 3 in TR
1315        #    P1-+-P2---P3---P4
1316        P1 = [-4.0, -3.0]
1317        P2 = [ 1.0,  2.0]
1318        P3 = [ 2.0,  3.0]
1319        P4 = [ 3.0,  4.0]
1320        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1321
1322        # define 4 collinear points, 2 in TL, 2 in TR
1323        #    P1---P2-+-P3---P4
1324        P1 = [-4.0, -3.0]
1325        P2 = [-3.0, -2.0]
1326        P3 = [ 2.0,  3.0]
1327        P4 = [ 3.0,  4.0]
1328        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1329
1330        # define 4 collinear points, 3 in TL, 1 in TR
1331        #    P1---P2---P3-+-P4
1332        P1 = [-4.0, -3.0]
1333        P2 = [-3.0, -2.0]
1334        P3 = [-2.0, -1.0]
1335        P4 = [ 3.0,  4.0]
1336        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1337
1338    def test_intersection_bug_20081110_TR_BR(self):
1339        """test_intersection_bug_20081110(self)
1340
1341        Test all cases in top-right & bottom-right quadrant
1342        """
1343
1344        # define 4 collinear points, 1 in BR, 3 in TR
1345        #    P1-+-P2---P3---P4
1346        P1 = [ 1.0, -3.0]
1347        P2 = [ 5.0,  1.0]
1348        P3 = [ 6.0,  2.0]
1349        P4 = [ 7.0,  3.0]
1350        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1351
1352        # define 4 collinear points, 2 in BR, 2 in TR
1353        #    P1---P2-+-P3---P4
1354        P1 = [ 1.0, -3.0]
1355        P2 = [ 2.0, -2.0]
1356        P3 = [ 6.0,  2.0]
1357        P4 = [ 7.0,  3.0]
1358        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1359
1360        # define 4 collinear points, 3 in BR, 1 in TR
1361        #    P1---P2---P3-+-P4
1362        P1 = [ 1.0, -3.0]
1363        P2 = [ 2.0, -2.0]
1364        P3 = [ 3.0, -1.0]
1365        P4 = [ 7.0,  3.0]
1366        self.helper_test_parallel_intersection_code(P1, P2, P3, P4)
1367
1368
1369    def test_intersection_direction_invariance(self):
1370        """This runs through a number of examples and checks that
1371        direction of lines don't matter.
1372        """
1373
1374        line0 = [[0,0], [100,100]]
1375
1376        common_end_point = [20, 150]
1377
1378        for i in range(100):
1379            x = 20 + i * 1.0/100
1380
1381            line1 = [[x,0], common_end_point]
1382            status, p1 = intersection(line0, line1)
1383            assert status == 1
1384
1385            # Swap direction of line1
1386            line1 = [common_end_point, [x,0]]
1387            status, p2 = intersection(line0, line1)
1388            assert status == 1
1389
1390            msg = ('Orientation of line should not matter.\n'
1391                   'However, segment [%f,%f], [%f, %f]' %
1392                   (x, 0, common_end_point[0], common_end_point[1]))
1393            msg += ' gave %s, \nbut when reversed we got %s' % (p1, p2)
1394            assert num.allclose(p1, p2), msg
1395
1396            # Swap order of lines
1397            status, p3 = intersection(line1, line0)
1398            assert status == 1
1399            msg = 'Order of lines gave different results'
1400            assert num.allclose(p1, p3), msg
1401
1402    def test_no_intersection(self):
1403        line0 = [[-1,1], [1,1]]
1404        line1 = [[0,-1], [0,0]]
1405
1406        status, value = intersection(line0, line1)
1407        assert status == 0
1408        assert value is None
1409
1410    def test_intersection_parallel(self):
1411        line0 = [[-1,1], [1,1]]
1412        line1 = [[-1,0], [5,0]]
1413
1414        status, value = intersection(line0, line1)
1415        assert status == 4
1416        assert value is None
1417
1418        line0 = [[0,0], [10,100]]
1419        line1 = [[-10,5], [0,105]]
1420
1421        status, value = intersection(line0, line1)
1422        assert status == 4
1423        assert value is None
1424
1425    def test_intersection_coincide(self):
1426        """Test what happens when two lines partly coincide"""
1427
1428        # Overlap 1
1429        line0 = [[0,0], [5,0]]
1430        line1 = [[-3,0], [3,0]]
1431
1432        status, value = intersection(line0, line1)
1433        assert status == 2
1434        assert num.allclose(value, [[0,0], [3,0]])
1435
1436        # Overlap 2
1437        line0 = [[-10,0], [5,0]]
1438        line1 = [[-3,0], [10,0]]
1439
1440        status, value = intersection(line0, line1)
1441        assert status == 2
1442        assert num.allclose(value, [[-3, 0], [5,0]])
1443
1444        # Inclusion 1
1445        line0 = [[0,0], [5,0]]
1446        line1 = [[2,0], [3,0]]
1447
1448        status, value = intersection(line0, line1)
1449        assert status == 2
1450        assert num.allclose(value, line1)
1451
1452        # Inclusion 2
1453        line0 = [[1,0], [5,0]]
1454        line1 = [[-10,0], [15,0]]
1455
1456        status, value = intersection(line0, line1)
1457        assert status == 2
1458        assert num.allclose(value, line0)
1459
1460        # Exclusion (no intersection)
1461        line0 = [[-10,0], [1,0]]
1462        line1 = [[3,0], [15,0]]
1463
1464        status, value = intersection(line0, line1)
1465        assert status == 3
1466        assert value is None
1467
1468        # Try examples with some slope (y=2*x+5)
1469
1470        # Overlap
1471        line0 = [[0,5], [7,19]]
1472        line1 = [[1,7], [10,25]]
1473        status, value = intersection(line0, line1)
1474        assert status == 2
1475        assert num.allclose(value, [[1, 7], [7, 19]])
1476
1477        status, value = intersection(line1, line0)
1478        assert status == 2
1479        assert num.allclose(value, [[1, 7], [7, 19]])
1480
1481        # Swap direction
1482        line0 = [[7,19], [0,5]]
1483        line1 = [[1,7], [10,25]]
1484        status, value = intersection(line0, line1)
1485        assert status == 2
1486        assert num.allclose(value, [[7, 19], [1, 7]])
1487
1488        line0 = [[0,5], [7,19]]
1489        line1 = [[10,25], [1,7]]
1490        status, value = intersection(line0, line1)
1491        assert status == 2
1492        assert num.allclose(value, [[1, 7], [7, 19]])
1493
1494        # Inclusion
1495        line0 = [[1,7], [7,19]]
1496        line1 = [[0,5], [10,25]]
1497        status, value = intersection(line0, line1)
1498        assert status == 2
1499        assert num.allclose(value, [[1,7], [7, 19]])
1500
1501        line0 = [[0,5], [10,25]]
1502        line1 = [[1,7], [7,19]]
1503        status, value = intersection(line0, line1)
1504        assert status == 2
1505        assert num.allclose(value, [[1,7], [7, 19]])
1506
1507        line0 = [[0,5], [10,25]]
1508        line1 = [[7,19], [1,7]]
1509        status, value = intersection(line0, line1)
1510        assert status == 2
1511        assert num.allclose(value, [[7, 19], [1, 7]])
1512
1513
1514    def NOtest_inside_polygon_main(self):
1515        # FIXME (Ole): Why is this disabled?
1516        #print "inside",inside
1517        #print "outside",outside
1518
1519        assert not inside_polygon((0.5, 1.5), polygon)
1520        assert not inside_polygon((0.5, -0.5), polygon)
1521        assert not inside_polygon((-0.5, 0.5), polygon)
1522        assert not inside_polygon((1.5, 0.5), polygon)
1523
1524        # Try point on borders
1525        assert inside_polygon((1., 0.5), polygon, closed=True)
1526        assert inside_polygon((0.5, 1), polygon, closed=True)
1527        assert inside_polygon((0., 0.5), polygon, closed=True)
1528        assert inside_polygon((0.5, 0.), polygon, closed=True)
1529
1530        assert not inside_polygon((0.5, 1), polygon, closed=False)
1531        assert not inside_polygon((0., 0.5), polygon, closed=False)
1532        assert not inside_polygon((0.5, 0.), polygon, closed=False)
1533        assert not inside_polygon((1., 0.5), polygon, closed=False)
1534
1535        # From real example (that failed)
1536        polygon = [[20,20], [40,20], [40,40], [20,40]]
1537        points = [[40, 50]]
1538        res = inside_polygon(points, polygon)
1539        assert len(res) == 0
1540
1541        polygon = [[20,20], [40,20], [40,40], [20,40]]
1542        points = [[25, 25], [30, 20], [40, 50], [90, 20], [40, 90]]
1543        res = inside_polygon(points, polygon)
1544        assert len(res) == 2
1545        assert num.allclose(res, [0,1])
1546
1547    def test_polygon_area(self):
1548        # Simplest case: Polygon is the unit square
1549        polygon = [[0,0], [1,0], [1,1], [0,1]]
1550        assert polygon_area(polygon) == 1
1551
1552        # Simple case: Polygon is a rectangle
1553        polygon = [[0,0], [1,0], [1,4], [0,4]]
1554        assert polygon_area(polygon) == 4
1555
1556        # Simple case: Polygon is a unit triangle
1557        polygon = [[0,0], [1,0], [0,1]]
1558        assert polygon_area(polygon) == 0.5
1559
1560        # Simple case: Polygon is a diamond
1561        polygon = [[0,0], [1,1], [2,0], [1, -1]]
1562        assert polygon_area(polygon) == 2.0
1563
1564        # Complex case where numerical errors might occur
1565        polygon = [[314037.58727982, 6224952.2960092],
1566                   [314038.58727982, 6224952.2960092],
1567                   [314038.58727982, 6224953.2960092],
1568                   [314037.58727982, 6224953.2960092]]
1569        assert polygon_area(polygon) == 1.0
1570
1571    def test_poly_xy(self):
1572        # Simplest case: Polygon is the unit square
1573        polygon = [[0,0], [1,0], [1,1], [0,1]]
1574        x, y = _poly_xy(polygon)
1575        assert len(x) == len(polygon)+1
1576        assert len(y) == len(polygon)+1
1577        assert x[0] == 0
1578        assert x[1] == 1
1579        assert x[2] == 1
1580        assert x[3] == 0
1581        assert y[0] == 0
1582        assert y[1] == 0
1583        assert y[2] == 1
1584        assert y[3] == 1
1585
1586    # Arbitrary polygon
1587        polygon = [[1,5], [1,1], [100,10], [1,10], [3,6]]
1588        x, y = _poly_xy(polygon)
1589        assert len(x) == len(polygon)+1
1590        assert len(y) == len(polygon)+1
1591        assert x[0] == 1
1592        assert x[1] == 1
1593        assert x[2] == 100
1594        assert x[3] == 1
1595        assert x[4] == 3
1596        assert y[0] == 5
1597        assert y[1] == 1
1598        assert y[2] == 10
1599        assert y[3] == 10
1600        assert y[4] == 6
1601
1602
1603    def test_plot_polygons(self):
1604        import os
1605
1606        # Simplest case: Polygon is the unit square
1607        polygon1 = [[0,0], [1,0], [1,1], [0,1]]
1608        polygon2 = [[1,1], [2,1], [3,2], [2,2]]
1609        plot_polygons([polygon1, polygon2], figname='test1')
1610
1611        # Another case
1612        polygon3 = [[1,5], [10,1], [100,10], [50,10], [3,6]]
1613        v = plot_polygons([polygon2,polygon3], figname='test2')
1614
1615        for file in ['test1.png', 'test2.png']:
1616            assert os.access(file, os.R_OK)
1617            os.remove(file)
1618
1619
1620    def test_inside_polygon_geospatial(self):
1621        #Simplest case: Polygon is the unit square
1622        polygon_absolute = [[0,0], [1,0], [1,1], [0,1]]
1623        poly_geo_ref = Geo_reference(57, 100, 100)
1624        polygon = poly_geo_ref.change_points_geo_ref(polygon_absolute)
1625        poly_spatial = Geospatial_data(polygon, geo_reference=poly_geo_ref)
1626
1627        points_absolute = (0.5, 0.5)
1628        points_geo_ref = Geo_reference(57, 78, -56)
1629        points = points_geo_ref.change_points_geo_ref(points_absolute)
1630        points_spatial = Geospatial_data(points, geo_reference=points_geo_ref)
1631
1632        assert is_inside_polygon(points_absolute, polygon_absolute)
1633        assert is_inside_polygon(ensure_numeric(points_absolute),
1634                                 ensure_numeric(polygon_absolute))
1635        assert is_inside_polygon(points_absolute, poly_spatial)
1636        assert is_inside_polygon(points_spatial, poly_spatial)
1637        assert is_inside_polygon(points_spatial, polygon_absolute)
1638
1639        assert is_inside_polygon(points_absolute, polygon_absolute)
1640
1641    def NOtest_decimate_polygon(self):
1642        polygon = [[0,0], [10,10], [15,5], [20, 10],
1643                   [25,0], [30,10], [40,-10], [35, -5]]
1644
1645        dpoly = decimate_polygon(polygon, factor=2)
1646
1647        print dpoly
1648
1649        assert len(dpoly)*2==len(polygon)
1650
1651        minx = maxx = polygon[0][0]
1652        miny = maxy = polygon[0][1]
1653        for point in polygon[1:]:
1654            x, y = point
1655
1656            if x < minx: minx = x
1657            if x > maxx: maxx = x
1658            if y < miny: miny = y
1659            if y > maxy: maxy = y
1660
1661        assert [minx, miny] in polygon
1662        print minx, maxy
1663        assert [minx, maxy] in polygon
1664        assert [maxx, miny] in polygon
1665        assert [maxx, maxy] in polygon
1666
1667    def test_interpolate_polyline(self):
1668        """test_interpolate_polyline(self):
1669
1670        This test is added under the assumption that the function
1671        interpolate_polyline implemented by John Jakeman works.
1672        It has been exercised somewhat by tests of sts boundary,
1673        but never before separately.
1674        """
1675
1676        f = num.array([58.06150614, 58.06150614, 58.06150614])
1677        vertex_coordinates = num.array([[0., 0., ],
1678                                        [4.04092634, 1106.11074699],
1679                                        [8.08836552, 2212.16910609]])
1680        gauge_neighbour_id = [1, 2, -1]
1681        point_coordinates = num.array([[2.21870766e+03, 1.09802864e+03],
1682                                       [1.62739645e+03, 2.20626983e+03],
1683                                       [5.20084967e+02, 2.21030386e+03],
1684                                       [6.06464546e+00, 1.65913993e+03],
1685                                       [1.61934862e+03, -5.88143836e+00],
1686                                       [5.11996623e+02, -1.85956061e+00],
1687                                       [2.02046270e+00, 5.53055373e+02]])
1688
1689        z_ref = [0., 0., 0., 58.06150614, 0., 0., 58.06150614]
1690
1691        z = interpolate_polyline(f, vertex_coordinates,
1692                                 gauge_neighbour_id, point_coordinates)
1693        assert num.allclose(z, z_ref)
1694
1695        # Another f
1696        f = num.array([58.06150614, 158.06150614, 258.06150614])
1697        z_ref = [0., 0., 0., 208.06150645, 0., 0., 108.0615061]
1698        z = interpolate_polyline(f, vertex_coordinates,
1699                                 gauge_neighbour_id, point_coordinates)
1700        assert num.allclose(z, z_ref)
1701
1702        # Other and simpler numbers
1703        f = num.array([1, 5, 13])
1704        vertex_coordinates = num.array([[0., 0., ],
1705                                        [4., 4.],
1706                                        [8., 8.]])
1707        point_coordinates = num.array([[0.1, 0.1],
1708                                       [3.5, 3.5],
1709                                       [4.0, 4.0],
1710                                       [5.2, 5.2],
1711                                       [7.0, 7.0],
1712                                       [8.3, 8.3]])
1713        gauge_neighbour_id = [1, 2, -1]
1714
1715        z = interpolate_polyline(f, vertex_coordinates,
1716                                 gauge_neighbour_id, point_coordinates)
1717        z_ref = [1.1, 4.5, 5., 7.4, 11., 0.]
1718        assert num.allclose(z, z_ref)
1719
1720        # Test exception thrown for one point
1721        f = num.array([5])
1722        vertex_coordinates = num.array([[4., 4.]])
1723        try:
1724            z = interpolate_polyline(f, vertex_coordinates,
1725                                     gauge_neighbour_id, point_coordinates)
1726        except Exception:
1727            pass
1728        else:
1729            raise Exception, 'One point should have raised exception'
1730
1731        # More polyline nodes
1732        data = num.array([1, 5, 13, 12, 6, 29])
1733        polyline_nodes = num.array([[0., 0.],
1734                                    [4., 4.],
1735                                    [8., 8.],
1736                                    [10., 10.],
1737                                    [10., 5.],
1738                                    [10., 0.]])
1739        point_coordinates = num.array([[0.1, 0.1],
1740                                       [3.5, 3.5],
1741                                       [4.0, 4.0],
1742                                       [5.2, 5.2],
1743                                       [7.0, 7.0],
1744                                       [8.3, 8.3],
1745                                       [10., 10.],
1746                                       [10., 9.],
1747                                       [10., 7.1],
1748                                       [10., 4.3],
1749                                       [10., 1.0]])
1750        gauge_neighbour_id = [1, 2, 3, 4, 5, -1]
1751        z = interpolate_polyline(data, polyline_nodes,
1752                                 gauge_neighbour_id, point_coordinates)
1753        z_ref = [1.1, 4.5, 5., 7.4, 11., 12.85, 12., 10.8, 8.52, 9.22, 24.4]
1754        assert num.allclose(z, z_ref)
1755
1756
1757    def test_is_inside_triangle_more(self):
1758
1759        res = is_inside_triangle([0.5, 0.5], [[ 0.5,  0. ],
1760                                              [ 0.5,  0.5],
1761                                              [ 0.,   0. ]])
1762        assert res is True
1763
1764        res = is_inside_triangle([0.59999999999999998, 0.29999999999999999],
1765                                 [[ 0.5,  0. ], [ 0.5, 0.5], [0., 0.]])
1766        assert res is False
1767
1768        res = is_inside_triangle([0.59999999999999998, 0.29999999999999999],
1769                                 [[1., 0.], [1., 0.5], [0.5, 0.]])
1770        assert res is False
1771
1772
1773        res = is_inside_triangle([0.59999999999999998, 0.29999999999999999],
1774                                 [[0.5, 0.5], [0.5, 0.], [1., 0.5]])
1775        assert res is True
1776
1777
1778        res = is_inside_triangle([0.10000000000000001, 0.20000000000000001],
1779                                 [[0.5, 0.], [0.5, 0.5], [0., 0.]])
1780        assert res is False
1781
1782
1783        res = is_inside_triangle([0.10000000000000001, 0.20000000000000001],
1784                                 [[0., 0.5], [0., 0.], [0.5, 0.5]])
1785        assert res is True
1786
1787        res = is_inside_triangle([0.69999999999999996, 0.69999999999999996],
1788                                 [[0.5, 0.], [0.5, 0.5], [0., 0.]])
1789        assert res is False
1790
1791        res = is_inside_triangle([0.59999999999999998, 0.29999999999999999],
1792                                 [[0.25, 0.5], [0.25, 0.25], [0.5, 0.5]])
1793        assert res is False
1794
1795
1796        res = is_inside_triangle([10, 3],
1797                                 [[0.1, 0.],
1798                                  [0.1, 0.08333333],
1799                                  [0., 0.]])
1800        assert res is False
1801
1802       
1803    def test_is_polygon_complex(self):
1804        """Test a concave and a complex poly with is_complex, to make sure it can detect
1805           self-intersection.
1806        """
1807        concave_poly = [[0, 0], [10, 0], [5, 5], [10, 10], [0, 10]]
1808        complex_poly = [[0, 0], [10, 0], [5, 5], [4, 15], [5, 7], [10, 10], [0, 10]]
1809
1810        assert not is_complex(concave_poly)
1811        assert is_complex(complex_poly)
1812
1813    def test_is_polygon_complex2(self):
1814        """Test a concave and a complex poly with is_complex, to make sure it can detect
1815           self-intersection. This test uses more complicated polygons.
1816        """   
1817        concave_poly = [[0, 0], [10, 0], [11,0], [5, 5], [7,6], [10, 10], [1,5], [0, 10]]
1818        complex_poly = [[0, 0], [12,12], [10, 0], [5, 5], [3,18], [4, 15], [5, 7], [10, 10], [0, 10], [16, 12]]       
1819
1820        assert not is_complex(concave_poly)
1821        assert is_complex(complex_poly)
1822       
1823################################################################################
1824
1825if __name__ == "__main__":
1826    suite = unittest.makeSuite(Test_Polygon,'test')
1827    runner = unittest.TextTestRunner()
1828    runner.run(suite)
Note: See TracBrowser for help on using the repository browser.