1
0
mirror of https://github.com/django/django.git synced 2025-07-04 01:39:20 +00:00

gis: gdal: OSGeo sprint -- cleaned up spatial references associated with geometries (fixed a segfault); cleaned up Envelope module (thanks to ww for help), and added tests; added a test module for invoking all gdal tests; changed exception style.

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@6436 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Justin Bronn 2007-09-29 14:02:41 +00:00
parent cfb807a1fb
commit 9eb115e304
14 changed files with 311 additions and 136 deletions

View File

@ -1,12 +1,39 @@
"""
This module houses ctypes interfaces for GDAL objects. The following GDAL
objects are supported:
CoordTransform: Used for coordinate transformations from one spatial
reference system to another.
Driver: Wraps an OGR data source driver.
DataSource: Wrapper for the OGR data source object, supports
OGR-supported data sources.
Envelope: A ctypes structure for bounding boxes (GDAL library
not required).
OGRGeometry: Layer for accessing OGR Geometry objects.
OGRGeomType: A class for representing the different OGR Geometry
types (GDAL library not required).
SpatialReference: Represents OSR Spatial Reference objects.
"""
# Attempting to import objects that depend on the GDAL library. The
# HAS_GDAL flag will be set to True if the library is present on
# the system.
try:
from django.contrib.gis.gdal.driver import Driver
from django.contrib.gis.gdal.envelope import Envelope
from django.contrib.gis.gdal.datasource import DataSource
from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform
from django.contrib.gis.gdal.geometries import OGRGeometry
from django.contrib.gis.gdal.geomtype import OGRGeomType
from django.contrib.gis.gdal.error import check_err, OGRException, SRSException
HAS_GDAL = True
except:
HAS_GDAL = False
# The envelope, error, and geomtype modules do not actually require the
# GDAL library.
from django.contrib.gis.gdal.envelope import Envelope
from django.contrib.gis.gdal.error import check_err, OGRException, OGRIndexError, SRSException
from django.contrib.gis.gdal.geomtype import OGRGeomType

View File

@ -4,7 +4,7 @@ from ctypes import c_char_p, c_int, c_void_p, byref, string_at
# The GDAL C library, OGR exceptions, and the Layer object.
from django.contrib.gis.gdal.libgdal import lgdal
from django.contrib.gis.gdal.error import OGRException, check_err
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, check_err
from django.contrib.gis.gdal.layer import Layer
from django.contrib.gis.gdal.driver import Driver
@ -60,7 +60,7 @@ class DataSource(object):
# Registering all the drivers, this needs to be done
# _before_ we try to open up a data source.
if not lgdal.OGRGetDriverCount() and not lgdal.OGRRegisterAll():
raise OGRException, 'Could not register all the OGR data source drivers!'
raise OGRException('Could not register all the OGR data source drivers!')
if isinstance(ds_input, StringType):
@ -72,12 +72,12 @@ class DataSource(object):
elif isinstance(ds_input, c_void_p) and isinstance(ds_driver, c_void_p):
ds = ds_input
else:
raise OGRException, 'Invalid data source input type: %s' % str(type(ds_input))
raise OGRException('Invalid data source input type: %s' % str(type(ds_input)))
# Raise an exception if the returned pointer is NULL
if not ds:
self._ds = False
raise OGRException, 'Invalid data source file "%s"' % ds_input
raise OGRException('Invalid data source file "%s"' % ds_input)
else:
self._ds = ds
self._driver = Driver(ds_driver)
@ -95,10 +95,10 @@ class DataSource(object):
"Allows use of the index [] operator to get a layer at the index."
if isinstance(index, StringType):
l = lgdal.OGR_DS_GetLayerByName(self._ds, c_char_p(index))
if not l: raise IndexError, 'invalid OGR Layer name given: "%s"' % index
if not l: raise OGRIndexError('invalid OGR Layer name given: "%s"' % index)
else:
if index < 0 or index >= self.layer_count:
raise IndexError, 'index out of range'
raise OGRIndexError('index out of range')
l = lgdal.OGR_DS_GetLayer(self._ds, c_int(index))
return Layer(l)

View File

