1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

gis: GDAL improvements; added Driver class, improved tests, removed non-existent exception, updated geometries for tests, updated documentation.

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@5478 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Justin Bronn 2007-06-15 06:02:04 +00:00
parent b0b7bbced7
commit 48c9f87e1f
14 changed files with 500 additions and 78 deletions

View File

@ -6,12 +6,20 @@ from ctypes import c_char_p, c_int, c_void_p, byref, string_at
from django.contrib.gis.gdal.libgdal import lgdal
from django.contrib.gis.gdal.OGRError import OGRException, check_err
from django.contrib.gis.gdal.Layer import Layer
from django.contrib.gis.gdal.Driver import Driver
"""
DataSource is a wrapper for the OGR Data Source object, which provides
an interface for reading vector geometry data from many different file
formats (including ESRI shapefiles).
When instantiating a DataSource object, use the filename of a
GDAL-supported data source. For example, a SHP file or a
TIGER/Line file from the government.
The ds_driver keyword is used internally when a ctypes pointer
is passed in directly.
Example:
ds = DataSource('/home/foo/bar.shp')
for layer in ds:
@ -22,13 +30,24 @@ from django.contrib.gis.gdal.Layer import Layer
# Getting the 'description' field for the feature.
desc = feature['description']
More documentation forthcoming.
# We can also increment through all of the fields
# attached to this feature.
for field in feature:
# Get the name of the field (e.g. 'description')
nm = field.name
# Get the type (integer) of the field, e.g. 0 => OFTInteger
t = field.type
# Returns the value the field; OFTIntegers return ints,
# OFTReal returns floats, all else returns string.
val = field.value
"""
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
#
# The OGR_DS* routines are relevant here.
# The OGR_DS_* routines are relevant here.
class DataSource(object):
"Wraps an OGR Data Source object."
@ -36,26 +55,32 @@ class DataSource(object):
_ds = 0 # Initially NULL
#### Python 'magic' routines ####
def __init__(self, ds_file):
def __init__(self, ds_input, ds_driver=False):
# Registering all the drivers, this needs to be done
# _before_ we try to open up a data source.
if not lgdal.OGRRegisterAll():
raise OGRException, 'Could not register all data source drivers!'
if not lgdal.OGRGetDriverCount() and not lgdal.OGRRegisterAll():
raise OGRException, 'Could not register all the OGR data source drivers!'
# The data source driver is a void pointer.
ds_driver = c_void_p()
if isinstance(ds_input, StringType):
# OGROpen will auto-detect the data source type.
ds = lgdal.OGROpen(c_char_p(ds_file), c_int(0), byref(ds_driver))
# The data source driver is a void pointer.
ds_driver = c_void_p()
# OGROpen will auto-detect the data source type.
ds = lgdal.OGROpen(c_char_p(ds_input), c_int(0), byref(ds_driver))
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 an exception if the returned pointer is NULL
if not ds:
self._ds = False
raise OGRException, 'Invalid data source file "%s"' % ds_file
raise OGRException, 'Invalid data source file "%s"' % ds_input
else:
self._ds = ds
self._driver = ds_driver
self._driver = Driver(ds_driver)
def __del__(self):
"This releases the reference to the data source (destroying it if it's the only one)."
@ -83,13 +108,13 @@ class DataSource(object):
def __str__(self):
"Returns OGR GetName and Driver for the Data Source."
return '%s (%s)' % (self.name, self.driver)
return '%s (%s)' % (self.name, str(self.driver))
#### DataSource Properties ####
@property
def driver(self):
"Returns the name of the data source driver."
return string_at(lgdal.OGR_Dr_GetName(self._driver))
"Returns the Driver object for this Data Source."
return self._driver
@property
def layer_count(self):

View File

