test_srs.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. from unittest import skipIf
  2. from django.contrib.gis.gdal import (
  3. GDAL_VERSION, AxisOrder, CoordTransform, GDALException, SpatialReference,
  4. SRSException,
  5. )
  6. from django.contrib.gis.geos import GEOSGeometry
  7. from django.test import SimpleTestCase
  8. class TestSRS:
  9. def __init__(self, wkt, **kwargs):
  10. self.wkt = wkt
  11. for key, value in kwargs.items():
  12. setattr(self, key, value)
  13. WGS84_proj = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs '
  14. # Some Spatial Reference examples
  15. srlist = (
  16. TestSRS(
  17. 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,'
  18. 'AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],'
  19. 'PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",'
  20. '0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],'
  21. 'AXIS["Longitude",EAST],AUTHORITY["EPSG","4326"]]',
  22. epsg=4326, projected=False, geographic=True, local=False,
  23. lin_name='unknown', ang_name='degree', lin_units=1.0, ang_units=0.0174532925199,
  24. auth={'GEOGCS': ('EPSG', '4326'), 'spheroid': ('EPSG', '7030')},
  25. attr=(('DATUM', 'WGS_1984'), (('SPHEROID', 1), '6378137'), ('primem|authority', 'EPSG'),),
  26. ),
  27. TestSRS(
  28. 'PROJCS["NAD83 / Texas South Central",GEOGCS["NAD83",DATUM["North_American_Datum_1983",'
  29. 'SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],'
  30. 'AUTHORITY["EPSG","6269"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],'
  31. 'UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],'
  32. 'AUTHORITY["EPSG","4269"]],PROJECTION["Lambert_Conformal_Conic_2SP"],'
  33. 'PARAMETER["standard_parallel_1",30.2833333333333],'
  34. 'PARAMETER["standard_parallel_2",28.3833333333333],'
  35. 'PARAMETER["latitude_of_origin",27.8333333333333],'
  36. 'PARAMETER["central_meridian",-99],PARAMETER["false_easting",600000],'
  37. 'PARAMETER["false_northing",4000000],UNIT["metre",1,AUTHORITY["EPSG","9001"]],'
  38. 'AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","32140"]]',
  39. epsg=32140, projected=True, geographic=False, local=False,
  40. lin_name='metre', ang_name='degree', lin_units=1.0, ang_units=0.0174532925199,
  41. auth={'PROJCS': ('EPSG', '32140'), 'spheroid': ('EPSG', '7019'), 'unit': ('EPSG', '9001')},
  42. attr=(
  43. ('DATUM', 'North_American_Datum_1983'),
  44. (('SPHEROID', 2), '298.257222101'),
  45. ('PROJECTION', 'Lambert_Conformal_Conic_2SP'),
  46. ),
  47. ),
  48. TestSRS(
  49. 'PROJCS["NAD83 / Texas South Central (ftUS)",'
  50. 'GEOGCS["NAD83",DATUM["North_American_Datum_1983",'
  51. 'SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],AUTHORITY["EPSG","6269"]],'
  52. 'PRIMEM["Greenwich",0],'
  53. 'UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic_2SP"],'
  54. 'PARAMETER["false_easting",1968500],PARAMETER["false_northing",13123333.3333333],'
  55. 'PARAMETER["central_meridian",-99],PARAMETER["standard_parallel_1",28.3833333333333],'
  56. 'PARAMETER["standard_parallel_2",30.2833333333333],PARAMETER["latitude_of_origin",27.8333333333333],'
  57. 'UNIT["US survey foot",0.304800609601219],AXIS["Easting",EAST],AXIS["Northing",NORTH]]',
  58. epsg=None, projected=True, geographic=False, local=False,
  59. lin_name='US survey foot', ang_name='Degree', lin_units=0.3048006096012192, ang_units=0.0174532925199,
  60. auth={'PROJCS': (None, None)},
  61. attr=(('PROJCS|GeOgCs|spheroid', 'GRS 1980'), (('projcs', 9), 'UNIT'), (('projcs', 11), 'AXIS'),),
  62. ),
  63. # This is really ESRI format, not WKT -- but the import should work the same
  64. TestSRS(
  65. 'LOCAL_CS["Non-Earth (Meter)",LOCAL_DATUM["Local Datum",32767],'
  66. 'UNIT["Meter",1],AXIS["X",EAST],AXIS["Y",NORTH]]',
  67. esri=True, epsg=None, projected=False, geographic=False, local=True,
  68. lin_name='Meter', ang_name='degree', lin_units=1.0, ang_units=0.0174532925199,
  69. attr=(('LOCAL_DATUM', 'Local Datum'),),
  70. ),
  71. )
  72. # Well-Known Names
  73. well_known = (
  74. TestSRS(
  75. 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,'
  76. 'AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],'
  77. 'PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,'
  78. 'AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]',
  79. wk='WGS84', name='WGS 84',
  80. attrs=(('GEOGCS|AUTHORITY', 1, '4326'), ('SPHEROID', 'WGS 84')),
  81. ),
  82. TestSRS(
  83. 'GEOGCS["WGS 72",DATUM["WGS_1972",SPHEROID["WGS 72",6378135,298.26,'
  84. 'AUTHORITY["EPSG","7043"]],AUTHORITY["EPSG","6322"]],'
  85. 'PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],'
  86. 'UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],'
  87. 'AUTHORITY["EPSG","4322"]]',
  88. wk='WGS72', name='WGS 72',
  89. attrs=(('GEOGCS|AUTHORITY', 1, '4322'), ('SPHEROID', 'WGS 72')),
  90. ),
  91. TestSRS(
  92. 'GEOGCS["NAD27",DATUM["North_American_Datum_1927",'
  93. 'SPHEROID["Clarke 1866",6378206.4,294.9786982138982,'
  94. 'AUTHORITY["EPSG","7008"]],AUTHORITY["EPSG","6267"]],'
  95. 'PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],'
  96. 'UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],'
  97. 'AUTHORITY["EPSG","4267"]]',
  98. wk='NAD27', name='NAD27',
  99. attrs=(('GEOGCS|AUTHORITY', 1, '4267'), ('SPHEROID', 'Clarke 1866'))
  100. ),
  101. TestSRS(
  102. 'GEOGCS["NAD83",DATUM["North_American_Datum_1983",'
  103. 'SPHEROID["GRS 1980",6378137,298.257222101,'
  104. 'AUTHORITY["EPSG","7019"]],AUTHORITY["EPSG","6269"]],'
  105. 'PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],'
  106. 'UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],'
  107. 'AUTHORITY["EPSG","4269"]]',
  108. wk='NAD83', name='NAD83',
  109. attrs=(('GEOGCS|AUTHORITY', 1, '4269'), ('SPHEROID', 'GRS 1980')),
  110. ),
  111. TestSRS(
  112. 'PROJCS["NZGD49 / Karamea Circuit",GEOGCS["NZGD49",'
  113. 'DATUM["New_Zealand_Geodetic_Datum_1949",'
  114. 'SPHEROID["International 1924",6378388,297,'
  115. 'AUTHORITY["EPSG","7022"]],'
  116. 'TOWGS84[59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993],'
  117. 'AUTHORITY["EPSG","6272"]],PRIMEM["Greenwich",0,'
  118. 'AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,'
  119. 'AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4272"]],'
  120. 'PROJECTION["Transverse_Mercator"],'
  121. 'PARAMETER["latitude_of_origin",-41.28991152777778],'
  122. 'PARAMETER["central_meridian",172.1090281944444],'
  123. 'PARAMETER["scale_factor",1],PARAMETER["false_easting",300000],'
  124. 'PARAMETER["false_northing",700000],'
  125. 'UNIT["metre",1,AUTHORITY["EPSG","9001"]],AUTHORITY["EPSG","27216"]]',
  126. wk='EPSG:27216', name='NZGD49 / Karamea Circuit',
  127. attrs=(('PROJECTION', 'Transverse_Mercator'), ('SPHEROID', 'International 1924')),
  128. ),
  129. )
  130. bad_srlist = (
  131. 'Foobar',
  132. 'OOJCS["NAD83 / Texas South Central",GEOGCS["NAD83",'
  133. 'DATUM["North_American_Datum_1983",'
  134. 'SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],'
  135. 'AUTHORITY["EPSG","6269"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],'
  136. 'UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],'
  137. 'AUTHORITY["EPSG","4269"]],PROJECTION["Lambert_Conformal_Conic_2SP"],'
  138. 'PARAMETER["standard_parallel_1",30.28333333333333],'
  139. 'PARAMETER["standard_parallel_2",28.38333333333333],'
  140. 'PARAMETER["latitude_of_origin",27.83333333333333],'
  141. 'PARAMETER["central_meridian",-99],PARAMETER["false_easting",600000],'
  142. 'PARAMETER["false_northing",4000000],UNIT["metre",1,'
  143. 'AUTHORITY["EPSG","9001"]],AUTHORITY["EPSG","32140"]]',
  144. )
  145. class SpatialRefTest(SimpleTestCase):
  146. def test01_wkt(self):
  147. "Testing initialization on valid OGC WKT."
  148. for s in srlist:
  149. SpatialReference(s.wkt)
  150. def test02_bad_wkt(self):
  151. "Testing initialization on invalid WKT."
  152. for bad in bad_srlist:
  153. try:
  154. srs = SpatialReference(bad)
  155. srs.validate()
  156. except (SRSException, GDALException):
  157. pass
  158. else:
  159. self.fail('Should not have initialized on bad WKT "%s"!')
  160. def test03_get_wkt(self):
  161. "Testing getting the WKT."
  162. for s in srlist:
  163. srs = SpatialReference(s.wkt)
  164. # GDAL 3 strips UNIT part in the last occurrence.
  165. self.assertEqual(
  166. s.wkt.replace(',UNIT["Meter",1]', ''),
  167. srs.wkt.replace(',UNIT["Meter",1]', ''),
  168. )
  169. def test04_proj(self):
  170. """PROJ import and export."""
  171. proj_parts = [
  172. '+proj=longlat', '+ellps=WGS84', '+towgs84=0,0,0,0,0,0,0', '+datum=WGS84', '+no_defs'
  173. ]
  174. srs1 = SpatialReference(srlist[0].wkt)
  175. srs2 = SpatialReference(WGS84_proj)
  176. self.assertTrue(all(part in proj_parts for part in srs1.proj.split()))
  177. self.assertTrue(all(part in proj_parts for part in srs2.proj.split()))
  178. def test05_epsg(self):
  179. "Test EPSG import."
  180. for s in srlist:
  181. if s.epsg:
  182. srs1 = SpatialReference(s.wkt)
  183. srs2 = SpatialReference(s.epsg)
  184. srs3 = SpatialReference(str(s.epsg))
  185. srs4 = SpatialReference('EPSG:%d' % s.epsg)
  186. for srs in (srs1, srs2, srs3, srs4):
  187. for attr, expected in s.attr:
  188. self.assertEqual(expected, srs[attr])
  189. def test07_boolean_props(self):
  190. "Testing the boolean properties."
  191. for s in srlist:
  192. srs = SpatialReference(s.wkt)
  193. self.assertEqual(s.projected, srs.projected)
  194. self.assertEqual(s.geographic, srs.geographic)
  195. def test08_angular_linear(self):
  196. "Testing the linear and angular units routines."
  197. for s in srlist:
  198. srs = SpatialReference(s.wkt)
  199. self.assertEqual(s.ang_name, srs.angular_name)
  200. self.assertEqual(s.lin_name, srs.linear_name)
  201. self.assertAlmostEqual(s.ang_units, srs.angular_units, 9)
  202. self.assertAlmostEqual(s.lin_units, srs.linear_units, 9)
  203. def test09_authority(self):
  204. "Testing the authority name & code routines."
  205. for s in srlist:
  206. if hasattr(s, 'auth'):
  207. srs = SpatialReference(s.wkt)
  208. for target, tup in s.auth.items():
  209. self.assertEqual(tup[0], srs.auth_name(target))
  210. self.assertEqual(tup[1], srs.auth_code(target))
  211. def test10_attributes(self):
  212. "Testing the attribute retrieval routines."
  213. for s in srlist:
  214. srs = SpatialReference(s.wkt)
  215. for tup in s.attr:
  216. att = tup[0] # Attribute to test
  217. exp = tup[1] # Expected result
  218. self.assertEqual(exp, srs[att])
  219. def test11_wellknown(self):
  220. "Testing Well Known Names of Spatial References."
  221. for s in well_known:
  222. srs = SpatialReference(s.wk)
  223. self.assertEqual(s.name, srs.name)
  224. for tup in s.attrs:
  225. if len(tup) == 2:
  226. key = tup[0]
  227. exp = tup[1]
  228. elif len(tup) == 3:
  229. key = tup[:2]
  230. exp = tup[2]
  231. self.assertEqual(srs[key], exp)
  232. def test12_coordtransform(self):
  233. "Testing initialization of a CoordTransform."
  234. target = SpatialReference('WGS84')
  235. CoordTransform(SpatialReference(srlist[0].wkt), target)
  236. def test13_attr_value(self):
  237. "Testing the attr_value() method."
  238. s1 = SpatialReference('WGS84')
  239. with self.assertRaises(TypeError):
  240. s1.__getitem__(0)
  241. with self.assertRaises(TypeError):
  242. s1.__getitem__(('GEOGCS', 'foo'))
  243. self.assertEqual('WGS 84', s1['GEOGCS'])
  244. self.assertEqual('WGS_1984', s1['DATUM'])
  245. self.assertEqual('EPSG', s1['AUTHORITY'])
  246. self.assertEqual(4326, int(s1['AUTHORITY', 1]))
  247. self.assertIsNone(s1['FOOBAR'])
  248. def test_unicode(self):
  249. wkt = (
  250. 'PROJCS["DHDN / Soldner 39 Langschoß",'
  251. 'GEOGCS["DHDN",DATUM["Deutsches_Hauptdreiecksnetz",'
  252. 'SPHEROID["Bessel 1841",6377397.155,299.1528128,AUTHORITY["EPSG","7004"]],AUTHORITY["EPSG","6314"]],'
  253. 'PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],'
  254. 'UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],'
  255. 'AUTHORITY["EPSG","4314"]],PROJECTION["Cassini_Soldner"],'
  256. 'PARAMETER["latitude_of_origin",50.66738711],PARAMETER["central_meridian",6.28935703],'
  257. 'PARAMETER["false_easting",0],PARAMETER["false_northing",0],'
  258. 'UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",NORTH],AXIS["Y",EAST],AUTHORITY["mj10777.de","187939"]]'
  259. )
  260. srs = SpatialReference(wkt)
  261. srs_list = [srs, srs.clone()]
  262. srs.import_wkt(wkt)
  263. for srs in srs_list:
  264. self.assertEqual(srs.name, 'DHDN / Soldner 39 Langschoß')
  265. self.assertEqual(srs.wkt, wkt)
  266. self.assertIn('Langschoß', srs.pretty_wkt)
  267. self.assertIn('Langschoß', srs.xml)
  268. @skipIf(GDAL_VERSION < (3, 0), 'GDAL >= 3.0 is required')
  269. def test_axis_order(self):
  270. wgs84_trad = SpatialReference(4326, axis_order=AxisOrder.TRADITIONAL)
  271. wgs84_auth = SpatialReference(4326, axis_order=AxisOrder.AUTHORITY)
  272. # Coordinate interpretation may depend on the srs axis predicate.
  273. pt = GEOSGeometry('POINT (992385.4472045 481455.4944650)', 2774)
  274. pt_trad = pt.transform(wgs84_trad, clone=True)
  275. self.assertAlmostEqual(pt_trad.x, -104.609, 3)
  276. self.assertAlmostEqual(pt_trad.y, 38.255, 3)
  277. pt_auth = pt.transform(wgs84_auth, clone=True)
  278. self.assertAlmostEqual(pt_auth.x, 38.255, 3)
  279. self.assertAlmostEqual(pt_auth.y, -104.609, 3)
  280. # clone() preserves the axis order.
  281. pt_auth = pt.transform(wgs84_auth.clone(), clone=True)
  282. self.assertAlmostEqual(pt_auth.x, 38.255, 3)
  283. self.assertAlmostEqual(pt_auth.y, -104.609, 3)
  284. def test_axis_order_invalid(self):
  285. msg = 'SpatialReference.axis_order must be an AxisOrder instance.'
  286. with self.assertRaisesMessage(ValueError, msg):
  287. SpatialReference(4326, axis_order='other')
  288. @skipIf(GDAL_VERSION > (3, 0), "GDAL < 3.0 doesn't support authority.")
  289. def test_axis_order_non_traditional_invalid(self):
  290. msg = 'AxisOrder.AUTHORITY is not supported in GDAL < 3.0.'
  291. with self.assertRaisesMessage(ValueError, msg):
  292. SpatialReference(4326, axis_order=AxisOrder.AUTHORITY)