@ -45,11 +45,11 @@ class Driver(object):
elif isinstance(input, c_void_p):
dr = input
else:
raise OGRException, 'Unrecognized input type for OGR Driver: %s' % str(type(input))
raise OGRException('Unrecognized input type for OGR Driver: %s' % str(type(input)))
# Making sure we get a valid pointer to the OGR Driver
if not dr:
raise OGRException, 'Could not initialize OGR Driver on input: %s' % str(input)
raise OGRException('Could not initialize OGR Driver on input: %s' % str(input))
self._dr = dr
def __str__(self):
@ -61,7 +61,7 @@ class Driver(object):
# Only register all if the driver count is 0 (or else all drivers
# will be registered over and over again)
if not self.driver_count and not lgdal.OGRRegisterAll():
raise OGRException, 'Could not register all the OGR data source drivers!'
raise OGRException('Could not register all the OGR data source drivers!')
# Driver properties
@property

View File

@ -1,6 +1,3 @@
from ctypes import Structure, c_double
from types import TupleType
"""
The GDAL/OGR library uses an Envelope structure to hold the bounding
box information for a geometry. The envelope (bounding box) contains
@ -14,6 +11,9 @@ from types import TupleType
Lower left (min_x, min_y) o----------+
"""
from ctypes import Structure, c_double
from types import TupleType, ListType
from django.contrib.gis.gdal.error import OGRException
# The OGR definition of an Envelope is a C structure containing four doubles.
# See the 'ogr_core.h' source file for more information:
@ -27,25 +27,48 @@ class OGREnvelope(Structure):
]
class Envelope(object):
"A class that will wrap an OGR Envelope structure."
"""
The Envelope object is a C structure that contains the minimum and
maximum X, Y coordinates for a rectangle bounding box. The naming
of the variables is compatible with the OGR Envelope structure.
"""
def __init__(self, *args):
"""
The initialization function may take an OGREnvelope structure, 4-element
tuple or list, or 4 individual arguments.
"""
if len(args) == 1:
if isinstance(args[0], OGREnvelope):
# OGREnvelope (a ctypes Structure) was passed in.
self._envelope = args[0]
elif isinstance(args[0], TupleType) and len(args[0]) == 4:
# A Tuple was passed in
self._from_tuple(args[0])
elif isinstance(args[0], (TupleType, ListType)):
# A tuple was passed in.
if len(args[0]) != 4:
raise OGRException('Incorrect number of tuple elements (%d).' % len(args[0]))
else:
self._from_sequence(args[0])
else:
raise OGRException, 'Incorrect type of argument: %s' % str(type(args[0]))
raise TypeError('Incorrect type of argument: %s' % str(type(args[0])))
elif len(args) == 4:
self._from_tuple(args)
# Individiual parameters passed in.
# Thanks to ww for the help
self._from_sequence(map(float, args))
else:
raise OGRException, 'Incorrect number of arguments!'
raise OGRException('Incorrect number (%d) of arguments.' % len(args))
# Checking the x,y coordinates
if self.min_x >= self.max_x:
raise OGRException('Envelope minimum X >= maximum X.')
if self.min_y >= self.max_y:
raise OGRException('Envelope minimum Y >= maximum Y.')
def __eq__(self, other):
"Returns true if the envelopes are equivalent; can compare against other Envelopes and 4-tuples."
"""
Returns True if the envelopes are equivalent; can compare against
other Envelopes and 4-tuples.
"""
if isinstance(other, Envelope):
return (self.min_x == other.min_x) and (self.min_y == other.min_y) and \
(self.max_x == other.max_x) and (self.max_y == other.max_y)
@ -53,19 +76,19 @@ class Envelope(object):
return (self.min_x == other[0]) and (self.min_y == other[1]) and \
(self.max_x == other[2]) and (self.max_y == other[3])
else:
raise OGRException, 'Equivalence testing only works with other Envelopes.'
raise OGRException('Equivalence testing only works with other Envelopes.')
def __str__(self):
"Returns a string representation of the tuple."
return str(self.tuple)
def _from_tuple(self, tup):
"Initializes the C OGR Envelope structure from the given tuple."
def _from_sequence(self, seq):
"Initializes the C OGR Envelope structure from the given sequence."
self._envelope = OGREnvelope()
self._envelope.MinX = tup[0]
self._envelope.MinY = tup[1]
self._envelope.MaxX = tup[2]
self._envelope.MaxY = tup[3]
self._envelope.MinX = seq[0]
self._envelope.MinY = seq[1]
self._envelope.MaxX = seq[2]
self._envelope.MaxY = seq[3]
@property
def min_x(self):
@ -106,7 +129,7 @@ class Envelope(object):
def wkt(self):
"Returns WKT representing a Polygon for this envelope."
# TODO: Fix significant figures.
return 'POLYGON((%s %s,%s %s,%s %s,%s %s,%s %s))' % (self.min_x, self.min_y, self.min_x, self.max_y,
self.max_x, self.max_y, self.max_x, self.min_y,
self.min_x, self.min_y)
return 'POLYGON((%s %s,%s %s,%s %s,%s %s,%s %s))' % \
(self.min_x, self.min_y, self.min_x, self.max_y,
self.max_x, self.max_y, self.max_x, self.min_y,
self.min_x, self.min_y)

