mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Fixed #34685 -- Dropped support for GEOS 3.6 and 3.7.
This commit is contained in:
parent
ce204bed7f
commit
601ffb0da3
@ -8,7 +8,7 @@ from ctypes import byref, c_byte, c_double, c_uint
|
|||||||
from django.contrib.gis.geos import prototypes as capi
|
from django.contrib.gis.geos import prototypes as capi
|
||||||
from django.contrib.gis.geos.base import GEOSBase
|
from django.contrib.gis.geos.base import GEOSBase
|
||||||
from django.contrib.gis.geos.error import GEOSException
|
from django.contrib.gis.geos.error import GEOSException
|
||||||
from django.contrib.gis.geos.libgeos import CS_PTR, geos_version_tuple
|
from django.contrib.gis.geos.libgeos import CS_PTR
|
||||||
from django.contrib.gis.shortcuts import numpy
|
from django.contrib.gis.shortcuts import numpy
|
||||||
|
|
||||||
|
|
||||||
@ -202,16 +202,6 @@ class GEOSCoordSeq(GEOSBase):
|
|||||||
@property
|
@property
|
||||||
def is_counterclockwise(self):
|
def is_counterclockwise(self):
|
||||||
"""Return whether this coordinate sequence is counterclockwise."""
|
"""Return whether this coordinate sequence is counterclockwise."""
|
||||||
if geos_version_tuple() < (3, 7):
|
|
||||||
# A modified shoelace algorithm to determine polygon orientation.
|
|
||||||
# See https://en.wikipedia.org/wiki/Shoelace_formula.
|
|
||||||
area = 0.0
|
|
||||||
n = len(self)
|
|
||||||
for i in range(n):
|
|
||||||
j = (i + 1) % n
|
|
||||||
area += self[i][0] * self[j][1]
|
|
||||||
area -= self[j][0] * self[i][1]
|
|
||||||
return area > 0.0
|
|
||||||
ret = c_byte()
|
ret = c_byte()
|
||||||
if not capi.cs_is_ccw(self.ptr, byref(ret)):
|
if not capi.cs_is_ccw(self.ptr, byref(ret)):
|
||||||
raise GEOSException(
|
raise GEOSException(
|
||||||
|
@ -11,7 +11,7 @@ from django.contrib.gis.geos import prototypes as capi
|
|||||||
from django.contrib.gis.geos.base import GEOSBase
|
from django.contrib.gis.geos.base import GEOSBase
|
||||||
from django.contrib.gis.geos.coordseq import GEOSCoordSeq
|
from django.contrib.gis.geos.coordseq import GEOSCoordSeq
|
||||||
from django.contrib.gis.geos.error import GEOSException
|
from django.contrib.gis.geos.error import GEOSException
|
||||||
from django.contrib.gis.geos.libgeos import GEOM_PTR, geos_version_tuple
|
from django.contrib.gis.geos.libgeos import GEOM_PTR
|
||||||
from django.contrib.gis.geos.mutable_list import ListMixin
|
from django.contrib.gis.geos.mutable_list import ListMixin
|
||||||
from django.contrib.gis.geos.prepared import PreparedGeometry
|
from django.contrib.gis.geos.prepared import PreparedGeometry
|
||||||
from django.contrib.gis.geos.prototypes.io import ewkb_w, wkb_r, wkb_w, wkt_r, wkt_w
|
from django.contrib.gis.geos.prototypes.io import ewkb_w, wkb_r, wkb_w, wkt_r, wkt_w
|
||||||
@ -238,8 +238,6 @@ class GEOSGeometryBase(GEOSBase):
|
|||||||
Attempt to create a valid representation of a given invalid geometry
|
Attempt to create a valid representation of a given invalid geometry
|
||||||
without losing any of the input vertices.
|
without losing any of the input vertices.
|
||||||
"""
|
"""
|
||||||
if geos_version_tuple() < (3, 8):
|
|
||||||
raise GEOSException("GEOSGeometry.make_valid() requires GEOS >= 3.8.0.")
|
|
||||||
return GEOSGeometry(capi.geos_makevalid(self.ptr), srid=self.srid)
|
return GEOSGeometry(capi.geos_makevalid(self.ptr), srid=self.srid)
|
||||||
|
|
||||||
# #### Unary predicates ####
|
# #### Unary predicates ####
|
||||||
|
@ -259,24 +259,14 @@ class WKBWriter(IOBase):
|
|||||||
|
|
||||||
def write(self, geom):
|
def write(self, geom):
|
||||||
"Return the WKB representation of the given geometry."
|
"Return the WKB representation of the given geometry."
|
||||||
from django.contrib.gis.geos import Polygon
|
|
||||||
|
|
||||||
geom = self._handle_empty_point(geom)
|
geom = self._handle_empty_point(geom)
|
||||||
wkb = wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t()))
|
wkb = wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t()))
|
||||||
if self.geos_version < (3, 6, 1) and isinstance(geom, Polygon) and geom.empty:
|
|
||||||
# Fix GEOS output for empty polygon.
|
|
||||||
# See https://trac.osgeo.org/geos/ticket/680.
|
|
||||||
wkb = wkb[:-8] + b"\0" * 4
|
|
||||||
return memoryview(wkb)
|
return memoryview(wkb)
|
||||||
|
|
||||||
def write_hex(self, geom):
|
def write_hex(self, geom):
|
||||||
"Return the HEXEWKB representation of the given geometry."
|
"Return the HEXEWKB representation of the given geometry."
|
||||||
from django.contrib.gis.geos.polygon import Polygon
|
|
||||||
|
|
||||||
geom = self._handle_empty_point(geom)
|
geom = self._handle_empty_point(geom)
|
||||||
wkb = wkb_writer_write_hex(self.ptr, geom.ptr, byref(c_size_t()))
|
wkb = wkb_writer_write_hex(self.ptr, geom.ptr, byref(c_size_t()))
|
||||||
if self.geos_version < (3, 6, 1) and isinstance(geom, Polygon) and geom.empty:
|
|
||||||
wkb = wkb[:-16] + b"0" * 8
|
|
||||||
return wkb
|
return wkb
|
||||||
|
|
||||||
# ### WKBWriter Properties ###
|
# ### WKBWriter Properties ###
|
||||||
|
@ -8,7 +8,7 @@ geospatial libraries:
|
|||||||
======================== ==================================== ================================ ======================================
|
======================== ==================================== ================================ ======================================
|
||||||
Program Description Required Supported Versions
|
Program Description Required Supported Versions
|
||||||
======================== ==================================== ================================ ======================================
|
======================== ==================================== ================================ ======================================
|
||||||
:doc:`GEOS <../geos>` Geometry Engine Open Source Yes 3.11, 3.10, 3.9, 3.8, 3.7, 3.6
|
:doc:`GEOS <../geos>` Geometry Engine Open Source Yes 3.11, 3.10, 3.9, 3.8
|
||||||
`PROJ`_ Cartographic Projections library Yes (PostgreSQL and SQLite only) 9.x, 8.x, 7.x, 6.x, 5.x
|
`PROJ`_ Cartographic Projections library Yes (PostgreSQL and SQLite only) 9.x, 8.x, 7.x, 6.x, 5.x
|
||||||
:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes 3.6, 3.5, 3.4, 3.3, 3.2, 3.1, 3.0, 2.4
|
:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes 3.6, 3.5, 3.4, 3.3, 3.2, 3.1, 3.0, 2.4
|
||||||
:doc:`GeoIP <../geoip2>` IP-based geolocation library No 2
|
:doc:`GeoIP <../geoip2>` IP-based geolocation library No 2
|
||||||
@ -21,8 +21,6 @@ totally fine with GeoDjango. Your mileage may vary.
|
|||||||
|
|
||||||
..
|
..
|
||||||
Libs release dates:
|
Libs release dates:
|
||||||
GEOS 3.6.0 2016-10-25
|
|
||||||
GEOS 3.7.0 2018-09-10
|
|
||||||
GEOS 3.8.0 2019-10-10
|
GEOS 3.8.0 2019-10-10
|
||||||
GEOS 3.9.0 2020-12-14
|
GEOS 3.9.0 2020-12-14
|
||||||
GEOS 3.10.0 2021-10-20
|
GEOS 3.10.0 2021-10-20
|
||||||
|
@ -422,6 +422,8 @@ backends.
|
|||||||
|
|
||||||
* Support for GDAL 2.2 and 2.3 is removed.
|
* Support for GDAL 2.2 and 2.3 is removed.
|
||||||
|
|
||||||
|
* Support for GEOS 3.6 and 3.7 is removed.
|
||||||
|
|
||||||
Using ``create_defaults__exact`` may now be required with ``QuerySet.update_or_create()``
|
Using ``create_defaults__exact`` may now be required with ``QuerySet.update_or_create()``
|
||||||
-----------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import pickle
|
|||||||
import random
|
import random
|
||||||
from binascii import a2b_hex
|
from binascii import a2b_hex
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from unittest import mock, skipIf
|
from unittest import mock
|
||||||
|
|
||||||
from django.contrib.gis import gdal
|
from django.contrib.gis import gdal
|
||||||
from django.contrib.gis.geos import (
|
from django.contrib.gis.geos import (
|
||||||
@ -393,7 +393,7 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
|
|||||||
line.ewkt, "SRID=4326;LINESTRING (151.2607 -33.887, 144.963 -37.8143)"
|
line.ewkt, "SRID=4326;LINESTRING (151.2607 -33.887, 144.963 -37.8143)"
|
||||||
)
|
)
|
||||||
|
|
||||||
def _test_is_counterclockwise(self):
|
def test_is_counterclockwise(self):
|
||||||
lr = LinearRing((0, 0), (1, 0), (0, 1), (0, 0))
|
lr = LinearRing((0, 0), (1, 0), (0, 1), (0, 0))
|
||||||
self.assertIs(lr.is_counterclockwise, True)
|
self.assertIs(lr.is_counterclockwise, True)
|
||||||
lr.reverse()
|
lr.reverse()
|
||||||
@ -402,11 +402,6 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
|
|||||||
with self.assertRaisesMessage(ValueError, msg):
|
with self.assertRaisesMessage(ValueError, msg):
|
||||||
LinearRing().is_counterclockwise
|
LinearRing().is_counterclockwise
|
||||||
|
|
||||||
@skipIf(geos_version_tuple() < (3, 7), "GEOS >= 3.7.0 is required")
|
|
||||||
def test_is_counterclockwise(self):
|
|
||||||
self._test_is_counterclockwise()
|
|
||||||
|
|
||||||
@skipIf(geos_version_tuple() < (3, 7), "GEOS >= 3.7.0 is required")
|
|
||||||
def test_is_counterclockwise_geos_error(self):
|
def test_is_counterclockwise_geos_error(self):
|
||||||
with mock.patch("django.contrib.gis.geos.prototypes.cs_is_ccw") as mocked:
|
with mock.patch("django.contrib.gis.geos.prototypes.cs_is_ccw") as mocked:
|
||||||
mocked.return_value = 0
|
mocked.return_value = 0
|
||||||
@ -415,10 +410,6 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
|
|||||||
with self.assertRaisesMessage(GEOSException, msg):
|
with self.assertRaisesMessage(GEOSException, msg):
|
||||||
LinearRing((0, 0), (1, 0), (0, 1), (0, 0)).is_counterclockwise
|
LinearRing((0, 0), (1, 0), (0, 1), (0, 0)).is_counterclockwise
|
||||||
|
|
||||||
@mock.patch("django.contrib.gis.geos.libgeos.geos_version", lambda: b"3.6.9")
|
|
||||||
def test_is_counterclockwise_fallback(self):
|
|
||||||
self._test_is_counterclockwise()
|
|
||||||
|
|
||||||
def test_multilinestring(self):
|
def test_multilinestring(self):
|
||||||
"Testing MultiLineString objects."
|
"Testing MultiLineString objects."
|
||||||
prev = fromstr("POINT(0 0)")
|
prev = fromstr("POINT(0 0)")
|
||||||
@ -1543,7 +1534,6 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
|
|||||||
self.assertEqual(multipoint_2, normalized)
|
self.assertEqual(multipoint_2, normalized)
|
||||||
self.assertNotEqual(multipoint, normalized)
|
self.assertNotEqual(multipoint, normalized)
|
||||||
|
|
||||||
@skipIf(geos_version_tuple() < (3, 8), "GEOS >= 3.8.0 is required")
|
|
||||||
def test_make_valid(self):
|
def test_make_valid(self):
|
||||||
poly = GEOSGeometry("POLYGON((0 0, 0 23, 23 0, 23 23, 0 0))")
|
poly = GEOSGeometry("POLYGON((0 0, 0 23, 23 0, 23 23, 0 0))")
|
||||||
self.assertIs(poly.valid, False)
|
self.assertIs(poly.valid, False)
|
||||||
@ -1555,13 +1545,6 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
|
|||||||
self.assertIs(valid_poly2.valid, True)
|
self.assertIs(valid_poly2.valid, True)
|
||||||
self.assertEqual(valid_poly, valid_poly2)
|
self.assertEqual(valid_poly, valid_poly2)
|
||||||
|
|
||||||
@mock.patch("django.contrib.gis.geos.libgeos.geos_version", lambda: b"3.7.3")
|
|
||||||
def test_make_valid_geos_version(self):
|
|
||||||
msg = "GEOSGeometry.make_valid() requires GEOS >= 3.8.0."
|
|
||||||
poly = GEOSGeometry("POLYGON((0 0, 0 23, 23 0, 23 23, 0 0))")
|
|
||||||
with self.assertRaisesMessage(GEOSException, msg):
|
|
||||||
poly.make_valid()
|
|
||||||
|
|
||||||
def test_empty_point(self):
|
def test_empty_point(self):
|
||||||
p = Point(srid=4326)
|
p = Point(srid=4326)
|
||||||
self.assertEqual(p.ogr.ewkt, p.ewkt)
|
self.assertEqual(p.ogr.ewkt, p.ewkt)
|
||||||
|
Loading…
Reference in New Issue
Block a user