1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +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:
raise OGRException, 'Incorrect type of argument: %s' % str(type(args[0]))
self._from_sequence(args[0])
else:
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,
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,14 +1,3 @@
# 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
@ -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))