View File

@ -7,6 +7,7 @@ from django.contrib.gis.gdal.libgdal import lgdal
from django.contrib.gis.gdal.error import OGRException, OGRIndexError
from django.contrib.gis.gdal.field import Field
from django.contrib.gis.gdal.geometries import OGRGeometry, OGRGeomType
from django.contrib.gis.gdal.srs import SpatialReference
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
@ -21,7 +22,7 @@ class Feature(object):
self._feat = 0 # Initially NULL
self._fdefn = 0
if not f:
raise OGRException, 'Cannot create OGR Feature, invalid pointer given.'
raise OGRException('Cannot create OGR Feature, invalid pointer given.')
self._feat = f
self._fdefn = lgdal.OGR_F_GetDefnRef(f)
@ -35,7 +36,7 @@ class Feature(object):
i = self.index(index)
else:
if index < 0 or index > self.num_fields:
raise OGRIndexError, 'index out of range'
raise OGRIndexError('index out of range')
i = index
return Field(lgdal.OGR_F_GetFieldDefnRef(self._feat, c_int(i)),
string_at(lgdal.OGR_F_GetFieldAsString(self._feat, c_int(i))))
@ -84,8 +85,20 @@ class Feature(object):
@property
def geom(self):
"Returns the OGR Geometry for this Feature."
# A clone is used, so destruction of the Geometry won't bork the Feature.
return OGRGeometry(lgdal.OGR_G_Clone(lgdal.OGR_F_GetGeometryRef(self._feat)))
# Retrieving the geometry pointer for the feature.
geom_ptr = lgdal.OGR_F_GetGeometryRef(self._feat)
if not geom_ptr:
raise OGRException('Cannot retrieve Geometry from the feature.')
# Attempting to retrieve the Spatial Reference for the geometry.
srs_ptr = lgdal.OGR_G_GetSpatialReference(geom_ptr)
if srs_ptr:
srs = SpatialReference(srs_ptr, 'ogr')
else:
srs = None
# Geometry is cloned so the feature isn't invalidated.
return OGRGeometry(lgdal.OGR_G_Clone(geom_ptr), srs)
@property
def geom_type(self):
@ -105,7 +118,7 @@ class Feature(object):
def index(self, field_name):
"Returns the index of the given field name."
i = lgdal.OGR_F_GetFieldIndex(self._feat, c_char_p(field_name))
if i < 0: raise OGRIndexError, 'invalid OFT field name given: "%s"' % field_name
if i < 0: raise OGRIndexError('invalid OFT field name given: "%s"' % field_name)
return i
def clone(self):

View File

@ -1,5 +1,4 @@
from ctypes import string_at
from django.contrib.gis.gdal.libgdal import lgdal
from django.contrib.gis.gdal.error import OGRException
@ -16,7 +15,7 @@ class Field(object):
self._fld = 0 # Initially NULL
if not fld:
raise OGRException, 'Cannot create OGR Field, invalid pointer given.'
raise OGRException('Cannot create OGR Field, invalid pointer given.')
self._fld = fld
self._val = val
@ -64,7 +63,10 @@ class OFTReal(Field):
return None
class OFTRealList(Field): pass
class OFTString(Field): pass
class OFTString(Field):
def __str__(self):
return '%s ("%s")' % (self.name, self.value)
class OFTStringList(Field): pass
class OFTWideString(Field): pass
class OFTWideStringList(Field): pass

