Loading django/contrib/gis/db/backends/base/features.py +2 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ class BaseSpatialFeatures(object): # Does the backend introspect GeometryField to its subtypes? supports_geometry_field_introspection = True # Does the backend support storing 3D geometries? supports_3d_storage = False # Reference implementation of 3D functions is: # http://postgis.net/docs/PostGIS_Special_Functions_Index.html#PostGIS_3D_Functions supports_3d_functions = False Loading django/contrib/gis/db/backends/postgis/features.py +1 −0 Original line number Diff line number Diff line Loading @@ -4,5 +4,6 @@ from django.db.backends.postgresql_psycopg2.features import \ class DatabaseFeatures(BaseSpatialFeatures, Psycopg2DatabaseFeatures): supports_3d_storage = True supports_3d_functions = True supports_left_right_lookups = True django/contrib/gis/db/backends/spatialite/features.py +5 −0 Original line number Diff line number Diff line from django.contrib.gis.db.backends.base.features import BaseSpatialFeatures from django.contrib.gis.geos import geos_version from django.db.backends.sqlite3.features import \ DatabaseFeatures as SQLiteDatabaseFeatures from django.utils.functional import cached_property Loading @@ -15,3 +16,7 @@ class DatabaseFeatures(BaseSpatialFeatures, SQLiteDatabaseFeatures): # which can result in a significant performance improvement when # creating the database. return self.connection.ops.spatial_version >= (4, 1, 0) @cached_property def supports_3d_storage(self): return geos_version() >= '3.3' django/contrib/gis/db/backends/spatialite/introspection.py +8 −2 Original line number Diff line number Diff line Loading @@ -41,7 +41,13 @@ class SpatiaLiteIntrospection(DatabaseIntrospection): # OGRGeomType does not require GDAL and makes it easy to convert # from OGC geom type name to Django field. field_type = OGRGeomType(row[2]).django ogr_type = row[2] if isinstance(ogr_type, six.integer_types) and ogr_type > 1000: # Spatialite versions >= 4 use the new SFSQL 1.2 offsets # 1000 (Z), 2000 (M), and 3000 (ZM) to indicate the presence of # higher dimensional coordinates (M not yet supported by Django). ogr_type = ogr_type % 1000 + OGRGeomType.wkb25bit field_type = OGRGeomType(ogr_type).django # Getting any GeometryField keyword arguments that are not the default. dim = row[0] Loading @@ -49,7 +55,7 @@ class SpatiaLiteIntrospection(DatabaseIntrospection): field_params = {} if srid != 4326: field_params['srid'] = srid if isinstance(dim, six.string_types) and 'Z' in dim: if (isinstance(dim, six.string_types) and 'Z' in dim) or dim == 3: field_params['dim'] = 3 finally: cursor.close() Loading tests/gis_tests/geo3d/tests.py +7 −1 Original line number Diff line number Diff line Loading @@ -74,7 +74,7 @@ bbox_data = ( @skipUnless(HAS_GDAL, "GDAL is required for Geo3DTest.") @skipUnlessDBFeature("gis_enabled", "supports_3d_functions") @skipUnlessDBFeature("gis_enabled", "supports_3d_storage") class Geo3DTest(TestCase): """ Only a subset of the PostGIS routines are 3D-enabled, and this TestCase Loading Loading @@ -189,6 +189,7 @@ class Geo3DTest(TestCase): ref_json_regex = re.compile(r'^{"type":"Point","coordinates":\[-95.363151,29.763374,18(\.0+)?\]}$') self.assertTrue(ref_json_regex.match(h.geojson)) @skipUnlessDBFeature("supports_3d_functions") def test_union(self): """ Testing the Union aggregate of 3D models. Loading @@ -207,6 +208,7 @@ class Geo3DTest(TestCase): # Ordering of points in the resulting geometry may vary between implementations self.assertSetEqual({p.ewkt for p in ref_union}, {p.ewkt for p in union}) @skipUnlessDBFeature("supports_3d_functions") @ignore_warnings(category=RemovedInDjango20Warning) def test_extent(self): """ Loading @@ -227,6 +229,7 @@ class Geo3DTest(TestCase): self.assertIsNone(City3D.objects.none().extent3d()) self.assertIsNone(City3D.objects.none().aggregate(Extent3D('point'))['point__extent3d']) @skipUnlessDBFeature("supports_3d_functions") def test_perimeter(self): """ Testing GeoQuerySet.perimeter() on 3D fields. Loading @@ -244,6 +247,7 @@ class Geo3DTest(TestCase): Polygon3D.objects.perimeter().get(name='3D BBox').perimeter.m, tol) @skipUnlessDBFeature("supports_3d_functions") def test_length(self): """ Testing GeoQuerySet.length() on 3D fields. Loading Loading @@ -276,6 +280,7 @@ class Geo3DTest(TestCase): InterstateProj3D.objects.length().get(name='I-45').length.m, tol) @skipUnlessDBFeature("supports_3d_functions") def test_scale(self): """ Testing GeoQuerySet.scale() on Z values. Loading @@ -287,6 +292,7 @@ class Geo3DTest(TestCase): for city in City3D.objects.scale(1.0, 1.0, zscale): self.assertEqual(city_dict[city.name][2] * zscale, city.scale.z) @skipUnlessDBFeature("supports_3d_functions") def test_translate(self): """ Testing GeoQuerySet.translate() on Z values. Loading Loading
django/contrib/gis/db/backends/base/features.py +2 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ class BaseSpatialFeatures(object): # Does the backend introspect GeometryField to its subtypes? supports_geometry_field_introspection = True # Does the backend support storing 3D geometries? supports_3d_storage = False # Reference implementation of 3D functions is: # http://postgis.net/docs/PostGIS_Special_Functions_Index.html#PostGIS_3D_Functions supports_3d_functions = False Loading
django/contrib/gis/db/backends/postgis/features.py +1 −0 Original line number Diff line number Diff line Loading @@ -4,5 +4,6 @@ from django.db.backends.postgresql_psycopg2.features import \ class DatabaseFeatures(BaseSpatialFeatures, Psycopg2DatabaseFeatures): supports_3d_storage = True supports_3d_functions = True supports_left_right_lookups = True
django/contrib/gis/db/backends/spatialite/features.py +5 −0 Original line number Diff line number Diff line from django.contrib.gis.db.backends.base.features import BaseSpatialFeatures from django.contrib.gis.geos import geos_version from django.db.backends.sqlite3.features import \ DatabaseFeatures as SQLiteDatabaseFeatures from django.utils.functional import cached_property Loading @@ -15,3 +16,7 @@ class DatabaseFeatures(BaseSpatialFeatures, SQLiteDatabaseFeatures): # which can result in a significant performance improvement when # creating the database. return self.connection.ops.spatial_version >= (4, 1, 0) @cached_property def supports_3d_storage(self): return geos_version() >= '3.3'
django/contrib/gis/db/backends/spatialite/introspection.py +8 −2 Original line number Diff line number Diff line Loading @@ -41,7 +41,13 @@ class SpatiaLiteIntrospection(DatabaseIntrospection): # OGRGeomType does not require GDAL and makes it easy to convert # from OGC geom type name to Django field. field_type = OGRGeomType(row[2]).django ogr_type = row[2] if isinstance(ogr_type, six.integer_types) and ogr_type > 1000: # Spatialite versions >= 4 use the new SFSQL 1.2 offsets # 1000 (Z), 2000 (M), and 3000 (ZM) to indicate the presence of # higher dimensional coordinates (M not yet supported by Django). ogr_type = ogr_type % 1000 + OGRGeomType.wkb25bit field_type = OGRGeomType(ogr_type).django # Getting any GeometryField keyword arguments that are not the default. dim = row[0] Loading @@ -49,7 +55,7 @@ class SpatiaLiteIntrospection(DatabaseIntrospection): field_params = {} if srid != 4326: field_params['srid'] = srid if isinstance(dim, six.string_types) and 'Z' in dim: if (isinstance(dim, six.string_types) and 'Z' in dim) or dim == 3: field_params['dim'] = 3 finally: cursor.close() Loading
tests/gis_tests/geo3d/tests.py +7 −1 Original line number Diff line number Diff line Loading @@ -74,7 +74,7 @@ bbox_data = ( @skipUnless(HAS_GDAL, "GDAL is required for Geo3DTest.") @skipUnlessDBFeature("gis_enabled", "supports_3d_functions") @skipUnlessDBFeature("gis_enabled", "supports_3d_storage") class Geo3DTest(TestCase): """ Only a subset of the PostGIS routines are 3D-enabled, and this TestCase Loading Loading @@ -189,6 +189,7 @@ class Geo3DTest(TestCase): ref_json_regex = re.compile(r'^{"type":"Point","coordinates":\[-95.363151,29.763374,18(\.0+)?\]}$') self.assertTrue(ref_json_regex.match(h.geojson)) @skipUnlessDBFeature("supports_3d_functions") def test_union(self): """ Testing the Union aggregate of 3D models. Loading @@ -207,6 +208,7 @@ class Geo3DTest(TestCase): # Ordering of points in the resulting geometry may vary between implementations self.assertSetEqual({p.ewkt for p in ref_union}, {p.ewkt for p in union}) @skipUnlessDBFeature("supports_3d_functions") @ignore_warnings(category=RemovedInDjango20Warning) def test_extent(self): """ Loading @@ -227,6 +229,7 @@ class Geo3DTest(TestCase): self.assertIsNone(City3D.objects.none().extent3d()) self.assertIsNone(City3D.objects.none().aggregate(Extent3D('point'))['point__extent3d']) @skipUnlessDBFeature("supports_3d_functions") def test_perimeter(self): """ Testing GeoQuerySet.perimeter() on 3D fields. Loading @@ -244,6 +247,7 @@ class Geo3DTest(TestCase): Polygon3D.objects.perimeter().get(name='3D BBox').perimeter.m, tol) @skipUnlessDBFeature("supports_3d_functions") def test_length(self): """ Testing GeoQuerySet.length() on 3D fields. Loading Loading @@ -276,6 +280,7 @@ class Geo3DTest(TestCase): InterstateProj3D.objects.length().get(name='I-45').length.m, tol) @skipUnlessDBFeature("supports_3d_functions") def test_scale(self): """ Testing GeoQuerySet.scale() on Z values. Loading @@ -287,6 +292,7 @@ class Geo3DTest(TestCase): for city in City3D.objects.scale(1.0, 1.0, zscale): self.assertEqual(city_dict[city.name][2] * zscale, city.scale.z) @skipUnlessDBFeature("supports_3d_functions") def test_translate(self): """ Testing GeoQuerySet.translate() on Z values. Loading