1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
|
import unittest
from math import pi
import numpy as np
import pytest
from shapely import affinity
from shapely.geometry import Point
from shapely.wkt import loads as load_wkt
class AffineTestCase(unittest.TestCase):
def test_affine_params(self):
g = load_wkt("LINESTRING(2.4 4.1, 2.4 3, 3 3)")
with pytest.raises(TypeError):
affinity.affine_transform(g, None)
with pytest.raises(ValueError):
affinity.affine_transform(g, [1, 2, 3, 4, 5, 6, 7, 8, 9])
with pytest.raises(AttributeError):
affinity.affine_transform(None, [1, 2, 3, 4, 5, 6])
def test_affine_geom_types(self):
# identity matrices, which should result with no transformation
matrix2d = (1, 0, 0, 1, 0, 0)
matrix3d = (1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
# empty in, empty out
empty2d = load_wkt("MULTIPOLYGON EMPTY")
assert affinity.affine_transform(empty2d, matrix2d).is_empty
def test_geom(g2, g3=None):
assert not g2.has_z
a2 = affinity.affine_transform(g2, matrix2d)
assert not a2.has_z
assert g2.equals(a2)
if g3 is not None:
assert g3.has_z
a3 = affinity.affine_transform(g3, matrix3d)
assert a3.has_z
assert g3.equals(a3)
pt2d = load_wkt("POINT(12.3 45.6)")
pt3d = load_wkt("POINT(12.3 45.6 7.89)")
test_geom(pt2d, pt3d)
ls2d = load_wkt("LINESTRING(0.9 3.4, 0.7 2, 2.5 2.7)")
ls3d = load_wkt("LINESTRING(0.9 3.4 3.3, 0.7 2 2.3, 2.5 2.7 5.5)")
test_geom(ls2d, ls3d)
lr2d = load_wkt("LINEARRING(0.9 3.4, 0.7 2, 2.5 2.7, 0.9 3.4)")
lr3d = load_wkt("LINEARRING(0.9 3.4 3.3, 0.7 2 2.3, 2.5 2.7 5.5, 0.9 3.4 3.3)")
test_geom(lr2d, lr3d)
test_geom(
load_wkt(
"POLYGON((0.9 2.3, 0.5 1.1, 2.4 0.8, 0.9 2.3), "
"(1.1 1.7, 0.9 1.3, 1.4 1.2, 1.1 1.7), "
"(1.6 1.3, 1.7 1, 1.9 1.1, 1.6 1.3))"
)
)
test_geom(
load_wkt("MULTIPOINT ((-300 300), (700 300), (-800 -1100), (200 -300))")
)
test_geom(
load_wkt(
"MULTILINESTRING((0 0, -0.7 -0.7, 0.6 -1), (-0.5 0.5, 0.7 0.6, 0 -0.6))"
)
)
test_geom(
load_wkt(
"MULTIPOLYGON(((900 4300, -1100 -400, 900 -800, 900 4300)), "
"((1200 4300, 2300 4400, 1900 1000, 1200 4300)))"
)
)
test_geom(
load_wkt(
"GEOMETRYCOLLECTION(POINT(20 70),"
" POLYGON((60 70, 13 35, 60 -30, 60 70)),"
" LINESTRING(60 70, 50 100, 80 100))"
)
)
def test_affine_2d(self):
g = load_wkt("LINESTRING(2.4 4.1, 2.4 3, 3 3)")
# custom scale and translate
expected2d = load_wkt("LINESTRING(-0.2 14.35, -0.2 11.6, 1 11.6)")
matrix2d = (2, 0, 0, 2.5, -5, 4.1)
a2 = affinity.affine_transform(g, matrix2d)
assert a2.equals_exact(expected2d, 1e-6)
assert not a2.has_z
# Make sure a 3D matrix does not make a 3D shape from a 2D input
matrix3d = (2, 0, 0, 0, 2.5, 0, 0, 0, 10, -5, 4.1, 100)
a3 = affinity.affine_transform(g, matrix3d)
assert a3.equals_exact(expected2d, 1e-6)
assert not a3.has_z
def test_affine_3d(self):
g2 = load_wkt("LINESTRING(2.4 4.1, 2.4 3, 3 3)")
g3 = load_wkt("LINESTRING(2.4 4.1 100.2, 2.4 3 132.8, 3 3 128.6)")
# custom scale and translate
matrix2d = (2, 0, 0, 2.5, -5, 4.1)
matrix3d = (2, 0, 0, 0, 2.5, 0, 0, 0, 0.3048, -5, 4.1, 100)
# Combinations of 2D and 3D geometries and matrices
a22 = affinity.affine_transform(g2, matrix2d)
a23 = affinity.affine_transform(g2, matrix3d)
a32 = affinity.affine_transform(g3, matrix2d)
a33 = affinity.affine_transform(g3, matrix3d)
# Check dimensions
assert not a22.has_z
assert not a23.has_z
assert a32.has_z
assert a33.has_z
# 2D equality checks
expected2d = load_wkt("LINESTRING(-0.2 14.35, -0.2 11.6, 1 11.6)")
expected3d = load_wkt(
"LINESTRING(-0.2 14.35 130.54096, -0.2 11.6 140.47744, 1 11.6 139.19728)"
)
expected32 = load_wkt(
"LINESTRING(-0.2 14.35 100.2, -0.2 11.6 132.8, 1 11.6 128.6)"
)
assert a22.equals_exact(expected2d, 1e-6)
assert a23.equals_exact(expected2d, 1e-6)
# Do explicit 3D check of coordinate values
for a, e in zip(a32.coords, expected32.coords):
for ap, ep in zip(a, e):
self.assertAlmostEqual(ap, ep)
for a, e in zip(a33.coords, expected3d.coords):
for ap, ep in zip(a, e):
self.assertAlmostEqual(ap, ep)
class TransformOpsTestCase(unittest.TestCase):
def test_rotate(self):
ls = load_wkt("LINESTRING(240 400, 240 300, 300 300)")
# counter-clockwise degrees
rls = affinity.rotate(ls, 90)
els = load_wkt("LINESTRING(220 320, 320 320, 320 380)")
assert rls.equals(els)
# retest with named parameters for the same result
rls = affinity.rotate(geom=ls, angle=90, origin="center")
assert rls.equals(els)
# clockwise radians
rls = affinity.rotate(ls, -pi / 2, use_radians=True)
els = load_wkt("LINESTRING(320 380, 220 380, 220 320)")
assert rls.equals(els)
## other `origin` parameters
# around the centroid
rls = affinity.rotate(ls, 90, origin="centroid")
els = load_wkt("LINESTRING(182.5 320, 282.5 320, 282.5 380)")
assert rls.equals(els)
# around the second coordinate tuple
rls = affinity.rotate(ls, 90, origin=ls.coords[1])
els = load_wkt("LINESTRING(140 300, 240 300, 240 360)")
assert rls.equals(els)
# around the absolute Point of origin
rls = affinity.rotate(ls, 90, origin=Point(0, 0))
els = load_wkt("LINESTRING(-400 240, -300 240, -300 300)")
assert rls.equals(els)
def test_rotate_empty(self):
rls = affinity.rotate(load_wkt("LINESTRING EMPTY"), 90)
els = load_wkt("LINESTRING EMPTY")
assert rls.equals(els)
def test_rotate_angle_array(self):
ls = load_wkt("LINESTRING(240 400, 240 300, 300 300)")
els = load_wkt("LINESTRING(220 320, 320 320, 320 380)")
# check with degrees
theta = np.array(90.0)
rls = affinity.rotate(ls, theta)
assert theta.item() == 90.0
assert rls.equals(els)
# check with radians
theta = np.array(pi / 2)
rls = affinity.rotate(ls, theta, use_radians=True)
assert theta.item() == pi / 2
assert rls.equals(els)
def test_scale(self):
ls = load_wkt("LINESTRING(240 400 10, 240 300 30, 300 300 20)")
# test defaults of 1.0
sls = affinity.scale(ls)
assert sls.equals(ls)
# different scaling in different dimensions
sls = affinity.scale(ls, 2, 3, 0.5)
els = load_wkt("LINESTRING(210 500 5, 210 200 15, 330 200 10)")
assert sls.equals(els)
# Do explicit 3D check of coordinate values
for a, b in zip(sls.coords, els.coords):
for ap, bp in zip(a, b):
self.assertEqual(ap, bp)
# retest with named parameters for the same result
sls = affinity.scale(geom=ls, xfact=2, yfact=3, zfact=0.5, origin="center")
assert sls.equals(els)
## other `origin` parameters
# around the centroid
sls = affinity.scale(ls, 2, 3, 0.5, origin="centroid")
els = load_wkt("LINESTRING(228.75 537.5, 228.75 237.5, 348.75 237.5)")
assert sls.equals(els)
# around the second coordinate tuple
sls = affinity.scale(ls, 2, 3, 0.5, origin=ls.coords[1])
els = load_wkt("LINESTRING(240 600, 240 300, 360 300)")
assert sls.equals(els)
# around some other 3D Point of origin
sls = affinity.scale(ls, 2, 3, 0.5, origin=Point(100, 200, 1000))
els = load_wkt("LINESTRING(380 800 505, 380 500 515, 500 500 510)")
assert sls.equals(els)
# Do explicit 3D check of coordinate values
for a, b in zip(sls.coords, els.coords):
for ap, bp in zip(a, b):
assert ap == bp
def test_scale_empty(self):
sls = affinity.scale(load_wkt("LINESTRING EMPTY"))
els = load_wkt("LINESTRING EMPTY")
assert sls.equals(els)
def test_skew(self):
ls = load_wkt("LINESTRING(240 400 10, 240 300 30, 300 300 20)")
# test default shear angles of 0.0
sls = affinity.skew(ls)
assert sls.equals(ls)
# different shearing in x- and y-directions
sls = affinity.skew(ls, 15, -30)
els = load_wkt(
"LINESTRING (253.39745962155615 417.3205080756888, "
"226.60254037844385 317.3205080756888, "
"286.60254037844385 282.67949192431126)"
)
assert sls.equals_exact(els, 1e-6)
# retest with radians for the same result
sls = affinity.skew(ls, pi / 12, -pi / 6, use_radians=True)
assert sls.equals_exact(els, 1e-6)
# retest with named parameters for the same result
sls = affinity.skew(geom=ls, xs=15, ys=-30, origin="center", use_radians=False)
assert sls.equals_exact(els, 1e-6)
## other `origin` parameters
# around the centroid
sls = affinity.skew(ls, 15, -30, origin="centroid")
els = load_wkt(
"LINESTRING(258.42150697963973 406.49519052838332, "
"231.6265877365273980 306.4951905283833185, "
"291.6265877365274264 271.8541743770057337)"
)
assert sls.equals_exact(els, 1e-6)
# around the second coordinate tuple
sls = affinity.skew(ls, 15, -30, origin=ls.coords[1])
els = load_wkt(
"LINESTRING(266.7949192431123038 400, 240 300, 300 265.3589838486224153)"
)
assert sls.equals_exact(els, 1e-6)
# around the absolute Point of origin
sls = affinity.skew(ls, 15, -30, origin=Point(0, 0))
els = load_wkt(
"LINESTRING(347.179676972449101 261.435935394489832, "
"320.3847577293367976 161.4359353944898317, "
"380.3847577293367976 126.7949192431122754)"
)
assert sls.equals_exact(els, 1e-6)
def test_skew_empty(self):
sls = affinity.skew(load_wkt("LINESTRING EMPTY"))
els = load_wkt("LINESTRING EMPTY")
assert sls.equals(els)
def test_skew_xs_ys_array(self):
ls = load_wkt("LINESTRING(240 400 10, 240 300 30, 300 300 20)")
els = load_wkt(
"LINESTRING (253.39745962155615 417.3205080756888, "
"226.60254037844385 317.3205080756888, "
"286.60254037844385 282.67949192431126)"
)
# check with degrees
xs_ys = np.array([15.0, -30.0])
sls = affinity.skew(ls, xs_ys[0, ...], xs_ys[1, ...])
assert xs_ys[0] == 15.0
assert xs_ys[1] == -30.0
assert sls.equals_exact(els, 1e-6)
# check with radians
xs_ys = np.array([pi / 12, -pi / 6])
sls = affinity.skew(ls, xs_ys[0, ...], xs_ys[1, ...], use_radians=True)
assert xs_ys[0] == pi / 12
assert xs_ys[1] == -pi / 6
assert sls.equals_exact(els, 1e-6)
def test_translate(self):
ls = load_wkt("LINESTRING(240 400 10, 240 300 30, 300 300 20)")
# test default offset of 0.0
tls = affinity.translate(ls)
assert tls.equals(ls)
# test all offsets
tls = affinity.translate(ls, 100, 400, -10)
els = load_wkt("LINESTRING(340 800 0, 340 700 20, 400 700 10)")
assert tls.equals(els)
# Do explicit 3D check of coordinate values
for a, b in zip(tls.coords, els.coords):
for ap, bp in zip(a, b):
assert ap == bp
# retest with named parameters for the same result
tls = affinity.translate(geom=ls, xoff=100, yoff=400, zoff=-10)
assert tls.equals(els)
def test_translate_empty(self):
tls = affinity.translate(load_wkt("LINESTRING EMPTY"))
els = load_wkt("LINESTRING EMPTY")
self.assertTrue(tls.equals(els))
assert tls.equals(els)
|