View File

@ -1,24 +1,13 @@
# types & ctypes
from types import IntType, StringType
from ctypes import byref, string_at, c_char_p, c_double, c_int, c_void_p
# Getting geodjango gdal prerequisites
from django.contrib.gis.gdal.libgdal import lgdal
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
from django.contrib.gis.gdal.error import check_err, OGRException, OGRIndexError
from django.contrib.gis.gdal.geomtype import OGRGeomType
from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform
"""
The OGRGeometry is a wrapper for using the OGR Geometry class
(see http://www.gdal.org/ogr/classOGRGeometry.html). OGRGeometry
may be instantiated when reading geometries from OGR Data Sources
(e.g. SHP files), or when given OGC WKT (a string).
(see http://www.gdal.org/ogr/classOGRGeometry.html). OGRGeometry
may be instantiated when reading geometries from OGR Data Sources
(e.g. SHP files), or when given OGC WKT (a string).
While the 'full' API is not present yet, the API is "pythonic" unlike
the traditional and "next-generation" OGR Python bindings. One major
advantage OGR Geometries have over their GEOS counterparts is support
for spatial reference systems and their transformation.
the traditional and "next-generation" OGR Python bindings. One major
advantage OGR Geometries have over their GEOS counterparts is support
for spatial reference systems and their transformation.
Example:
>>> from django.contrib.gis.gdal import OGRGeometry, OGRGeomType, SpatialReference
@ -49,6 +38,16 @@ from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform
>>> print gt1 == 3, gt1 == 'Polygon' # Equivalence works w/non-OGRGeomType objects
True
"""
# types & ctypes
from types import IntType, StringType
from ctypes import byref, string_at, c_char_p, c_double, c_int, c_void_p
# Getting GDAL prerequisites
from django.contrib.gis.gdal.libgdal import lgdal
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
from django.contrib.gis.gdal.error import check_err, OGRException, OGRIndexError
from django.contrib.gis.gdal.geomtype import OGRGeomType
from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
@ -75,37 +74,45 @@ get_area.argtypes = [c_void_p]
class OGRGeometry(object):
"Generally encapsulates an OGR geometry."
def __init__(self, input, srs=False):
def __init__(self, geom_input, srs=None):
"Initializes Geometry on either WKT or an OGR pointer as input."
self._g = 0 # Initially NULL
self._init_srs(srs)
if isinstance(input, StringType):
if isinstance(geom_input, StringType):
# First, trying the input as WKT
buf = c_char_p(input)
buf = c_char_p(geom_input)
g = c_void_p()
try:
check_err(lgdal.OGR_G_CreateFromWkt(byref(buf), self._s._srs, byref(g)))
except OGRException, msg:
check_err(lgdal.OGR_G_CreateFromWkt(byref(buf), c_void_p(), byref(g)))
except OGRException:
try:
ogr_t = OGRGeomType(input) # Seeing if the input is a valid short-hand string
# Seeing if the input is a valid short-hand string
ogr_t = OGRGeomType(geom_input)
g = lgdal.OGR_G_CreateGeometry(ogr_t.num)
except:
raise OGRException, 'Could not initialize on WKT "%s"' % input
elif isinstance(input, OGRGeomType):
g = lgdal.OGR_G_CreateGeometry(input.num)
lgdal.OGR_G_AssignSpatialReference(g, self._s._srs)
elif isinstance(input, IntType):
raise OGRException('Could not initialize OGR Geometry from: %s' % geom_input)
elif isinstance(geom_input, OGRGeomType):
g = lgdal.OGR_G_CreateGeometry(geom_input.num)
elif isinstance(geom_input, IntType):
# OGR Pointer (integer) was the input
g = input
g = geom_input
else:
raise OGRException, 'Type of input cannot be determined!'
raise OGRException('Type of input cannot be determined!')
# Assigning the SpatialReference object to the geometry, if valid.
if bool(srs):
if isinstance(srs, SpatialReference):
srs_ptr = srs._srs
else:
sr = SpatialReference(srs)
srs_ptr = sr._srs
lgdal.OGR_G_AssignSpatialReference(g, srs_ptr)
# Now checking the Geometry pointer before finishing initialization
if not g:
raise OGRException, 'Cannot create OGR Geometry from input: %s' % str(input)
raise OGRException('Cannot create OGR Geometry from input: %s' % str(geom_input))
self._g = g
# Setting the class depending upon the OGR Geometry Type
@ -115,13 +122,6 @@ class OGRGeometry(object):
"Deletes this Geometry."
if self._g: lgdal.OGR_G_DestroyGeometry(self._g)
def _init_srs(self, srs):
# Getting the spatial
if not isinstance(srs, SpatialReference):
self._s = SpatialReference() # creating an empty spatial reference
else:
self._s = srs.clone() # cloning the given spatial reference
### Geometry set-like operations ###
# g = g1 | g2
def __or__(self, other):
@ -184,7 +184,11 @@ class OGRGeometry(object):
@property
def srs(self):
"Returns the Spatial Reference for this Geometry."
return SpatialReference(lgdal.OSRClone(lgdal.OGR_G_GetSpatialReference(self._g)), 'ogr')
srs_ptr = lgdal.OGR_G_GetSpatialReference(self._g)
if srs_ptr:
return SpatialReference(lgdal.OSRClone(srs_ptr), 'ogr')
else:
return None
@property
def geom_type(self):
@ -196,13 +200,6 @@ class OGRGeometry(object):
"Returns the Name of this Geometry."
return string_at(lgdal.OGR_G_GetGeometryName(self._g))
@property
def wkt(self):
"Returns the WKT form of the Geometry."
buf = c_char_p()
check_err(lgdal.OGR_G_ExportToWkt(self._g, byref(buf)))
return string_at(buf)
@property
def area(self):
"Returns the area for a LinearRing, Polygon, or MultiPolygon; 0 otherwise."
@ -215,6 +212,21 @@ class OGRGeometry(object):
lgdal.OGR_G_GetEnvelope(self._g, byref(env))
return Envelope(env)
#### Output Methods ####
@property
def gml(self):
"Returns the GML representation of the Geometry."
buf = c_char_p()
check_err(lgdal.OGR_G_ExportToGML(self._g, byref(buf)))
return string_at(buf)
@property
def wkt(self):
"Returns the WKT representation of the Geometry."
buf = c_char_p()
check_err(lgdal.OGR_G_ExportToWkt(self._g, byref(buf)))
return string_at(buf)
#### Geometry Methods ####
def clone(self):
"Clones this OGR Geometry."
@ -230,13 +242,13 @@ class OGRGeometry(object):
def transform(self, coord_trans):
"Transforms this Geometry with the given CoordTransform object."
if not isinstance(coord_trans, CoordTransform):
raise OGRException, 'CoordTransform object required for transform.'
raise OGRException('CoordTransform object required for transform.')
check_err(lgdal.OGR_G_Transform(self._g, coord_trans._ct))
def transform_to(self, srs):
"Transforms this Geometry with the given SpatialReference."
if not isinstance(srs, SpatialReference):
raise OGRException, 'SpatialReference object required for transform_to.'
raise OGRException('SpatialReference object required for transform_to.')
check_err(lgdal.OGR_G_TransformTo(self._g, srs._srs))
#### Topology Methods ####
@ -244,7 +256,7 @@ class OGRGeometry(object):
"""A generalized function for topology operations, takes a GDAL function and
the other geometry to perform the operation on."""
if not isinstance(other, OGRGeometry):
raise OGRException, 'Must use another OGRGeometry object for topology operations!'
raise OGRException('Must use another OGRGeometry object for topology operations!')
# Calling the passed-in topology function with the other geometry
status = topo_func(self._g, other._g)
@ -368,7 +380,7 @@ class LineString(OGRGeometry):
elif self.coord_dim == 3:
return (x.value, y.value, z.value)
else:
raise OGRIndexError, 'index out of range: %s' % str(index)
raise OGRIndexError('index out of range: %s' % str(index))
def __iter__(self):
"Iterates over each point in the LineString."
@ -401,9 +413,9 @@ class Polygon(OGRGeometry):
def __getitem__(self, index):
"Gets the ring at the specified index."
if index < 0 or index >= self.geom_count:
raise OGRIndexError, 'index out of range: %s' % str(index)
raise OGRIndexError('index out of range: %s' % str(index))
else:
return OGRGeometry(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index))))
return OGRGeometry(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index))), self.srs)
# Polygon Properties
@property
@ -437,9 +449,9 @@ class GeometryCollection(OGRGeometry):
def __getitem__(self, index):
"Gets the Geometry at the specified index."
if index < 0 or index >= self.geom_count:
raise OGRIndexError, 'index out of range: %s' % str(index)
raise OGRIndexError('index out of range: %s' % str(index))
else:
return OGRGeometry(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index))))
return OGRGeometry(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index))), self.srs)
def __iter__(self):
"Iterates over each Geometry."
@ -458,7 +470,7 @@ class GeometryCollection(OGRGeometry):
tmp = OGRGeometry(geom)
ptr = tmp._g
else:
raise OGRException, 'Must add an OGRGeometry.'
raise OGRException('Must add an OGRGeometry.')
lgdal.OGR_G_AddGeometry(self._g, ptr)
@property

