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:
parent
b0b7bbced7
commit
48c9f87e1f
@ -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.libgdal import lgdal
|
||||||
from django.contrib.gis.gdal.OGRError import OGRException, check_err
|
from django.contrib.gis.gdal.OGRError import OGRException, check_err
|
||||||
from django.contrib.gis.gdal.Layer import Layer
|
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
|
DataSource is a wrapper for the OGR Data Source object, which provides
|
||||||
an interface for reading vector geometry data from many different file
|
an interface for reading vector geometry data from many different file
|
||||||
formats (including ESRI shapefiles).
|
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:
|
Example:
|
||||||
ds = DataSource('/home/foo/bar.shp')
|
ds = DataSource('/home/foo/bar.shp')
|
||||||
for layer in ds:
|
for layer in ds:
|
||||||
@ -22,13 +30,24 @@ from django.contrib.gis.gdal.Layer import Layer
|
|||||||
# Getting the 'description' field for the feature.
|
# Getting the 'description' field for the feature.
|
||||||
desc = feature['description']
|
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:
|
# For more information, see the OGR C API source code:
|
||||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
# 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):
|
class DataSource(object):
|
||||||
"Wraps an OGR Data Source object."
|
"Wraps an OGR Data Source object."
|
||||||
@ -36,26 +55,32 @@ class DataSource(object):
|
|||||||
_ds = 0 # Initially NULL
|
_ds = 0 # Initially NULL
|
||||||
|
|
||||||
#### Python 'magic' routines ####
|
#### 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
|
# Registering all the drivers, this needs to be done
|
||||||
# _before_ we try to open up a data source.
|
# _before_ we try to open up a data source.
|
||||||
if not lgdal.OGRRegisterAll():
|
if not lgdal.OGRGetDriverCount() and not lgdal.OGRRegisterAll():
|
||||||
raise OGRException, 'Could not register all data source drivers!'
|
raise OGRException, 'Could not register all the OGR data source drivers!'
|
||||||
|
|
||||||
# The data source driver is a void pointer.
|
if isinstance(ds_input, StringType):
|
||||||
ds_driver = c_void_p()
|
|
||||||
|
|
||||||
# OGROpen will auto-detect the data source type.
|
# The data source driver is a void pointer.
|
||||||
ds = lgdal.OGROpen(c_char_p(ds_file), c_int(0), byref(ds_driver))
|
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
|
# Raise an exception if the returned pointer is NULL
|
||||||
if not ds:
|
if not ds:
|
||||||
self._ds = False
|
self._ds = False
|
||||||
raise OGRException, 'Invalid data source file "%s"' % ds_file
|
raise OGRException, 'Invalid data source file "%s"' % ds_input
|
||||||
else:
|
else:
|
||||||
self._ds = ds
|
self._ds = ds
|
||||||
self._driver = ds_driver
|
self._driver = Driver(ds_driver)
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
"This releases the reference to the data source (destroying it if it's the only one)."
|
"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):
|
def __str__(self):
|
||||||
"Returns OGR GetName and Driver for the Data Source."
|
"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 ####
|
#### DataSource Properties ####
|
||||||
@property
|
@property
|
||||||
def driver(self):
|
def driver(self):
|
||||||
"Returns the name of the data source driver."
|
"Returns the Driver object for this Data Source."
|
||||||
return string_at(lgdal.OGR_Dr_GetName(self._driver))
|
return self._driver
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def layer_count(self):
|
def layer_count(self):
|
||||||
|
86
django/contrib/gis/gdal/Driver.py
Normal file
86
django/contrib/gis/gdal/Driver.py
Normal 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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
# types and ctypes
|
# types and ctypes
|
||||||
import types
|
from types import StringType
|
||||||
from ctypes import c_char_p, c_int, string_at
|
from ctypes import c_char_p, c_int, string_at
|
||||||
|
|
||||||
# The GDAL C library, OGR exception, and the Field object
|
# The GDAL C library, OGR exception, and the Field object
|
||||||
@ -31,7 +31,7 @@ class Feature(object):
|
|||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
"Gets the Field at the specified index."
|
"Gets the Field at the specified index."
|
||||||
if isinstance(index, types.StringType):
|
if isinstance(index, StringType):
|
||||||
i = self.index(index)
|
i = self.index(index)
|
||||||
else:
|
else:
|
||||||
if index < 0 or index > self.num_fields:
|
if index < 0 or index > self.num_fields:
|
||||||
|
@ -8,7 +8,7 @@ from django.contrib.gis.gdal.OGRError import OGRException
|
|||||||
#
|
#
|
||||||
# The OGR_Fld_* routines are relevant here.
|
# The OGR_Fld_* routines are relevant here.
|
||||||
class Field(object):
|
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
|
_fld = 0 # Initially NULL
|
||||||
|
|
||||||
|
@ -1,14 +1,53 @@
|
|||||||
# types & ctypes
|
# types & ctypes
|
||||||
from types import StringType
|
from types import IntType, StringType
|
||||||
from ctypes import \
|
from ctypes import byref, string_at, c_char_p, c_double, c_int, c_void_p
|
||||||
byref, string_at, create_string_buffer, POINTER, \
|
|
||||||
c_char_p, c_double, c_int, c_void_p
|
|
||||||
|
|
||||||
# Getting the GDAL C library and error checking facilities
|
# Getting the GDAL C library and error checking facilities
|
||||||
from django.contrib.gis.gdal.libgdal import lgdal
|
from django.contrib.gis.gdal.libgdal import lgdal
|
||||||
from django.contrib.gis.gdal.OGRError import check_err, OGRException
|
from django.contrib.gis.gdal.OGRError import check_err, OGRException
|
||||||
from django.contrib.gis.gdal.SpatialReference import SpatialReference, CoordTransform
|
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:
|
# For more information, see the OGR C API source code:
|
||||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
# http://www.gdal.org/ogr/ogr__api_8h.html
|
||||||
#
|
#
|
||||||
@ -29,10 +68,10 @@ class OGRGeomType(object):
|
|||||||
"Encapulates OGR Geometry Types."
|
"Encapulates OGR Geometry Types."
|
||||||
|
|
||||||
# Ordered array of acceptable strings and their corresponding OGRwkbGeometryType
|
# 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',
|
'MultiLineString', 'MultiPolygon', 'GeometryCollection',
|
||||||
'None', 'LinearRing']
|
'LinearRing']
|
||||||
__ogr_int = [0, 1, 2, 3, 4, 5, 6, 7, 100, 101]
|
__ogr_int = [1, 2, 3, 4, 5, 6, 7, 101]
|
||||||
|
|
||||||
def __init__(self, input):
|
def __init__(self, input):
|
||||||
"Figures out the correct OGR Type based upon the input."
|
"Figures out the correct OGR Type based upon the input."
|
||||||
@ -40,7 +79,7 @@ class OGRGeomType(object):
|
|||||||
self._index = input._index
|
self._index = input._index
|
||||||
elif isinstance(input, StringType):
|
elif isinstance(input, StringType):
|
||||||
idx = self._has_str(self.__ogr_str, input)
|
idx = self._has_str(self.__ogr_str, input)
|
||||||
if not idx:
|
if idx == None:
|
||||||
raise OGRException, 'Invalid OGR String Type "%s"' % input
|
raise OGRException, 'Invalid OGR String Type "%s"' % input
|
||||||
self._index = idx
|
self._index = idx
|
||||||
elif isinstance(input, int):
|
elif isinstance(input, int):
|
||||||
@ -61,7 +100,7 @@ class OGRGeomType(object):
|
|||||||
return self._index == other._index
|
return self._index == other._index
|
||||||
elif isinstance(other, StringType):
|
elif isinstance(other, StringType):
|
||||||
idx = self._has_str(self.__ogr_str, other)
|
idx = self._has_str(self.__ogr_str, other)
|
||||||
if idx: return self._index == idx
|
if not (idx == None): return self._index == idx
|
||||||
return False
|
return False
|
||||||
elif isinstance(other, int):
|
elif isinstance(other, int):
|
||||||
if not other in self.__ogr_int: return False
|
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))
|
raise TypeError, 'Cannot compare with type: %s' % str(type(other))
|
||||||
|
|
||||||
def _has_str(self, arr, s):
|
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)):
|
for i in xrange(len(arr)):
|
||||||
if slow == arr[i].lower(): return i
|
if s_low == arr[i].lower(): return i
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -99,18 +139,15 @@ class OGRGeometry(object):
|
|||||||
"Initializes Geometry on either WKT or an OGR pointer as input."
|
"Initializes Geometry on either WKT or an OGR pointer as input."
|
||||||
|
|
||||||
if isinstance(input, StringType):
|
if isinstance(input, StringType):
|
||||||
|
# Getting the spatial reference
|
||||||
|
self._init_srs(srs)
|
||||||
|
|
||||||
# First, trying the input as WKT
|
# First, trying the input as WKT
|
||||||
buf = c_char_p(input)
|
buf = c_char_p(input)
|
||||||
g = c_void_p()
|
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:
|
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:
|
except OGRException, msg:
|
||||||
try:
|
try:
|
||||||
ogr_t = OGRGeomType(input) # Seeing if the input is a valid short-hand string
|
ogr_t = OGRGeomType(input) # Seeing if the input is a valid short-hand string
|
||||||
@ -118,8 +155,10 @@ class OGRGeometry(object):
|
|||||||
except:
|
except:
|
||||||
raise OGRException, 'Could not initialize on WKT "%s"' % input
|
raise OGRException, 'Could not initialize on WKT "%s"' % input
|
||||||
elif isinstance(input, OGRGeomType):
|
elif isinstance(input, OGRGeomType):
|
||||||
|
self._init_srs(srs)
|
||||||
g = lgdal.OGR_G_CreateGeometry(input.num)
|
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
|
# OGR Pointer (integer) was the input
|
||||||
g = input
|
g = input
|
||||||
else:
|
else:
|
||||||
@ -133,13 +172,24 @@ class OGRGeometry(object):
|
|||||||
# Setting the class depending upon the OGR Geometry Type
|
# Setting the class depending upon the OGR Geometry Type
|
||||||
self.__class__ = GEO_CLASSES[self.geom_type.num]
|
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):
|
def __del__(self):
|
||||||
"Deletes this Geometry."
|
"Deletes this Geometry."
|
||||||
if self._g: lgdal.OGR_G_DestroyGeometry(self._g)
|
if self._g: lgdal.OGR_G_DestroyGeometry(self._g)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
"Is this Geometry equal to the other?"
|
"Is this Geometry equal to the other?"
|
||||||
return lgdal.OGR_G_Equals(self._g, other._g)
|
return self.equals(other)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"WKT is used for the string representation."
|
"WKT is used for the string representation."
|
||||||
@ -163,9 +213,14 @@ class OGRGeometry(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def point_count(self):
|
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)
|
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
|
@property
|
||||||
def srs(self):
|
def srs(self):
|
||||||
"Returns the Spatial Reference for this Geometry."
|
"Returns the Spatial Reference for this Geometry."
|
||||||
@ -188,11 +243,26 @@ class OGRGeometry(object):
|
|||||||
check_err(lgdal.OGR_G_ExportToWkt(self._g, byref(buf)))
|
check_err(lgdal.OGR_G_ExportToWkt(self._g, byref(buf)))
|
||||||
return string_at(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 ####
|
#### Geometry Methods ####
|
||||||
def clone(self):
|
def clone(self):
|
||||||
"Clones this OGR Geometry."
|
"Clones this OGR Geometry."
|
||||||
return OGRGeometry(lgdal.OGR_G_Clone(self._g))
|
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):
|
def transform(self, coord_trans):
|
||||||
"Transforms this Geometry with the given CoordTransform object."
|
"Transforms this Geometry with the given CoordTransform object."
|
||||||
if not isinstance(coord_trans, CoordTransform):
|
if not isinstance(coord_trans, CoordTransform):
|
||||||
@ -205,6 +275,78 @@ class OGRGeometry(object):
|
|||||||
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))
|
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.
|
# The subclasses for OGR Geometry.
|
||||||
class Point(OGRGeometry):
|
class Point(OGRGeometry):
|
||||||
|
|
||||||
@ -298,6 +440,20 @@ class Polygon(OGRGeometry):
|
|||||||
"Returns a tuple of LinearRing coordinate tuples."
|
"Returns a tuple of LinearRing coordinate tuples."
|
||||||
return tuple(self.__getitem__(i).tuple for i in xrange(self.geom_count))
|
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.
|
# Geometry Collection base class.
|
||||||
class GeometryCollection(OGRGeometry):
|
class GeometryCollection(OGRGeometry):
|
||||||
"The Geometry Collection class."
|
"The Geometry Collection class."
|
||||||
@ -320,9 +476,25 @@ class GeometryCollection(OGRGeometry):
|
|||||||
|
|
||||||
def add(self, geom):
|
def add(self, geom):
|
||||||
"Add the geometry to this Geometry Collection."
|
"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.'
|
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.
|
# Multiple Geometry types.
|
||||||
class MultiPoint(GeometryCollection): pass
|
class MultiPoint(GeometryCollection): pass
|
||||||
|
@ -11,6 +11,36 @@ from django.contrib.gis.gdal.libgdal import lgdal
|
|||||||
# Getting the error checking routine and exceptions
|
# Getting the error checking routine and exceptions
|
||||||
from django.contrib.gis.gdal.OGRError import check_err, OGRException, SRSException
|
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 ####
|
#### ctypes function prototypes ####
|
||||||
def ellipsis_func(f):
|
def ellipsis_func(f):
|
||||||
"""Creates a ctypes function prototype for OSR ellipsis property functions,
|
"""Creates a ctypes function prototype for OSR ellipsis property functions,
|
||||||
@ -183,7 +213,13 @@ class SpatialReference(object):
|
|||||||
self._cache_angular()
|
self._cache_angular()
|
||||||
return self._angular_units
|
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
|
@property
|
||||||
def semi_major(self):
|
def semi_major(self):
|
||||||
"Gets the Semi Major Axis for this Spatial Reference."
|
"Gets the Semi Major Axis for this Spatial Reference."
|
||||||
@ -267,6 +303,10 @@ class SpatialReference(object):
|
|||||||
check_err(lgdal.OSRExportToProj4(self._srs, byref(w)))
|
check_err(lgdal.OSRExportToProj4(self._srs, byref(w)))
|
||||||
return string_at(w)
|
return string_at(w)
|
||||||
|
|
||||||
|
def proj4(self):
|
||||||
|
"Alias for proj()."
|
||||||
|
return self.proj
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def xml(self, dialect=''):
|
def xml(self, dialect=''):
|
||||||
"Returns the XML representation of this Spatial Reference."
|
"Returns the XML representation of this Spatial Reference."
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
from Driver import Driver
|
||||||
from DataSource import DataSource
|
from DataSource import DataSource
|
||||||
from SpatialReference import SpatialReference, CoordTransform
|
from SpatialReference import SpatialReference, CoordTransform
|
||||||
from OGRGeometry import OGRGeometry, OGRGeomType
|
from OGRGeometry import OGRGeometry, OGRGeomType
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import os, sys
|
import os, sys
|
||||||
from ctypes import CDLL
|
from ctypes import CDLL
|
||||||
|
from django.contrib.gis.gdal.OGRError import OGRException
|
||||||
|
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
# Windows NT library
|
# Windows NT shared library
|
||||||
lib_name = 'libgdal-1.dll'
|
lib_name = 'libgdal-1.dll'
|
||||||
elif os.name == 'posix':
|
elif os.name == 'posix':
|
||||||
platform = os.uname()[0]
|
platform = os.uname()[0]
|
||||||
@ -10,13 +11,13 @@ elif os.name == 'posix':
|
|||||||
# Linux shared library
|
# Linux shared library
|
||||||
lib_name = 'libgdal.so'
|
lib_name = 'libgdal.so'
|
||||||
elif platform == 'Darwin':
|
elif platform == 'Darwin':
|
||||||
# Mac OSX Shared Library
|
# Mac OSX shared library
|
||||||
lib_name = 'libgdal.dylib'
|
lib_name = 'libgdal.dylib'
|
||||||
else:
|
else:
|
||||||
raise GDALException, 'Unknown POSIX platform "%s"' % platform
|
raise OGRException, 'Unknown POSIX platform "%s"' % platform
|
||||||
else:
|
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)
|
lgdal = CDLL(lib_name)
|
||||||
|
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
from unittest import TestSuite, makeSuite, TextTestRunner
|
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():
|
def suite():
|
||||||
s = TestSuite()
|
s = TestSuite()
|
||||||
s.addTest(test_geos.suite())
|
s.addTest(test_geos.suite())
|
||||||
s.addTest(test_gdal_ds.suite())
|
s.addTest(test_gdal_ds.suite())
|
||||||
|
s.addTest(test_gdal_driver.suite())
|
||||||
s.addTest(test_gdal_srs.suite())
|
s.addTest(test_gdal_srs.suite())
|
||||||
s.addTest(test_gdal_geom.suite())
|
s.addTest(test_gdal_geom.suite())
|
||||||
s.addTest(test_spatialrefsys.suite())
|
s.addTest(test_spatialrefsys.suite())
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def run(verbosity=2):
|
def run(verbosity=1):
|
||||||
TextTestRunner(verbosity=verbosity).run(suite())
|
TextTestRunner(verbosity=verbosity).run(suite())
|
||||||
|
File diff suppressed because one or more lines are too long
40
django/contrib/gis/tests/test_gdal_driver.py
Normal file
40
django/contrib/gis/tests/test_gdal_driver.py
Normal 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())
|
@ -40,7 +40,7 @@ class DataSourceTest(unittest.TestCase):
|
|||||||
self.assertEqual(source.ds, ds.name)
|
self.assertEqual(source.ds, ds.name)
|
||||||
|
|
||||||
# Making sure the driver name matches up
|
# Making sure the driver name matches up
|
||||||
self.assertEqual('ESRI Shapefile', ds.driver)
|
self.assertEqual('ESRI Shapefile', str(ds.driver))
|
||||||
|
|
||||||
# Making sure indexing works
|
# Making sure indexing works
|
||||||
try:
|
try:
|
||||||
|
@ -10,11 +10,11 @@ class OGRGeomTest(unittest.TestCase):
|
|||||||
|
|
||||||
# OGRGeomType should initialize on all these inputs.
|
# OGRGeomType should initialize on all these inputs.
|
||||||
try:
|
try:
|
||||||
g = OGRGeomType(0)
|
|
||||||
g = OGRGeomType(1)
|
g = OGRGeomType(1)
|
||||||
g = OGRGeomType(7)
|
g = OGRGeomType(7)
|
||||||
g = OGRGeomType('point')
|
g = OGRGeomType('point')
|
||||||
g = OGRGeomType('GeometrycollectioN')
|
g = OGRGeomType('GeometrycollectioN')
|
||||||
|
g = OGRGeomType('LINearrING')
|
||||||
except:
|
except:
|
||||||
self.fail('Could not create an OGRGeomType object!')
|
self.fail('Could not create an OGRGeomType object!')
|
||||||
|
|
||||||
@ -42,15 +42,54 @@ class OGRGeomTest(unittest.TestCase):
|
|||||||
for p in points:
|
for p in points:
|
||||||
if not hasattr(p, 'z'): # No 3D
|
if not hasattr(p, 'z'): # No 3D
|
||||||
pnt = OGRGeometry(p.wkt)
|
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.x, pnt.x)
|
||||||
self.assertEqual(p.y, pnt.y)
|
self.assertEqual(p.y, pnt.y)
|
||||||
self.assertEqual((p.x, p.y), pnt.tuple)
|
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."
|
"Testing Polygon objects."
|
||||||
for p in polygons:
|
for p in polygons:
|
||||||
poly = OGRGeometry(p.wkt)
|
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
|
first = True
|
||||||
for r in poly:
|
for r in poly:
|
||||||
if first and p.ext_ring_cs:
|
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(len(p.ext_ring_cs), r.point_count)
|
||||||
self.assertEqual(p.ext_ring_cs, r.tuple)
|
self.assertEqual(p.ext_ring_cs, r.tuple)
|
||||||
|
|
||||||
def test04_multipoints(self):
|
def test07_closepolygons(self):
|
||||||
"Testing MultiPoint objects."
|
"Testing closing Polygon objects."
|
||||||
|
|
||||||
for mp in multipoints:
|
# Both rings in this geometry are not closed.
|
||||||
mgeom1 = OGRGeometry(mp.wkt) # First one from WKT
|
poly = OGRGeometry('POLYGON((0 0, 5 0, 5 5, 0 5), (1 1, 2 1, 2 2, 2 1))')
|
||||||
mgeom2 = OGRGeometry('MULTIPOINT') # Creating empty multipoint
|
self.assertEqual(8, poly.point_count)
|
||||||
for g in mgeom1:
|
try:
|
||||||
mgeom2.add(g) # adding each point from the multipoint
|
c = poly.centroid
|
||||||
self.assertEqual(mgeom1, mgeom2) # they should equal
|
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():
|
def suite():
|
||||||
s = unittest.TestSuite()
|
s = unittest.TestSuite()
|
||||||
|
@ -115,8 +115,9 @@ class GeosTest2(unittest.TestCase):
|
|||||||
self.assertEqual(mp.valid, mpoly.valid)
|
self.assertEqual(mp.valid, mpoly.valid)
|
||||||
|
|
||||||
if mp.valid:
|
if mp.valid:
|
||||||
self.assertEqual(mp.n_p, mpoly.num_geom)
|
self.assertEqual(mp.num_geom, mpoly.num_geom)
|
||||||
self.assertEqual(mp.n_p, len(mpoly))
|
self.assertEqual(mp.n_p, mpoly.num_coords)
|
||||||
|
self.assertEqual(mp.num_geom, len(mpoly))
|
||||||
for p in mpoly:
|
for p in mpoly:
|
||||||
self.assertEqual(p.geom_type, 'Polygon')
|
self.assertEqual(p.geom_type, 'Polygon')
|
||||||
self.assertEqual(p.geom_typeid, 3)
|
self.assertEqual(p.geom_typeid, 3)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user