Repository URL to install this package:
|
Version:
0.19.0.post1 ▾
|
# Copyright Cartopy Contributors
#
# This file is part of Cartopy and is released under the LGPL license.
# See COPYING and COPYING.LESSER in the root of the repository for full
# licensing details.
import itertools
import time
import numpy as np
import pytest
import shapely.geometry as sgeom
import cartopy.crs as ccrs
class TestLineString:
def test_out_of_bounds(self):
# Check that a line that is completely out of the map boundary produces
# a valid LineString
projection = ccrs.TransverseMercator(central_longitude=0, approx=True)
# For both start & end, define a point that results in well-defined
# projection coordinates and one that results in NaN.
start_points = [(86, 0), (130, 0)]
end_points = [(88, 0), (120, 0)]
# Try all four combinations of valid/NaN vs valid/NaN.
for start, end in itertools.product(start_points, end_points):
line_string = sgeom.LineString([start, end])
multi_line_string = projection.project_geometry(line_string)
if start[0] == 130 and end[0] == 120:
expected = 0
else:
expected = 1
assert len(multi_line_string) == expected, \
'Unexpected line when working from {} to {}'.format(start, end)
def test_simple_fragment_count(self):
projection = ccrs.PlateCarree()
tests = [
([(150, 0), (-150, 0)], 2),
([(10, 0), (90, 0), (180, 0), (-90, 0), (-10, 0)], 2),
([(-10, 0), (10, 0)], 1),
([(-45, 0), (45, 30)], 1),
]
for coords, pieces in tests:
line_string = sgeom.LineString(coords)
multi_line_string = projection.project_geometry(line_string)
# from cartopy.tests.mpl import show
# show(projection, multi_line_string)
assert len(multi_line_string) == pieces
def test_split(self):
projection = ccrs.Robinson(170.5)
line_string = sgeom.LineString([(-10, 30), (10, 60)])
multi_line_string = projection.project_geometry(line_string)
# from cartopy.tests.mpl import show
# show(projection, multi_line_string)
assert len(multi_line_string) == 2
def test_out_of_domain_efficiency(self):
# Check we're efficiently dealing with lines that project
# outside the map domain.
# Because the south pole projects to an *enormous* circle
# (radius ~ 1e23) this will take a *long* time to project if the
# within-domain exactness criteria are used.
line_string = sgeom.LineString([(0, -90), (2, -90)])
tgt_proj = ccrs.NorthPolarStereo()
src_proj = ccrs.PlateCarree()
cutoff_time = time.time() + 1
tgt_proj.project_geometry(line_string, src_proj)
assert time.time() < cutoff_time, 'Projection took too long'
class FakeProjection(ccrs.PlateCarree):
def __init__(self, left_offset=0, right_offset=0):
self.left_offset = left_offset
self.right_offset = right_offset
self._half_width = 180
self._half_height = 90
ccrs.PlateCarree.__init__(self)
@property
def boundary(self):
# XXX Should this be a LinearRing?
w, h = self._half_width, self._half_height
return sgeom.LineString([(-w + self.left_offset, -h),
(-w + self.left_offset, h),
(w - self.right_offset, h),
(w - self.right_offset, -h),
(-w + self.left_offset, -h)])
class TestBisect:
# A bunch of tests to check the bisection algorithm is robust for a
# variety of simple and/or pathological cases.
def test_repeated_point(self):
projection = FakeProjection()
line_string = sgeom.LineString([(10, 0), (10, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
def test_interior_repeated_point(self):
projection = FakeProjection()
line_string = sgeom.LineString([(0, 0), (10, 0), (10, 0), (20, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 4
def test_circular_repeated_point(self):
projection = FakeProjection()
line_string = sgeom.LineString([(0, 0), (360, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
def test_short(self):
projection = FakeProjection()
line_string = sgeom.LineString([(0, 0), (1e-12, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
def test_empty(self):
projection = FakeProjection(right_offset=10)
line_string = sgeom.LineString([(175, 0), (175, 10)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 0
def test_simple_run_in(self):
projection = FakeProjection(right_offset=10)
line_string = sgeom.LineString([(160, 0), (175, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
def test_simple_wrap(self):
projection = FakeProjection()
line_string = sgeom.LineString([(160, 0), (-160, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 2
assert len(multi_line_string[0].coords) == 2
assert len(multi_line_string[1].coords) == 2
def test_simple_run_out(self):
projection = FakeProjection(left_offset=10)
line_string = sgeom.LineString([(-175, 0), (-160, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
def test_point_on_boundary(self):
projection = FakeProjection()
line_string = sgeom.LineString([(180, 0), (-160, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
# Add a small offset to the left-hand boundary to make things
# even more pathological.
projection = FakeProjection(left_offset=5)
line_string = sgeom.LineString([(180, 0), (-160, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
def test_nan_start(self):
projection = ccrs.TransverseMercator(central_longitude=-90,
approx=False)
line_string = sgeom.LineString([(10, 50), (-10, 30)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
for line_string in multi_line_string:
for coord in line_string.coords:
assert not any(np.isnan(coord)), \
'Unexpected NaN in projected coords.'
def test_nan_end(self):
projection = ccrs.TransverseMercator(central_longitude=-90,
approx=False)
line_string = sgeom.LineString([(-10, 30), (10, 50)])
multi_line_string = projection.project_geometry(line_string)
# from cartopy.tests.mpl import show
# show(projection, multi_line_string)
assert len(multi_line_string) == 1
for line_string in multi_line_string:
for coord in line_string.coords:
assert not any(np.isnan(coord)), \
'Unexpected NaN in projected coords.'
class TestMisc:
def test_misc(self):
projection = ccrs.TransverseMercator(central_longitude=-90,
approx=False)
line_string = sgeom.LineString([(10, 50), (-10, 30)])
multi_line_string = projection.project_geometry(line_string)
# from cartopy.tests.mpl import show
# show(projection, multi_line_string)
for line_string in multi_line_string:
for coord in line_string.coords:
assert not any(np.isnan(coord)), \
'Unexpected NaN in projected coords.'
def test_something(self):
projection = ccrs.RotatedPole(pole_longitude=177.5,
pole_latitude=37.5)
line_string = sgeom.LineString([(0, 0), (1e-14, 0)])
multi_line_string = projection.project_geometry(line_string)
assert len(multi_line_string) == 1
assert len(multi_line_string[0].coords) == 2
def test_global_boundary(self):
linear_ring = sgeom.LineString([(-180, -180), (-180, 180),
(180, 180), (180, -180)])
pc = ccrs.PlateCarree()
merc = ccrs.Mercator()
multi_line_string = pc.project_geometry(linear_ring, merc)
assert len(multi_line_string) > 0
# check the identity transform
multi_line_string = merc.project_geometry(linear_ring, merc)
assert len(multi_line_string) > 0
class TestSymmetry:
@pytest.mark.xfail
def test_curve(self):
# Obtain a simple, curved path.
projection = ccrs.PlateCarree()
coords = [(-0.08, 51.53), (132.00, 43.17)] # London to Vladivostock
line_string = sgeom.LineString(coords)
multi_line_string = projection.project_geometry(line_string)
# Compute the reverse path.
line_string = sgeom.LineString(coords[::-1])
multi_line_string2 = projection.project_geometry(line_string)
# Make sure that they generated the same points.
# (Although obviously they will be in the opposite order!)
assert len(multi_line_string) == 1
assert len(multi_line_string2) == 1
coords = multi_line_string[0].coords
coords2 = multi_line_string2[0].coords
np.testing.assert_allclose(coords, coords2[::-1],
err_msg='Asymmetric curve generation')