View File

@ -11,21 +11,21 @@ class OGRGeomType(object):
'LinearRing']
__ogr_int = [1, 2, 3, 4, 5, 6, 7, 101]
def __init__(self, input):
def __init__(self, type_input):
"Figures out the correct OGR Type based upon the input."
if isinstance(input, OGRGeomType):
self._index = input._index
elif isinstance(input, StringType):
idx = self._has_str(self.__ogr_str, input)
if isinstance(type_input, OGRGeomType):
self._index = type_input._index
elif isinstance(type_input, StringType):
idx = self._has_str(self.__ogr_str, type_input)
if idx == None:
raise OGRException, 'Invalid OGR String Type "%s"' % input
raise OGRException('Invalid OGR String Type "%s"' % type_input)
self._index = idx
elif isinstance(input, int):
if not input in self.__ogr_int:
raise OGRException, 'Invalid OGR Integer Type: %d' % input
self._index = self.__ogr_int.index(input)
elif isinstance(type_input, int):
if not type_input in self.__ogr_int:
raise OGRException('Invalid OGR Integer Type: %d' % type_input)
self._index = self.__ogr_int.index(type_input)
else:
raise TypeError, 'Invalid OGR Input type given!'
raise TypeError('Invalid OGR Input type given!')
def __str__(self):
"Returns a short-hand string form of the OGR Geometry type."
@ -44,7 +44,7 @@ class OGRGeomType(object):
if not other in self.__ogr_int: return False
return self.__ogr_int.index(other) == self._index
else:
raise TypeError, 'Cannot compare with type: %s' % str(type(other))
raise TypeError('Cannot compare with type: %s' % str(type(other)))
def _has_str(self, arr, s):
"Case-insensitive search of the string array for the given pattern."

