test_srs.py 15 KB

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