@ -0,0 +1,86 @@
# types and ctypes
from types import StringType
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.OGRError import OGRException
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
#
# The OGR_Dr_* routines are relevant here.
class Driver(object):
"Wraps an OGR Data Source Driver."
_dr = 0 # Initially NULL
# Case-insensitive aliases for OGR Drivers.
_alias = {'esri' : 'ESRI Shapefile',
'shp' : 'ESRI Shapefile',
'shape' : 'ESRI Shapefile',
'tiger' : 'TIGER',
'tiger/line' : 'TIGER',
}
def __init__(self, input, ptr=False):
"Initializes an OGR driver on either a string or integer input."
if isinstance(input, StringType):
# If a string name of the driver was passed in
self._register()
# Checking the alias dictionary (case-insensitive) to see if an alias
# exists for the given driver.
if input.lower() in self._alias:
name = c_char_p(self._alias[input.lower()])
else:
name = c_char_p(input)
# Attempting to get the OGR driver by the string name.
dr = lgdal.OGRGetDriverByName(name)
elif isinstance(input, int):
self._register()
dr = lgdal.OGRGetDriver(c_int(input))
elif isinstance(input, c_void_p):
dr = input
else:
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)
self._dr = dr
def __str__(self):
"Returns the string name of the OGR Driver."
return string_at(lgdal.OGR_Dr_GetName(self._dr))
def _register(self):
"Attempts to register all the data source drivers."
# 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!'
# Driver properties
@property
def driver_count(self):
"Returns the number of OGR data source drivers registered."
return lgdal.OGRGetDriverCount()
def create_ds(self, **kwargs):
"Creates a data source using the keyword args as name value options."
raise NotImplementedError
# Getting the options string
#options = ''
#n_opts = len(kwargs)
#for i in xrange(n_opts):
# options += '%s=%s' % (str(k), str(v))
# if i < n_opts-1: options += ','
#opts = c_char_p(options)

View File

@ -1,5 +1,5 @@
# types and ctypes
import types
from types import StringType
from ctypes import c_char_p, c_int, string_at
# The GDAL C library, OGR exception, and the Field object
@ -31,7 +31,7 @@ class Feature(object):
def __getitem__(self, index):
"Gets the Field at the specified index."
if isinstance(index, types.StringType):
if isinstance(index, StringType):
i = self.index(index)
else:
if index < 0 or index > self.num_fields:

View File

@ -8,7 +8,7 @@ from django.contrib.gis.gdal.OGRError import OGRException
#
# The OGR_Fld_* routines are relevant here.
class Field(object):
"A class that wraps an OGR Field."
"A class that wraps an OGR Field, needs to be instantiated from a Feature object."
_fld = 0 # Initially NULL

View File

