Browse Source

Fixed #26920 -- Made GEOSGeometry equality check consider the srid

Jackie Leng 8 years ago
parent
commit
50613d957a

+ 5 - 3
django/contrib/gis/geos/geometry.py

@@ -174,12 +174,14 @@ class GEOSGeometry(GEOSBase, ListMixin):
     def __eq__(self, other):
         """
         Equivalence testing, a Geometry may be compared with another Geometry
-        or a WKT representation.
+        or an EWKT representation.
         """
         if isinstance(other, six.string_types):
-            return self.wkt == other
+            if other.startswith('SRID=0;'):
+                return self.ewkt == other[7:]  # Test only WKT part of other
+            return self.ewkt == other
         elif isinstance(other, GEOSGeometry):
-            return self.equals_exact(other)
+            return self.srid == other.srid and self.equals_exact(other)
         else:
             return False
 

+ 9 - 1
docs/ref/contrib/gis/geos.txt

@@ -160,15 +160,23 @@ Geometries support set-like operators::
     The :class:`~GEOSGeometry` equality operator uses
     :meth:`~GEOSGeometry.equals_exact`, not :meth:`~GEOSGeometry.equals`, i.e.
     it requires the compared geometries to have the same coordinates in the
-    same positions::
+    same positions with the same SRIDs::
 
         >>> from django.contrib.gis.geos import LineString
         >>> ls1 = LineString((0, 0), (1, 1))
         >>> ls2 = LineString((1, 1), (0, 0))
+        >>> ls3 = LineString((1, 1), (0, 0), srid=4326)
         >>> ls1.equals(ls2)
         True
         >>> ls1 == ls2
         False
+        >>> ls3 == ls2  # different SRIDs
+        False
+
+    .. versionchanged:: 1.11
+
+        Older versions didn't check the ``srid`` when comparing
+        ``GEOSGeometry`` objects using the equality operator.
 
 Geometry Objects
 ================

+ 2 - 0
docs/releases/1.11.txt

@@ -423,6 +423,8 @@ Backwards incompatible changes in 1.11
   the Google Maps API and seems to be unmaintained. If you're using it, `let
   us know <https://code.djangoproject.com/ticket/14284>`_.
 
+* The ``GEOSGeometry`` equality operator now also compares SRID.
+
 Database backend API
 --------------------
 

+ 1 - 1
tests/gis_tests/geoapp/test_functions.py

@@ -266,7 +266,7 @@ class GISFunctionsTests(TestCase):
         State.objects.create(name='invalid', poly=invalid_geom)
         invalid = State.objects.filter(name='invalid').annotate(repaired=functions.MakeValid('poly')).first()
         self.assertIs(invalid.repaired.valid, True)
