/* SWIG (www.swig.org) interface file for shapelib
*
* At the moment (Dec 2000) this file is only useful to generate Python
* bindings. Invoke swig as follows:
*
* swig -python -shadow shapelib.i
*
* to generate shapelib_wrap.c and shapelib.py. shapelib_wrap.c
* defines a bunch of Python-functions that wrap the appripriate
* shapelib functions and shapelib.py contains an object oriented
* wrapper around shapelib_wrap.c.
*
* Shapelib, and hence this module too, defines two types of objects,
* shapes and shapefiles.
*/
%module shapelib
/*
* First, a %{,%}-Block. These blocks are copied verbatim to the
* shapelib_wrap.c file and are not parsed by SWIG. This is the place to
* import headerfiles and define helper-functions that are needed by the
* automatically generated wrappers.
*/
%{
/* import the shapelib headefile. */
#include "shapefil.h"
#include "pyshapelib_api.h"
/*
* Rename a few shapelib functions that are effectively methods with
* preprocessor macros so that they have the names that swig expects
* (e.g. the destructor of SHPObject has to be called delete_SHPObject)
*/
#define delete_SHPObject SHPDestroyObject
/*
* The extents() method of SHPObject.
*
* Return the extents as a tuple of two 4-element lists with the min.
* and max. values of x, y, z, m.
*/
static PyObject *
SHPObject_extents(SHPObject *object)
{
return Py_BuildValue("[dddd][dddd]",
object->dfXMin, object->dfYMin, object->dfZMin,
object->dfMMin,
object->dfXMax, object->dfYMax, object->dfZMax,
object->dfMMax);
}
/*
* The vertices() method of SHPObject.
*
* Return the x and y coords of the vertices as a list of lists of
* tuples.
*/
static PyObject* build_vertex_list(SHPObject *object, int index, int length);
static PyObject*
SHPObject_vertices(SHPObject *object)
{
PyObject *result = NULL;
PyObject *part = NULL;
int part_idx, vertex_idx;
int length = 0;
if (object->nParts > 0)
{
/* A multipart shape. Usual for SHPT_ARC and SHPT_POLYGON */
result = PyList_New(object->nParts);
if (!result)
return NULL;
for (part_idx = 0, vertex_idx = 0; part_idx < object->nParts;
part_idx++)
{
if (part_idx < object->nParts - 1)
length = (object->panPartStart[part_idx + 1]
- object->panPartStart[part_idx]);
else
length = object->nVertices - object->panPartStart[part_idx];
part = build_vertex_list(object, vertex_idx, length);
if (!part)
goto fail;
if (PyList_SetItem(result, part_idx, part) < 0)
goto fail;
vertex_idx += length;
}
}
else
{
/* only one part. usual for SHPT_POINT */
result = build_vertex_list(object, 0, object->nVertices);
}
return result;
fail:
Py_XDECREF(part);
Py_DECREF(result);
return NULL;
}
/* Return the length coordinates of the shape object starting at vertex
* index as a Python-list of tuples. Helper function for
* SHPObject_vertices.
*/
static PyObject*
build_vertex_list(SHPObject *object, int index, int length)
{
int i;
PyObject * list;
PyObject * vertex = NULL;
list = PyList_New(length);
if (!list)
return NULL;
for (i = 0; i < length; i++, index++)
{
vertex = Py_BuildValue("dd", object->padfX[index],
object->padfY[index]);
if (!vertex)
goto fail;
if (PyList_SetItem(list, i, vertex) < 0)
goto fail;
}
return list;
fail:
Py_XDECREF(vertex);
Py_DECREF(list);
return NULL;
}
/* The constructor of SHPObject. parts is a list of lists of tuples
* describing the parts and their vertices just likethe output of the
* vertices() method. part_type_list is the list of part-types and may
* be NULL. For the meaning of the part-types and their default value
* see the Shaplib documentation.
*/
SHPObject * new_SHPObject(int type, int id, PyObject * parts,
PyObject * part_type_list)
{
/* arrays to hold thex and y coordinates of the vertices */
double *xs = NULL, *ys = NULL;
/* number of all vertices of all parts */
int num_vertices;
/* number of parts in the list parts */
int num_parts;
/* start index of in xs and ys of the part currently worked on */
int part_start;
/* array of start indices in xs and ys as expected by shapelib */
int *part_starts = NULL;
/* generic counter */
int i;
/* array of part types. holds the converted content of
* part_type_list. Stays NULL of part_type_list is NULL
*/
int *part_types = NULL;
/* temporary python objects referring to the the list items being
* worked on.
*/
PyObject * part = NULL, *tuple = NULL;
/* The result object */
SHPObject *result;
num_parts = PySequence_Length(parts);
num_vertices = 0;
/* parts and part_types have to have the same lengths */
if (part_type_list
&& PySequence_Length(parts) != PySequence_Length(part_type_list))
{
PyErr_SetString(PyExc_TypeError,
"parts and part_types have to have the same lengths");
return NULL;
}
/* determine how many vertices there are altogether */
for (i = 0; i < num_parts; i++)
{
PyObject * part = PySequence_GetItem(parts, i);
if (!part)
return NULL;
num_vertices += PySequence_Length(part);
Py_DECREF(part);
}
/* allocate the memory for the various arrays and check for memory
errors */
xs = malloc(num_vertices * sizeof(double));
ys = malloc(num_vertices * sizeof(double));
part_starts = malloc(num_parts * sizeof(int));
if (part_type_list)
part_types = malloc(num_parts * sizeof(int));
if (!xs || !ys || !part_starts || (part_type_list && !part_types))
{
PyErr_NoMemory();
goto fail;
}
/* convert the part types */
if (part_type_list)
{
for (i = 0; i < num_parts; i++)
{
PyObject * otype = PySequence_GetItem(part_type_list, i);
if (!otype)
return NULL;
part_types[i] = PyInt_AsLong(otype);
Py_DECREF(otype);
}
}
/* convert the list of parts */
part_start = 0;
for (i = 0; i < num_parts; i++)
{
int j, length;
part = PySequence_GetItem(parts, i);
length = PySequence_Length(part);
part_starts[i] = part_start;
for (j = 0; j < length; j++)
{
tuple = PySequence_GetItem(part, j);
if (!tuple)
goto fail;
if (!PyArg_ParseTuple(tuple, "dd", xs + part_start + j,
ys + part_start + j))
{
goto fail;
}
Py_DECREF(tuple);
tuple = NULL;
}
Py_DECREF(part);
part = NULL;
part_start += length;
}
result = SHPCreateObject(type, id, num_parts, part_starts, part_types,
num_vertices, xs, ys, NULL, NULL);
free(xs);
free(ys);
free(part_starts);
free(part_types);
return result;
fail:
free(xs);
free(ys);
free(part_starts);
free(part_types);
Py_XDECREF(part);
Py_XDECREF(tuple);
return NULL;
}
%}
/*
* The SWIG Interface definition.
*/
/* include some common SWIG type definitions and standard exception
handling code */
%include typemaps.i
%include exception.i
/*
* SHPObject -- Represents one shape
*/
/* Exception typemap for the SHPObject constructor. The constructor the
the wrapper function defined above which returns NULL in case of
error. */
%typemap(python,except) SHPObject*new_SHPObject {
$function;
if (PyErr_Occurred())
return NULL;
}
/* Define the SHPObject struct for SWIG. This has to have the same name
* as the underlying C-struct in shapfil.h, but we don't have to repeat
* all the fields here, only those we want to access directly, and we
* can define methods for the object oriented interface.
*/
typedef struct {
/* The shape object has two read-only attributes: */
/* The type of the shape. In the c-struct defined the field is
* called 'nSHPType' but for the python bindings 'type' is more
* appropriate.
*/
%readonly %name(type) int nSHPType;
/* The id of the shape. Here 'id' is a better name than 'nShapeId'. */
%readonly %name(id) int nShapeId;
/* The methods */
%addmethods {
/* the constructor */
SHPObject(int type, int id, PyObject * parts,
PyObject * part_types = NULL);
/* The destructor */
~SHPObject();
/* extents and vertices correspond to the SHPObject_extents and
* SHPObject_vertices defined above
*/
PyObject *extents();
PyObject *vertices();
}
} SHPObject;
/*
* ShapeFile -- Represents the shape file
*/
/* Here we do things a little different. We define a new C-struct that
* holds the SHPHandle. This is mainly done so we can separate the
* close() method from the destructor but it also helps with exception
* handling.
*
* After the ShapeFile has been opened or created the handle is not
* NULL. The close() method closes the file and sets handle to NULL as
* an indicator that the file has been closed.
*/
/* First, define the C-struct */
%{
typedef struct {
SHPHandle handle;
} ShapeFile;
%}
/* define and use some typemaps for the info() method whose
* C-implementation has four output parameters that are returned through
* pointers passed into the function. SWIG already has definitions for
* common types such as int* and we can use those for the first two
* parameters:
*/
%apply int * OUTPUT { int * output_entities }
%apply int * OUTPUT { int * output_type }
/* for the last two, the 4-element arrays of min- and max-values, we
* have to define our own typemaps:
*/
%typemap (python,ignore) double * extents(double temp[4]) {
$target = temp;
}
%typemap (python,argout) double * extents {
PyObject * list = Py_BuildValue("[dddd]",
$source[0], $source[1],
$source[2], $source[3]);
$target = t_output_helper($target,list);
}
%apply double * extents { double * output_min_bounds }
%apply double * extents { double * output_max_bounds }
/* The first argument to the ShapeFile methods is a ShapeFile pointer.
* We have to check whether handle is not NULL in most methods but not
* all. In the destructor and the close method, it's OK for handle to be
* NULL. We achieve this by checking whether the preprocessor macro
* NOCHECK_$name is defined. SWIG replaces $name with the name of the
* function for which the code is inserted. In the %{,%}-block below we
* define the macros for the destructor and the close() method.
*/
%typemap(python,check) ShapeFile *{
%#ifndef NOCHECK_$name
if (!$target || !$target->handle)
SWIG_exception(SWIG_TypeError, "shapefile already closed");
%#endif
}
%{
#define NOCHECK_delete_ShapeFile
#define NOCHECK_ShapeFile_close
%}
/* An exception handle for the constructor and the module level open()
* and create() functions.
*
* Annoyingly, we *have* to put braces around the SWIG_exception()
* calls, at least in the python case, because of the way the macro is
* written. Of course, always putting braces around the branches of an
* if-statement is often considered good practice.
*/
%typemap(python,except) ShapeFile * {
$function;
if (!$source)
{
SWIG_exception(SWIG_MemoryError, "no memory");
}
else if (!$source->handle)
{
SWIG_exception(SWIG_IOError, "$name failed");
}
}
/*
* The SWIG-version of the ShapeFile struct.
*/
typedef struct
{
/* Only methods and no attributes here: */
%addmethods {
/* The constructor. Takes two arguments, the filename and the
* optinal mode which are passed through to SHPOpen (due to the
* renaming trick)
*/
ShapeFile(char *file, char * mode = "rb") {
ShapeFile * self = malloc(sizeof(ShapeFile));
if (self)
self->handle = SHPOpen(file, mode);
return self;
}
/* The destructor. Equivalent to SHPClose */
~ShapeFile() {
if (self->handle)
SHPClose(self->handle);
free(self);
}
/* close the shape file and set handle to NULL */
void close() {
if (self->handle)
{
SHPClose(self->handle);
self->handle = NULL;
}
}
/* info() -- Return a tuple (NUM_SHAPES, TYPE, MIN, MAX) where
* NUM_SHAPES is the number of shapes in the file, TYPE is the
* shape type and MIN and MAX are 4-element lists with the min.
* and max. values of the data.
*
* The arguments of the underlying shapelib function SHPGetInfo
* are all output parameters. To tell SWIG this, we have defined
* some typemaps above
*/
void info(int * output_entities, int * output_type,
double * output_min_bounds, double *output_max_bounds) {
SHPGetInfo(self->handle, output_entities, output_type,
output_min_bounds, output_max_bounds);
}
/* Return object number i */
%new SHPObject * read_object(int i) {
return SHPReadObject(self->handle, i);
}
/* Write an object */
int write_object(int iShape, SHPObject * psObject) {
return SHPWriteObject(self->handle, iShape, psObject);
}
/* Return the shapelib SHPHandle as a Python CObject */
PyObject * cobject() {
return PyCObject_FromVoidPtr(self->handle, NULL);
}
}
} ShapeFile;
/*
* Two module level functions, open() and create() that correspond to
* SHPOpen and SHPCreate respectively. open() is equivalent to the
* ShapeFile constructor.
*/
%{
ShapeFile * open_ShapeFile(const char *filename, const char * mode) {
ShapeFile * self = malloc(sizeof(ShapeFile));
if (self)
self->handle = SHPOpen(filename, mode);
return self;
}
%}
%name(open) %new ShapeFile *open_ShapeFile(const char *filename,
const char * mode = "rb");
%{
ShapeFile * create_ShapeFile(const char *filename, int type) {
ShapeFile * self = malloc(sizeof(ShapeFile));
if (self)
self->handle = SHPCreate(filename, type);
return self;
}
%}
%name(create) %new ShapeFile * create_ShapeFile(const char *filename,
int type);
/* Module level function to expose some of the shapelib functions linked
* with the shapefile C-module to other Python extension modules. This
* is a kludge to make a Thuban extension work that reads shapes from
* shapefiles opened by the shapefile module.
*/
%{
static PyShapeLibAPI the_api = {
SHPReadObject,
SHPDestroyObject,
SHPCreateTree,
SHPDestroyTree,
SHPTreeFindLikelyShapes
};
PyObject * c_api() {
return PyCObject_FromVoidPtr(&the_api, NULL);
}
%}
PyObject * c_api();
/*
* Module Level functions
*/
/* convert shapefile types to names */
%name(type_name) const char *SHPTypeName(int nSHPType);
%name(part_type_name) const char *SHPPartTypeName(int nPartType);
/*
* Finally, constants copied from shapefil.h
*/
/* -------------------------------------------------------------------- */
/* Shape types (nSHPType) */
/* -------------------------------------------------------------------- */
#define SHPT_NULL 0
#define SHPT_POINT 1
#define SHPT_ARC 3
#define SHPT_POLYGON 5
#define SHPT_MULTIPOINT 8
#define SHPT_POINTZ 11
#define SHPT_ARCZ 13
#define SHPT_POLYGONZ 15
#define SHPT_MULTIPOINTZ 18
#define SHPT_POINTM 21
#define SHPT_ARCM 23
#define SHPT_POLYGONM 25
#define SHPT_MULTIPOINTM 28
#define SHPT_MULTIPATCH 31
/* -------------------------------------------------------------------- */
/* Part types - everything but SHPT_MULTIPATCH just uses */
/* SHPP_RING. */
/* -------------------------------------------------------------------- */
#define SHPP_TRISTRIP 0
#define SHPP_TRIFAN 1
#define SHPP_OUTERRING 2
#define SHPP_INNERRING 3
#define SHPP_FIRSTRING 4
#define SHPP_RING 5