@ -1,14 +1,53 @@
# types & ctypes
from types import StringType
from ctypes import \
byref, string_at, create_string_buffer, POINTER, \
c_char_p, c_double, c_int, c_void_p
from types import IntType, StringType
from ctypes import byref, string_at, c_char_p, c_double, c_int, c_void_p
# Getting the GDAL C library and error checking facilities
from django.contrib.gis.gdal.libgdal import lgdal
from django.contrib.gis.gdal.OGRError import check_err, OGRException
from django.contrib.gis.gdal.SpatialReference 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).
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.
Example:
>>> from django.contrib.gis.gdal import OGRGeometry, OGRGeomType, SpatialReference
>>> wkt1, wkt2 = 'POINT(-90 30)', 'POLYGON((0 0, 5 0, 5 5, 0 5)'
>>> pnt = OGRGeometry(wkt1)
>>> print pnt
POINT (-90 30)
>>> mpnt = OGRGeometry(OGRGeomType('MultiPoint'), SpatialReference('WGS84'))
>>> mpnt.add(wkt1)
>>> mpnt.add(wkt1)
>>> print mpnt
MULTIPOINT (-90 30,-90 30)
>>> print mpnt.srs.name
WGS 84
>>> print mpnt.srs.proj
+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs
>>> mpnt.transform_to(SpatialReference('NAD27'))
>>> print mpnt.proj
+proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs
>>> print mpnt
MULTIPOINT (-89.999930378602485 29.999797886557641,-89.999930378602485 29.999797886557641)
The OGRGeomType class is to make it easy to specify an OGR geometry type:
>>> from django.contrib.gis.gdal import OGRGeomType
>>> gt1 = OGRGeomType(3) # Using an integer for the type
>>> gt2 = OGRGeomType('Polygon') # Using a string
>>> gt3 = OGRGeomType('POLYGON') # It's case-insensitive
>>> print gt1 == 3, gt1 == 'Polygon' # Equivalence works w/non-OGRGeomType objects
True
"""
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
#
@ -29,10 +68,10 @@ class OGRGeomType(object):
"Encapulates OGR Geometry Types."
# Ordered array of acceptable strings and their corresponding OGRwkbGeometryType
__ogr_str = ['Unknown', 'Point', 'LineString', 'Polygon', 'MultiPoint',
__ogr_str = ['Point', 'LineString', 'Polygon', 'MultiPoint',
'MultiLineString', 'MultiPolygon', 'GeometryCollection',
'None', 'LinearRing']
__ogr_int = [0, 1, 2, 3, 4, 5, 6, 7, 100, 101]
'LinearRing']
__ogr_int = [1, 2, 3, 4, 5, 6, 7, 101]
def __init__(self, input):
"Figures out the correct OGR Type based upon the input."
@ -40,7 +79,7 @@ class OGRGeomType(object):
self._index = input._index
elif isinstance(input, StringType):
idx = self._has_str(self.__ogr_str, input)
if not idx:
if idx == None:
raise OGRException, 'Invalid OGR String Type "%s"' % input
self._index = idx
elif isinstance(input, int):
@ -61,7 +100,7 @@ class OGRGeomType(object):
return self._index == other._index
elif isinstance(other, StringType):
idx = self._has_str(self.__ogr_str, other)
if idx: return self._index == idx
if not (idx == None): return self._index == idx
return False
elif isinstance(other, int):
if not other in self.__ogr_int: return False
@ -70,9 +109,10 @@ class OGRGeomType(object):
raise TypeError, 'Cannot compare with type: %s' % str(type(other))
def _has_str(self, arr, s):
slow = s.lower()
"Case-insensitive search of the string array for the given pattern."
s_low = s.lower()
for i in xrange(len(arr)):
if slow == arr[i].lower(): return i
if s_low == arr[i].lower(): return i
return None
@property
@ -99,18 +139,15 @@ class OGRGeometry(object):
"Initializes Geometry on either WKT or an OGR pointer as input."
if isinstance(input, StringType):
# Getting the spatial reference
self._init_srs(srs)
# First, trying the input as WKT
buf = c_char_p(input)
g = c_void_p()
# Getting the spatial
if not isinstance(srs, SpatialReference):
s = SpatialReference() # creating an empty spatial reference
else:
s = srs.clone() # cloning the given spatial reference
try:
check_err(lgdal.OGR_G_CreateFromWkt(byref(buf), s._srs, byref(g)))
check_err(lgdal.OGR_G_CreateFromWkt(byref(buf), self._s._srs, byref(g)))
except OGRException, msg:
try:
ogr_t = OGRGeomType(input) # Seeing if the input is a valid short-hand string
@ -118,8 +155,10 @@ class OGRGeometry(object):
except:
raise OGRException, 'Could not initialize on WKT "%s"' % input
elif isinstance(input, OGRGeomType):
self._init_srs(srs)
g = lgdal.OGR_G_CreateGeometry(input.num)
elif isinstance(input, int):
lgdal.OGR_G_AssignSpatialReference(g, self._s._srs)
elif isinstance(input, IntType):
# OGR Pointer (integer) was the input
g = input
else:
@ -133,13 +172,24 @@ class OGRGeometry(object):
# Setting the class depending upon the OGR Geometry Type
self.__class__ = GEO_CLASSES[self.geom_type.num]
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
def __add__(self, other):
"Returns the union of the two geometries."
return self.union(other)
def __del__(self):
"Deletes this Geometry."
if self._g: lgdal.OGR_G_DestroyGeometry(self._g)
def __eq__(self, other):
"Is this Geometry equal to the other?"
return lgdal.OGR_G_Equals(self._g, other._g)
return self.equals(other)
def __str__(self):
"WKT is used for the string representation."
@ -163,9 +213,14 @@ class OGRGeometry(object):
@property
def point_count(self):
"The number of Points in this Geometry."
"Returns the number of Points in this Geometry."
return lgdal.OGR_G_GetPointCount(self._g)
@property
def num_coords(self):
"Returns the number of Points in this Geometry."
return self.point_count
@property
def srs(self):
"Returns the Spatial Reference for this Geometry."
@ -188,11 +243,26 @@ class OGRGeometry(object):
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."
a = lgdal.OGR_G_GetArea(self._g)
return a.value
#### Geometry Methods ####
def clone(self):
"Clones this OGR Geometry."
return OGRGeometry(lgdal.OGR_G_Clone(self._g))
def close_rings(self):
"""If there are any rings within this geometry that have not been
closed, this routine will do so by adding the starting point at the
end."""
# Closing the open rings.
lgdal.OGR_G_CloseRings(self._g)
# This "fixes" a GDAL bug. See http://trac.osgeo.org/gdal/ticket/1673
foo = self.wkt
def transform(self, coord_trans):
"Transforms this Geometry with the given CoordTransform object."
if not isinstance(coord_trans, CoordTransform):
@ -205,6 +275,78 @@ class OGRGeometry(object):
raise OGRException, 'SpatialReference object required for transform_to.'
check_err(lgdal.OGR_G_TransformTo(self._g, srs._srs))
#### Topology Methods ####
def _topology(self, topo_func, other):
"""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!'
# Calling the passed-in topology function with the other geometry
status = topo_func(self._g, other._g)
# Returning based on the status code (an integer)
if status: return True
else: return False
def intersects(self, other):
"Returns True if this geometry intersects with the other."
return self._topology(lgdal.OGR_G_Intersects, other)
def equals(self, other):
"Returns True if this geometry is equivalent to the other."
return self._topology(lgdal.OGR_G_Equals, other)
def disjoint(self, other):
"Returns True if this geometry and the other are spatially disjoint."
return self._topology(lgdal.OGR_G_Disjoint, other)
def touches(self, other):
"Returns True if this geometry touches the other."
return self._topology(lgdal.OGR_G_Touches, other)
def crosses(self, other):
"Returns True if this geometry crosses the other."
return self._topology(lgdal.OGR_G_Crosses, other)
def within(self, other):
"Returns True if this geometry is within the other."
return self._topology(lgdal.OGR_G_Within, other)
def contains(self, other):
"Returns True if this geometry contains the other."
return self._topology(lgdal.OGR_G_Contains, other)
def overlaps(self, other):
"Returns True if this geometry overlaps the other."
return self._topology(lgdal.OGR_G_Overlaps, other)
#### Geometry-generation Methods ####
def _geomgen(self, gen_func, other):
if not isinstance(other, OGRGeometry):
raise OGRException, 'Must use another OGRGeometry object for geometry-generating operations!'
return OGRGeometry(gen_func(self._g, other._g))
def union(self, other):
"""Returns a new geometry consisting of the region which is the union of
this geometry and the other."""
return self._geomgen(lgdal.OGR_G_Union, other)
def difference(self, other):
"""Returns a new geometry consisting of the region which is the difference
of this geometry and the other."""
return self._geomgen(lgdal.OGR_G_Difference, other)
def sym_difference(self, other):
"""Returns a new geometry which is the symmetric difference of this
geometry and the other."""
return self._geomgen(lgdal.OGR_G_SymmetricDifference, other)
def intersection(self, other):
"""Returns a new geometry consisting of the region of intersection of this
geometry and the other."""
return self._geomgen(lgdal.OGR_G_Intersection, other)
# The subclasses for OGR Geometry.
class Point(OGRGeometry):
@ -298,6 +440,20 @@ class Polygon(OGRGeometry):
"Returns a tuple of LinearRing coordinate tuples."
return tuple(self.__getitem__(i).tuple for i in xrange(self.geom_count))
@property
def point_count(self):
"The number of Points in this Polygon."
# Summing up the number of points in each ring of the Polygon.
return sum([self.__getitem__(i).point_count for i in xrange(self.geom_count)])
@property
def centroid(self):
"Returns the centroid (a Point) of this Polygon."
# The centroid is a Point, create a geometry for this.
p = OGRGeometry(OGRGeomType('Point'))
check_err(lgdal.OGR_G_Centroid(self._g, p._g))
return p
# Geometry Collection base class.
class GeometryCollection(OGRGeometry):
"The Geometry Collection class."
@ -320,9 +476,25 @@ class GeometryCollection(OGRGeometry):
def add(self, geom):
"Add the geometry to this Geometry Collection."
if not isinstance(geom, OGRGeometry):
if isinstance(geom, OGRGeometry):
ptr = geom._g
elif isinstance(geom, StringType):
tmp = OGRGeometry(geom)
ptr = tmp._g
else:
raise OGRException, 'Must add an OGRGeometry.'
lgdal.OGR_G_AddGeometry(self._g, geom._g)
lgdal.OGR_G_AddGeometry(self._g, ptr)
@property
def point_count(self):
"The number of Points in this Geometry Collection."
# Summing up the number of points in each geometry in this collection
return sum([self.__getitem__(i).point_count for i in xrange(self.geom_count)])
@property
def tuple(self):
"Returns a tuple representation of this Geometry Collection."
return tuple(self.__getitem__(i).tuple for i in xrange(self.geom_count))
# Multiple Geometry types.
class MultiPoint(GeometryCollection): pass