-        self.assertEqual(invalid.repaired, fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))'))
+        self.assertEqual(invalid.repaired, fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', srid=invalid.poly.srid))
 
     @skipUnlessDBFeature("has_MemSize_function")
     def test_memsize(self):

+ 7 - 4
tests/gis_tests/geoapp/tests.py

@@ -63,9 +63,9 @@ class GeoModelTest(TestCase):
         nullcity.point.x = 23
         nullcity.point.y = 5
         # Checking assignments pre & post-save.
-        self.assertNotEqual(Point(23, 5), City.objects.get(name='NullCity').point)
+        self.assertNotEqual(Point(23, 5, srid=4326), City.objects.get(name='NullCity').point)
         nullcity.save()
-        self.assertEqual(Point(23, 5), City.objects.get(name='NullCity').point)
+        self.assertEqual(Point(23, 5, srid=4326), City.objects.get(name='NullCity').point)
         nullcity.delete()
 
         # Testing on a Polygon
@@ -479,8 +479,11 @@ class GeoQuerySetTest(TestCase):
                 # SpatiaLite).
                 pass
             else:
-                self.assertEqual(c.mpoly.difference(geom), c.difference)
-                if not spatialite:
+                if spatialite:
+                    # Spatialite `difference` doesn't have an SRID
+                    self.assertEqual(c.mpoly.difference(geom).wkt, c.difference.wkt)
+                else:
+                    self.assertEqual(c.mpoly.difference(geom), c.difference)
                     self.assertEqual(c.mpoly.intersection(geom), c.intersection)
                 # Ordering might differ in collections
                 self.assertSetEqual(set(g.wkt for g in c.mpoly.sym_difference(geom)),

+ 21 - 0
tests/gis_tests/geos_tests/test_geos.py

@@ -227,6 +227,27 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
             self.assertNotEqual(g, {'foo': 'bar'})
             self.assertNotEqual(g, False)
 
+    def test_eq_with_srid(self):
+        "Testing non-equivalence with different srids."
+        p0 = Point(5, 23)
+        p1 = Point(5, 23, srid=4326)
+        p2 = Point(5, 23, srid=32632)
+        # GEOS
+        self.assertNotEqual(p0, p1)
+        self.assertNotEqual(p1, p2)
+        # EWKT
+        self.assertNotEqual(p0, p1.ewkt)
+        self.assertNotEqual(p1, p0.ewkt)
+        self.assertNotEqual(p1, p2.ewkt)
+        # Equivalence with matching SRIDs
+        self.assertEqual(p2, p2)
+        self.assertEqual(p2, p2.ewkt)
+        # WKT contains no SRID so will not equal
+        self.assertNotEqual(p2, p2.wkt)
+        # SRID of 0
+        self.assertEqual(p0, 'SRID=0;POINT (5 23)')
+        self.assertNotEqual(p1, 'SRID=0;POINT (5 23)')
+
     def test_points(self):
         "Testing Point objects."
         prev = fromstr('POINT(0 0)')

+ 1 - 1
tests/gis_tests/relatedapp/tests.py

@@ -36,7 +36,7 @@ class RelatedGeoModelTest(TestCase):
                 nm, st, lon, lat = ref
                 self.assertEqual(nm, c.name)
                 self.assertEqual(st, c.state)
-                self.assertEqual(Point(lon, lat), c.location.point)
+                self.assertEqual(Point(lon, lat, srid=c.location.point.srid), c.location.point)
 
     @skipUnlessDBFeature("has_transform_method")
     def test03_transform_related(self):

+ 10 - 5
tests/gis_tests/test_geoforms.py

@@ -48,12 +48,17 @@ class GeometryFieldTest(SimpleTestCase):
         # By default, all geometry types are allowed.
         fld = forms.GeometryField()
         for wkt in ('POINT(5 23)', 'MULTIPOLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'LINESTRING(0 0, 1 1)'):
-            self.assertEqual(GEOSGeometry(wkt), fld.clean(wkt))
+            # `to_python` uses the SRID of OpenLayersWidget if the converted
+            # value doesn't have an SRID itself.
+            self.assertEqual(GEOSGeometry(wkt, srid=fld.widget.map_srid), fld.clean(wkt))
 
         pnt_fld = forms.GeometryField(geom_type='POINT')
-        self.assertEqual(GEOSGeometry('POINT(5 23)'), pnt_fld.clean('POINT(5 23)'))
+        self.assertEqual(GEOSGeometry('POINT(5 23)', srid=pnt_fld.widget.map_srid), pnt_fld.clean('POINT(5 23)'))
         # a WKT for any other geom_type will be properly transformed by `to_python`
-        self.assertEqual(GEOSGeometry('LINESTRING(0 0, 1 1)'), pnt_fld.to_python('LINESTRING(0 0, 1 1)'))
+        self.assertEqual(
+            GEOSGeometry('LINESTRING(0 0, 1 1)', srid=pnt_fld.widget.map_srid),
+            pnt_fld.to_python('LINESTRING(0 0, 1 1)')
+        )
         # but rejected by `clean`
         with self.assertRaises(forms.ValidationError):
             pnt_fld.clean('LINESTRING(0 0, 1 1)')
@@ -66,7 +71,7 @@ class GeometryFieldTest(SimpleTestCase):
         fld = forms.GeometryField()
         # to_python returns the same GEOSGeometry for a WKT
         for wkt in ('POINT(5 23)', 'MULTIPOLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'LINESTRING(0 0, 1 1)'):
-            self.assertEqual(GEOSGeometry(wkt), fld.to_python(wkt))
+            self.assertEqual(GEOSGeometry(wkt, srid=fld.widget.map_srid), fld.to_python(wkt))
         # but raises a ValidationError for any other string
         for wkt in ('POINT(5)', 'MULTI   POLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'BLAH(0 0, 1 1)'):
             with self.assertRaises(forms.ValidationError):
@@ -78,7 +83,7 @@ class GeometryFieldTest(SimpleTestCase):
 
         form = PointForm()
         cleaned_pt = form.fields['pt'].clean('POINT(5 23)')
-        self.assertEqual(cleaned_pt, GEOSGeometry('POINT(5 23)'))
+        self.assertEqual(cleaned_pt, GEOSGeometry('POINT(5 23)', srid=4326))
         self.assertEqual(4326, cleaned_pt.srid)
 
         point = GEOSGeometry('SRID=4326;POINT(5 23)')