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