View File

@ -11,6 +11,36 @@ from django.contrib.gis.gdal.libgdal import lgdal
# Getting the error checking routine and exceptions
from django.contrib.gis.gdal.OGRError import check_err, OGRException, SRSException
"""
The Spatial Reference class, represensents OGR Spatial Reference objects.
Example:
>>> from django.contrib.gis.gdal import SpatialReference
>>> srs = SpatialReference('WGS84')
>>> print srs
GEOGCS["WGS 84",
DATUM["WGS_1984",
SPHEROID["WGS 84",6378137,298.257223563,
AUTHORITY["EPSG","7030"]],
TOWGS84[0,0,0,0,0,0,0],
AUTHORITY["EPSG","6326"]],
PRIMEM["Greenwich",0,
AUTHORITY["EPSG","8901"]],
UNIT["degree",0.01745329251994328,
AUTHORITY["EPSG","9122"]],
AUTHORITY["EPSG","4326"]]
>>> print srs.proj
+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs
>>> print srs.ellipsoid
(6378137.0, 6356752.3142451793, 298.25722356300003)
>>> print srs.projected, srs.geographic
False True
>>> srs.import_epsg(32140)
>>> print srs.name
NAD83 / Texas South Central
"""
#### ctypes function prototypes ####
def ellipsis_func(f):
"""Creates a ctypes function prototype for OSR ellipsis property functions,
@ -183,7 +213,13 @@ class SpatialReference(object):
self._cache_angular()
return self._angular_units
#### Spheroid/Ellipsis Properties ####
#### Spheroid/Ellipsoid Properties ####
@property
def ellipsoid(self):
"""Returns a tuple of the ellipsoid parameters:
(semimajor axis, semiminor axis, and inverse flattening)."""
return (self.semi_major, self.semi_minor, self.inverse_flattening)
@property
def semi_major(self):
"Gets the Semi Major Axis for this Spatial Reference."
@ -267,6 +303,10 @@ class SpatialReference(object):
check_err(lgdal.OSRExportToProj4(self._srs, byref(w)))
return string_at(w)
def proj4(self):
"Alias for proj()."
return self.proj
@property
def xml(self, dialect=''):
"Returns the XML representation of this Spatial Reference."

View File

@ -1,3 +1,4 @@
from Driver import Driver
from DataSource import DataSource
from SpatialReference import SpatialReference, CoordTransform
from OGRGeometry import OGRGeometry, OGRGeomType

View File

@ -1,8 +1,9 @@
import os, sys
from ctypes import CDLL
from django.contrib.gis.gdal.OGRError import OGRException
if os.name == 'nt':
# Windows NT library
# Windows NT shared library
lib_name = 'libgdal-1.dll'
elif os.name == 'posix':
platform = os.uname()[0]
@ -10,13 +11,13 @@ elif os.name == 'posix':
# Linux shared library
lib_name = 'libgdal.so'
elif platform == 'Darwin':
# Mac OSX Shared Library
# Mac OSX shared library
lib_name = 'libgdal.dylib'
else:
raise GDALException, 'Unknown POSIX platform "%s"' % platform
raise OGRException, 'Unknown POSIX platform "%s"' % platform
else:
raise GDALException, 'Unsupported OS "%s"' % os.name
raise OGRException, 'Unsupported OS "%s"' % os.name
# The GDAL C library
# This loads the GDAL/OGR C library
lgdal = CDLL(lib_name)

View File

@ -1,14 +1,15 @@
from unittest import TestSuite, makeSuite, TextTestRunner
import test_geos, test_gdal_ds, test_gdal_srs, test_gdal_geom, test_spatialrefsys
import test_geos, test_gdal_ds, test_gdal_driver, test_gdal_srs, test_gdal_geom, test_spatialrefsys
def suite():
s = TestSuite()
s.addTest(test_geos.suite())
s.addTest(test_gdal_ds.suite())
s.addTest(test_gdal_driver.suite())
s.addTest(test_gdal_srs.suite())
s.addTest(test_gdal_geom.suite())
s.addTest(test_spatialrefsys.suite())
return s
def run(verbosity=2):
def run(verbosity=1):
TextTestRunner(verbosity=verbosity).run(suite())

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,40 @@
import os, os.path, unittest
from django.contrib.gis.gdal import Driver, OGRException
valid_drivers = ('ESRI Shapefile', 'MapInfo File', 'TIGER', 'S57', 'DGN',
'Memory', 'CSV', 'GML', 'KML')
invalid_drivers = ('Foo baz', 'clucka', 'ESRI Shp')
aliases = {'eSrI' : 'ESRI Shapefile',
'TigER/linE' : 'TIGER',
'SHAPE' : 'ESRI Shapefile',
'sHp' : 'ESRI Shapefile',
}
class DriverTest(unittest.TestCase):
def test01_valid_driver(self):
"Testing valid OGR Data Source Drivers."
for d in valid_drivers:
dr = Driver(d)
self.assertEqual(d, str(dr))
def test02_invalid_driver(self):
"Testing invalid OGR Data Source Drivers."
for i in invalid_drivers:
self.assertRaises(OGRException, Driver, i)
def test03_aliases(self):
"Testing driver aliases."
for alias, full_name in aliases.items():
dr = Driver(alias)
self.assertEqual(full_name, str(dr))
def suite():
s = unittest.TestSuite()
s.addTest(unittest.makeSuite(DriverTest))
return s
def run(verbosity=2):
unittest.TextTestRunner(verbosity=verbosity).run(suite())

View File

@ -40,7 +40,7 @@ class DataSourceTest(unittest.TestCase):
self.assertEqual(source.ds, ds.name)
# Making sure the driver name matches up
self.assertEqual('ESRI Shapefile', ds.driver)
self.assertEqual('ESRI Shapefile', str(ds.driver))
# Making sure indexing works
try:

View File

@ -10,11 +10,11 @@ class OGRGeomTest(unittest.TestCase):
# OGRGeomType should initialize on all these inputs.
try:
g = OGRGeomType(0)
g = OGRGeomType(1)
g = OGRGeomType(7)
g = OGRGeomType('point')
g = OGRGeomType('GeometrycollectioN')
g = OGRGeomType('LINearrING')
except:
self.fail('Could not create an OGRGeomType object!')
@ -42,15 +42,54 @@ class OGRGeomTest(unittest.TestCase):
for p in points:
if not hasattr(p, 'z'): # No 3D
pnt = OGRGeometry(p.wkt)
self.assertEqual(pnt.geom_type, 1)
self.assertEqual(1, pnt.geom_type)
self.assertEqual('POINT', pnt.geom_name)
self.assertEqual(p.x, pnt.x)
self.assertEqual(p.y, pnt.y)
self.assertEqual((p.x, p.y), pnt.tuple)
def test03_polygons(self):
def test03_multipoints(self):
"Testing MultiPoint objects."
for mp in multipoints:
mgeom1 = OGRGeometry(mp.wkt) # First one from WKT
self.assertEqual(4, mgeom1.geom_type)
self.assertEqual('MULTIPOINT', mgeom1.geom_name)
mgeom2 = OGRGeometry('MULTIPOINT') # Creating empty multipoint
mgeom3 = OGRGeometry('MULTIPOINT')
for g in mgeom1:
mgeom2.add(g) # adding each point from the multipoints
mgeom3.add(g.wkt) # should take WKT as well
self.assertEqual(mgeom1, mgeom2) # they should equal
self.assertEqual(mgeom1, mgeom3)
self.assertEqual(mp.points, mgeom2.tuple)
self.assertEqual(mp.n_p, mgeom2.point_count)
def test04_linestring(self):
"Testing LineString objects."
for ls in linestrings:
linestr = OGRGeometry(ls.wkt)
self.assertEqual(2, linestr.geom_type)
self.assertEqual('LINESTRING', linestr.geom_name)
self.assertEqual(ls.n_p, linestr.point_count)
self.assertEqual(ls.tup, linestr.tuple)
def test05_multilinestring(self):
"Testing MultiLineString objects."
for mls in multilinestrings:
mlinestr = OGRGeometry(mls.wkt)
self.assertEqual(5, mlinestr.geom_type)
self.assertEqual('MULTILINESTRING', mlinestr.geom_name)
self.assertEqual(mls.n_p, mlinestr.point_count)
self.assertEqual(mls.tup, mlinestr.tuple)
def test06_polygons(self):
"Testing Polygon objects."
for p in polygons:
poly = OGRGeometry(p.wkt)
self.assertEqual(3, poly.geom_type)
self.assertEqual('POLYGON', poly.geom_name)
self.assertEqual(p.n_p, poly.point_count)
first = True
for r in poly:
if first and p.ext_ring_cs:
@ -60,15 +99,34 @@ class OGRGeomTest(unittest.TestCase):
self.assertEqual(len(p.ext_ring_cs), r.point_count)
self.assertEqual(p.ext_ring_cs, r.tuple)
def test04_multipoints(self):
"Testing MultiPoint objects."
def test07_closepolygons(self):
"Testing closing Polygon objects."
for mp in multipoints:
mgeom1 = OGRGeometry(mp.wkt) # First one from WKT
mgeom2 = OGRGeometry('MULTIPOINT') # Creating empty multipoint
for g in mgeom1:
mgeom2.add(g) # adding each point from the multipoint
self.assertEqual(mgeom1, mgeom2) # they should equal
# Both rings in this geometry are not closed.
poly = OGRGeometry('POLYGON((0 0, 5 0, 5 5, 0 5), (1 1, 2 1, 2 2, 2 1))')
self.assertEqual(8, poly.point_count)
try:
c = poly.centroid
except OGRException:
# Should raise an OGR exception, rings are not closed
pass
else:
self.fail('Should have raised an OGRException!')
# Closing the rings
poly.close_rings()
self.assertEqual(10, poly.point_count) # Two closing points should've been added
self.assertEqual(OGRGeometry('POINT(2.5 2.5)'), poly.centroid)
def test08_multipolygons(self):
"Testing MultiPolygon objects."
for mp in multipolygons:
mpoly = OGRGeometry(mp.wkt)
self.assertEqual(6, mpoly.geom_type)
self.assertEqual('MULTIPOLYGON', mpoly.geom_name)
if mp.valid:
self.assertEqual(mp.n_p, mpoly.point_count)
self.assertEqual(mp.num_geom, len(mpoly))
def suite():
s = unittest.TestSuite()

View File

@ -115,8 +115,9 @@ class GeosTest2(unittest.TestCase):
self.assertEqual(mp.valid, mpoly.valid)
if mp.valid:
self.assertEqual(mp.n_p, mpoly.num_geom)
self.assertEqual(mp.n_p, len(mpoly))
self.assertEqual(mp.num_geom, mpoly.num_geom)
self.assertEqual(mp.n_p, mpoly.num_coords)
self.assertEqual(mp.num_geom, len(mpoly))
for p in mpoly:
self.assertEqual(p.geom_type, 'Polygon')
self.assertEqual(p.geom_typeid, 3)