View File

@ -79,7 +79,7 @@ class SpatialReference(object):
_epsg_regex = re.compile('^EPSG:(?P<epsg>\d+)$', re.I)
#### Python 'magic' routines ####
def __init__(self, input='', srs_type='wkt'):
def __init__(self, srs_input='', srs_type='wkt'):
"Creates a spatial reference object from the given OGC Well Known Text (WKT)."
self._srs = 0 # Initially NULL
@ -87,45 +87,46 @@ class SpatialReference(object):
# Creating an initial empty string buffer.
buf = c_char_p('')
if isinstance(input, UnicodeType):
input = input.encode('ascii')
# Encoding to ASCII if unicode passed in.
if isinstance(srs_input, UnicodeType):
srs_input = srs_input.encode('ascii')
if isinstance(input, StringType):
if isinstance(srs_input, StringType):
# Is this an EPSG well known name?
m = self._epsg_regex.match(input)
m = self._epsg_regex.match(srs_input)
if m:
srs_type = 'epsg'
input = int(m.group('epsg'))
srs_input = int(m.group('epsg'))
# Is this a short-hand well known name?
elif input in self._well_known:
elif srs_input in self._well_known:
srs_type = 'epsg'
input = self._well_known[input]
srs_input = self._well_known[srs_input]
elif srs_type == 'proj':
pass
else:
buf = c_char_p(input)
elif isinstance(input, int):
buf = c_char_p(srs_input)
elif isinstance(srs_input, int):
if srs_type == 'wkt': srs_type = 'epsg' # want to try epsg if only integer provided
if srs_type not in ('epsg', 'ogr'):
raise SRSException, 'Integer input requires SRS type of "ogr" or "epsg".'
raise SRSException('Integer input requires SRS type of "ogr" or "epsg".')
else:
raise TypeError, 'Invalid SRS type "%s"' % srs_type
raise TypeError('Invalid SRS type "%s"' % srs_type)
# Calling OSRNewSpatialReference with the string buffer.
if srs_type == 'ogr':
srs = input # Input is OGR pointer
srs = srs_input # SRS input is OGR pointer
else:
srs = lgdal.OSRNewSpatialReference(buf)
# If the pointer is NULL, throw an exception.
if not srs:
raise SRSException, 'Could not create spatial reference from WKT! (%s)' % input
raise SRSException('Could not create spatial reference from: %s' % srs_input)
else:
self._srs = srs
# Post-processing if in PROJ.4 or EPSG formats.
if srs_type == 'proj': self.import_proj(input)
elif srs_type == 'epsg': self.import_epsg(input)
if srs_type == 'proj': self.import_proj(srs_input)
elif srs_type == 'epsg': self.import_epsg(srs_input)
def __del__(self):
"Destroys this spatial reference."
@ -142,6 +143,14 @@ class SpatialReference(object):
else:
return self.attr_value(target)
def __nonzero__(self):
"Returns True if this SpatialReference object is valid."
try:
self.validate()
return True
except OGRException:
return False
def __str__(self):
"The string representation uses 'pretty' WKT."
return self.pretty_wkt
@ -189,6 +198,14 @@ class SpatialReference(object):
elif self.local: return self.attr_value('LOCAL_CS')
else: return None
@property
def srid(self):
"""
Returns the EPSG SRID of this Spatial Reference, will be None if
if undefined.
"""
return self.srs['AUTHORITY', 1]
#### Unit Properties ####
def _cache_linear(self):
"Caches the linear units value and name."
@ -345,10 +362,10 @@ class CoordTransform(object):
"Initializes on a source and target SpatialReference objects."
self._ct = 0 # Initially NULL
if not isinstance(source, SpatialReference) or not isinstance(target, SpatialReference):
raise SRSException, 'source and target must be of type SpatialReference'
raise SRSException('source and target must be of type SpatialReference')
ct = lgdal.OCTNewCoordinateTransformation(source._srs, target._srs)
if not ct:
raise SRSException, 'could not intialize CoordTransform object'
raise SRSException('could not intialize CoordTransform object')
self._ct = ct
self._srs1_name = source.name
self._srs2_name = target.name

View File

@ -13,6 +13,7 @@ if HAS_GDAL:
test_suite_names += [
'test_gdal_driver',
'test_gdal_ds',
'test_gdal_envelope',
'test_gdal_geom',
'test_gdal_srs',
'test_spatialrefsys',

View File

@ -0,0 +1,24 @@
from unittest import TestSuite, TextTestRunner
# Importing the GDAL test modules.
from django.contrib.gis.tests import \
test_gdal_driver, test_gdal_ds, test_gdal_envelope, \
test_gdal_geom, test_gdal_srs
test_suites = [test_gdal_driver.suite(),
test_gdal_ds.suite(),
test_gdal_envelope.suite(),
test_gdal_geom.suite(),
test_gdal_srs.suite(),
]
def suite():
"Builds a test suite for the GDAL tests."
s = TestSuite()
map(s.addTest, test_suites)
return s
def run(verbosity=1):
"Runs the tests that do not require geographic (GEOS, GDAL, etc.) models."
TextTestRunner(verbosity=verbosity).run(suite())

View File

@ -1,6 +1,5 @@
import os, os.path, unittest
from django.contrib.gis.gdal import DataSource, OGRException
from django.contrib.gis.gdal.envelope import Envelope
from django.contrib.gis.gdal import DataSource, Envelope, OGRException, OGRIndexError
from django.contrib.gis.gdal.field import OFTReal, OFTInteger, OFTString
# Path for SHP files
@ -48,7 +47,7 @@ class DataSourceTest(unittest.TestCase):
# Making sure indexing works
try:
ds[len(ds)]
except IndexError:
except OGRIndexError:
pass
else:
self.fail('Expected an IndexError!')
@ -106,7 +105,9 @@ class DataSourceTest(unittest.TestCase):
# Asserting the string representation, and making sure we get
# the proper OGR Field instance.
self.assertEqual('%s (%s)' % (k, fld.value), str(fld))
if isinstance(fld, OFTString): fmt = '%s ("%s")'
else: fmt = '%s (%s)'
self.assertEqual(fmt % (k, fld.value), str(fld))
self.assertEqual(True, isinstance(fld, v))
# Testing __iter__ on the Feature
@ -136,5 +137,3 @@ def suite():
def run(verbosity=2):
unittest.TextTestRunner(verbosity=verbosity).run(suite())

View File

@ -0,0 +1,45 @@
import unittest
from django.contrib.gis.gdal import Envelope, OGRException
class EnvelopeTest(unittest.TestCase):
def test01_init(self):
"Testing Envelope initilization."
e1 = Envelope((0, 0, 5, 5))
e2 = Envelope(0, 0, 5, 5)
e3 = Envelope(0, '0', '5', 5) # Thanks to ww for this
e4 = Envelope(e1._envelope)
self.assertRaises(OGRException, Envelope, (5, 5, 0, 0))
self.assertRaises(OGRException, Envelope, 5, 5, 0, 0)
self.assertRaises(OGRException, Envelope, (0, 0, 5, 5, 3))
self.assertRaises(OGRException, Envelope, ())
self.assertRaises(ValueError, Envelope, 0, 'a', 5, 5)
self.assertRaises(TypeError, Envelope, u'foo')
def test02_properties(self):
"Testing Envelope properties."
e = Envelope(0, 0, 2, 3)
self.assertEqual(0, e.min_x)
self.assertEqual(0, e.min_y)
self.assertEqual(2, e.max_x)
self.assertEqual(3, e.max_y)
self.assertEqual((0, 0), e.ll)
self.assertEqual((2, 3), e.ur)
self.assertEqual((0, 0, 2, 3), e.tuple)
self.assertEqual('POLYGON((0.0 0.0,0.0 3.0,2.0 3.0,2.0 0.0,0.0 0.0))', e.wkt)
self.assertEqual('(0.0, 0.0, 2.0, 3.0)', str(e))
def test03_equivalence(self):
"Testing Envelope equivalence."
e1 = Envelope(0.523, 0.217, 253.23, 523.69)
e2 = Envelope((0.523, 0.217, 253.23, 523.69))
self.assertEqual(e1, e2)
self.assertEqual((0.523, 0.217, 253.23, 523.69), e1)
def suite():
s = unittest.TestSuite()
s.addTest(unittest.makeSuite(EnvelopeTest))
return s
def run(verbosity=2):
unittest.TextTestRunner(verbosity=verbosity).run(suite())

View File

@ -1,5 +1,5 @@
import unittest
from django.contrib.gis.gdal import OGRGeometry, OGRGeomType, OGRException
from django.contrib.gis.gdal import OGRGeometry, OGRGeomType, OGRException, SpatialReference
from geometries import *
class OGRGeomTest(unittest.TestCase):
@ -130,6 +130,18 @@ class OGRGeomTest(unittest.TestCase):
self.assertEqual(mp.n_p, mpoly.point_count)
self.assertEqual(mp.num_geom, len(mpoly))
def test09_srs(self):
"Testing OGR Geometries with Spatial Reference objects."
for mp in multipolygons:
sr = SpatialReference('WGS84')
mpoly = OGRGeometry(mp.wkt, sr)
self.assertEqual(sr.wkt, mpoly.srs.wkt)
for poly in mpoly:
self.assertEqual(sr.wkt, poly.srs.wkt)
for ring in poly:
self.assertEqual(sr.wkt, ring.srs.wkt)
def suite():
s = unittest.TestSuite()
s.addTest(unittest.makeSuite(OGRGeomTest))