/[thuban]/branches/WIP-pyshapelib-bramz/libraries/pyshapelib/shapelibmodule.c
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/libraries/pyshapelib/shapelibmodule.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2735 - (show annotations)
Mon Mar 12 23:24:35 2007 UTC (17 years, 11 months ago) by bramz
Original Path: branches/WIP-pyshapelib-bramz/libraries/pyshapelib/shapelib.c
File MIME type: text/plain
File size: 13581 byte(s)
rewritten shapelib to use hand-crafted Python bindings instead of SWIG generated ones.
1 #include "shapefil.h"
2 #include "pyshapelib_common.h"
3 #include "pyshapelib_api.h"
4
5 /* --- SHPObject ----------------------------------------------------------------------------------------------------- */
6
7 typedef struct
8 {
9 PyObject_HEAD
10 SHPObject* shpObject;
11 }
12 PySHPObject;
13
14 static PyObject* PySHPObject_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
15 {
16 PySHPObject* self;
17 self = (PySHPObject*) type->tp_alloc(type, 0);
18 self->shpObject = NULL;
19 return (PyObject*) self;
20 }
21
22 static void PySHPObject_dealloc(PySHPObject* self)
23 {
24 SHPDestroyObject(self->shpObject);
25 self->shpObject = NULL;
26 self->ob_type->tp_free((PyObject*)self);
27 }
28
29 /* The constructor of SHPObject. parts is a list of lists of tuples
30 * describing the parts and their vertices just likethe output of the
31 * vertices() method. part_type_list is the list of part-types and may
32 * be NULL. For the meaning of the part-types and their default value
33 * see the Shaplib documentation.
34 */
35 static int PySHPObject_init(PySHPObject* self, PyObject* args, PyObject* kwds)
36 {
37 int type;
38 int id;
39 PyObject* parts = NULL;
40 PyObject* part_type_list = NULL;
41
42 int num_parts;
43 int num_vertices;
44 int part_start;
45
46 double* xs = NULL;
47 double* ys = NULL;
48 int* part_starts = NULL;
49 int* part_types = NULL;
50
51 int i;
52 int return_code = -1;
53
54 /* first, unpack parameters */
55 if (kwds != NULL && PyDict_Size(kwds) > 0)
56 {
57 PyErr_Format(PyExc_TypeError, "shapelib.SHPObject.__init__ takes no keyword arguments");
58 return -1;
59 }
60 if (!PyArg_ParseTuple(args, "iiO|O", &type, &id, &parts, &part_type_list)) return -1;
61
62 if (!PySequence_Check(parts))
63 {
64 PyErr_SetString(PyExc_TypeError, "parts is not a sequence");
65 return -1;
66 }
67 num_parts = PySequence_Length(parts);
68 if (num_parts < 0)
69 {
70 PyErr_SetString(PyExc_TypeError, "cannot determine length of parts");
71 return -1;
72 }
73
74 /* parts and part_types have to have the same lengths */
75 if (part_type_list)
76 {
77 if (!PySequence_Check(parts))
78 {
79 PyErr_SetString(PyExc_TypeError, "part_type_list is not a sequence");
80 return -1;
81 }
82 if (PySequence_Length(part_type_list) != num_parts)
83 {
84 PyErr_SetString(PyExc_TypeError, "parts and part_types have to have the same lengths");
85 return -1;
86 }
87 }
88
89 /* determine how many vertices there are altogether */
90 num_vertices = 0;
91 for (i = 0; i < num_parts; ++i)
92 {
93 PyObject* part = PySequence_ITEM(parts, i);
94 if (!PySequence_Check(part))
95 {
96 PyErr_SetString(PyExc_TypeError, "at least one item in parts is not a sequence");
97 Py_DECREF(part);
98 return -1;
99 }
100 num_vertices += PySequence_Length(part);
101 Py_DECREF(part);
102 }
103
104 /* allocate the memory for the various arrays and check for memory errors */
105 xs = malloc(num_vertices * sizeof(double));
106 ys = malloc(num_vertices * sizeof(double));
107 part_starts = malloc(num_parts * sizeof(int));
108 part_types = part_type_list ? malloc(num_parts * sizeof(int)) : 0;
109
110 if (!xs || !ys || !part_starts || (part_type_list && !part_types))
111 {
112 PyErr_NoMemory();
113 goto exit;
114 }
115
116 /* convert the part types */
117 if (part_type_list)
118 {
119 for (i = 0; i < num_parts; i++)
120 {
121 PyObject* otype = PySequence_ITEM(part_type_list, i);
122 part_types[i] = PyInt_AsLong(otype);
123 Py_DECREF(otype);
124 if (part_types[i] < 0)
125 {
126 PyErr_SetString(PyExc_TypeError, "at least one item in part_type_list is not an integer or is negative");
127 goto exit;
128 }
129 }
130 }
131
132 /* convert the list of parts */
133 part_start = 0;
134 for (i = 0; i < num_parts; ++i)
135 {
136 int j, length;
137
138 PyObject* part = PySequence_ITEM(parts, i);
139 length = PySequence_Length(part);
140 part_starts[i] = part_start;
141
142 for (j = 0; j < length; ++j)
143 {
144 PyObject* vertex = PySequence_ITEM(part, j);
145 if (!PyArg_ParseTuple(vertex, "dd", xs + part_start + j, ys + part_start + j))
146 {
147 PyErr_SetString(PyExc_TypeError, "at least one part contains an vertex that's not a tuple of two doubles");
148 Py_DECREF(vertex);
149 Py_DECREF(part);
150 goto exit;
151 }
152 Py_DECREF(vertex);
153 }
154 Py_DECREF(part);
155 part_start += length;
156 }
157
158 self->shpObject = SHPCreateObject(type, id, num_parts, part_starts, part_types, num_vertices, xs, ys, NULL, NULL);
159 return_code = 0;
160
161 exit:
162 free(xs);
163 free(ys);
164 free(part_starts);
165 free(part_types);
166 return return_code;
167 }
168
169 /*
170 * The extents() method of SHPObject.
171 *
172 * Return the extents as a tuple of two 4-element lists with the min.
173 * and max. values of x, y, z, m.
174 */
175 static PyObject* PySHPObject_extents(PySHPObject* self)
176 {
177 SHPObject* object = self->shpObject;
178 return Py_BuildValue("(dddd)(dddd)",
179 object->dfXMin, object->dfYMin, object->dfZMin, object->dfMMin,
180 object->dfXMax, object->dfYMax, object->dfZMax, object->dfMMax);
181 }
182
183
184 /*
185 * The vertices() method of SHPObject.
186 *
187 * Return the x and y coords of the vertices as a list of lists of
188 * tuples.
189 */
190
191 static PyObject* build_vertex_list(SHPObject *object, int index, int length);
192
193 static PyObject* PySHPObject_vertices(PySHPObject* self)
194 {
195 PyObject *result = NULL;
196 PyObject *part = NULL;
197 int part_idx, vertex_idx;
198 int length = 0;
199 SHPObject* object = self->shpObject;
200
201 if (object->nParts > 0)
202 {
203 /* A multipart shape. Usual for SHPT_ARC and SHPT_POLYGON */
204
205 result = PyList_New(object->nParts);
206 if (!result)
207 return NULL;
208
209 for (part_idx = 0, vertex_idx = 0; part_idx < object->nParts;
210 part_idx++)
211 {
212 if (part_idx < object->nParts - 1)
213 length = (object->panPartStart[part_idx + 1]
214 - object->panPartStart[part_idx]);
215 else
216 length = object->nVertices - object->panPartStart[part_idx];
217
218 part = build_vertex_list(object, vertex_idx, length);
219 if (!part)
220 goto fail;
221
222 if (PyList_SetItem(result, part_idx, part) < 0)
223 goto fail;
224
225 vertex_idx += length;
226 }
227 }
228 else
229 {
230 /* only one part. usual for SHPT_POINT */
231 result = build_vertex_list(object, 0, object->nVertices);
232 }
233
234 return result;
235
236 fail:
237 Py_XDECREF(part);
238 Py_DECREF(result);
239 return NULL;
240 }
241
242
243 /* Return the length coordinates of the shape object starting at vertex
244 * index as a Python-list of tuples. Helper function for
245 * SHPObject_vertices.
246 */
247 static PyObject* build_vertex_list(SHPObject *object, int index, int length)
248 {
249 int i;
250 PyObject * list;
251 PyObject * vertex = NULL;
252
253 list = PyList_New(length);
254 if (!list)
255 return NULL;
256
257 for (i = 0; i < length; i++, index++)
258 {
259 vertex = Py_BuildValue("dd", object->padfX[index],
260 object->padfY[index]);
261 if (!vertex)
262 goto fail;
263 if (PyList_SetItem(list, i, vertex) < 0)
264 goto fail;
265 }
266
267 return list;
268
269 fail:
270 Py_XDECREF(vertex);
271 Py_DECREF(list);
272 return NULL;
273 }
274
275 static PyObject* PySHPObject_type(PySHPObject* self, void* closure)
276 {
277 return PyInt_FromLong(self->shpObject->nSHPType);
278 }
279
280 static PyObject* PySHPObject_id(PySHPObject* self, void* closure)
281 {
282 return PyInt_FromLong(self->shpObject->nShapeId);
283 }
284
285 static PyMethodDef PySHPObject_methods[] =
286 {
287 {"extents", (PyCFunction)PySHPObject_extents, METH_NOARGS, NULL},
288 {"vertices", (PyCFunction)PySHPObject_vertices, METH_NOARGS, NULL},
289 {NULL}
290 };
291
292 static PyGetSetDef PySHPObject_getsetters[] =
293 {
294 {"type", (getter)PySHPObject_type, NULL, NULL },
295 {"id", (getter)PySHPObject_id, NULL, NULL },
296 {NULL}
297 };
298
299 static PyTypeObject PySHPObjectType = PYSHAPELIB_DEFINE_TYPE(PySHPObject, "shapelib.SHPObject", 0);
300
301
302 /* --- ShapeFile ----------------------------------------------------------------------------------------------------- */
303
304 typedef struct
305 {
306 PyObject_HEAD
307 SHPHandle handle;
308 }
309 PyShapeFile;
310
311 static PyObject* PyShapeFile_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
312 {
313 PyShapeFile* self;
314 self = (PyShapeFile*) type->tp_alloc(type, 0);
315 self->handle = NULL;
316 return (PyObject*) self;
317 }
318
319 static int PyShapeFile_init(PyShapeFile* self, PyObject* args, PyObject* kwds)
320 {
321 char* file;
322 char* mode = "rb";
323 if (kwds != NULL && PyDict_Size(kwds) > 0)
324 {
325 PyErr_Format(PyExc_TypeError, "shapelib.ShapeFile.__init__ takes no keyword arguments");
326 return -1;
327 }
328 if (!PyArg_ParseTuple(args, "s|s", &file, &mode)) return -1;
329
330 self->handle = SHPOpen(file, mode);
331 return self->handle ? 0 : -1;
332 }
333
334 static PyObject* PyShapeFile_close(PyShapeFile* self)
335 {
336 SHPClose(self->handle);
337 self->handle = NULL;
338 Py_RETURN_NONE;
339 }
340
341 static void PyShapeFile_dealloc(PyShapeFile* self)
342 {
343 PyShapeFile_close(self);
344 self->ob_type->tp_free((PyObject*)self);
345 }
346
347 static PyObject* PyShapeFile_info(PyShapeFile* self)
348 {
349 SHPHandle handle = self->handle;
350 return Py_BuildValue("ii(dddd)(dddd)",
351 handle->nRecords, handle->nShapeType,
352 handle->adBoundsMin[0], handle->adBoundsMin[1], handle->adBoundsMin[2], handle->adBoundsMin[3],
353 handle->adBoundsMax[0], handle->adBoundsMax[1], handle->adBoundsMax[2], handle->adBoundsMax[3]);
354 }
355
356 static PyObject* PyShapeFile_read_object(PyShapeFile* self, PyObject* args)
357 {
358 int index;
359 SHPObject* object;
360 PySHPObject* result;
361
362 if (!PyArg_ParseTuple(args, "i", &index)) return NULL;
363
364 object = SHPReadObject(self->handle, index);
365 if (!object)
366 {
367 PyErr_SetString(PyExc_RuntimeError, "failed to read object");
368 return NULL;
369 }
370
371 result = PyObject_New(PySHPObject, &PySHPObjectType);
372 if (!result)
373 {
374 return PyErr_NoMemory();
375 }
376
377 result->shpObject = object;
378 return (PyObject*) result;
379 }
380
381 static PyObject* PyShapeFile_write_object(PyShapeFile* self, PyObject* args)
382 {
383 int index, result;
384 PyObject* object;
385
386 if (!PyArg_ParseTuple(args, "iO", &index, &object)) return NULL;
387
388 if (!PyObject_IsInstance(object, (PyObject*)&PySHPObjectType))
389 {
390 PyErr_SetString(PyExc_TypeError, "object is not a SHPObject");
391 return NULL;
392 }
393
394 result = SHPWriteObject(self->handle, index, ((PySHPObject*)object)->shpObject);
395 if (result < 0)
396 {
397 PyErr_SetString(PyExc_RuntimeError, "failed to write object");
398 return NULL;
399 }
400 return PyInt_FromLong((long)result);
401 }
402
403 static PyObject* PyShapeFile_cobject(PyShapeFile* self)
404 {
405 return PyCObject_FromVoidPtr(self->handle, NULL);
406 }
407
408 static PyMethodDef PyShapeFile_methods[] =
409 {
410 {"close", (PyCFunction)PyShapeFile_close, METH_NOARGS, "close the shape file" },
411 {"info", (PyCFunction)PyShapeFile_info, METH_NOARGS,
412 "Return a tuple (NUM_SHAPES, TYPE, MIN, MAX) where NUM_SHAPES is the number of shapes in the file, TYPE is the "
413 "shape type and MIN and MAX are 4-element tuples with the min. and max. values of the data." },
414 {"read_object", (PyCFunction)PyShapeFile_read_object, METH_VARARGS, "Return object number i" },
415 {"write_object", (PyCFunction)PyShapeFile_write_object, METH_VARARGS, "Write an object"},
416 {"cobject", (PyCFunction)PyShapeFile_cobject, METH_NOARGS, "Return the shapelib SHPHandle as a Python CObject"},
417 {NULL}
418 };
419
420 static PyGetSetDef PyShapeFile_getsetters[] =
421 {
422 {NULL}
423 };
424
425 static PyTypeObject PyShapeFileType = PYSHAPELIB_DEFINE_TYPE(PyShapeFile, "shapelib.ShapeFile", 0);
426
427 /* --- shapelib ------------------------------------------------------------------------------------------------------ */
428
429 static PyObject* shapelib_open(PyObject* module, PyObject* args)
430 {
431 return PyObject_CallObject((PyObject*)&PyShapeFileType, args);
432 }
433
434 static PyObject* shapelib_create(PyObject* module, PyObject* args)
435 {
436 char* file;
437 int type;
438 PyShapeFile* result;
439
440 if (!PyArg_ParseTuple(args, "si", &file, &type)) return NULL;
441
442 result = PyObject_New(PyShapeFile, &PyShapeFileType);
443 if (!result)
444 {
445 return PyErr_NoMemory();
446 }
447
448 result->handle = SHPCreate(file, type);
449 if (!result->handle)
450 {
451 PyObject_Del((PyObject*)result);
452 PyErr_SetString(PyExc_RuntimeError, "Failed to create ShapeFile");
453 return NULL;
454 }
455
456 return (PyObject*) result;
457 }
458
459 static PyShapeLibAPI shapelib_the_api =
460 {
461 SHPReadObject,
462 SHPDestroyObject,
463 SHPCreateTree,
464 SHPDestroyTree,
465 SHPTreeFindLikelyShapes
466 };
467
468 static PyObject* shapelib_c_api(PyObject* module)
469 {
470 return PyCObject_FromVoidPtr(&shapelib_the_api, NULL);
471 }
472
473 static PyObject* shapelib_type_name(PyObject* module, PyObject* args)
474 {
475 int type;
476 if (!PyArg_ParseTuple(args, "i", &type)) return NULL;
477 return PyString_FromString(SHPTypeName(type));
478 }
479
480 static PyObject* shapelib_part_type_name(PyObject* module, PyObject* args)
481 {
482 int type;
483 if (!PyArg_ParseTuple(args, "i", &type)) return NULL;
484 return PyString_FromString(SHPPartTypeName(type));
485 }
486
487 static PyMethodDef shapelib_methods[] =
488 {
489 {"open", (PyCFunction)shapelib_open, METH_VARARGS, "open a ShapeFile" },
490 {"create", (PyCFunction)shapelib_create, METH_VARARGS, "create a ShapeFile" },
491 {"c_api", (PyCFunction)shapelib_c_api, METH_NOARGS, "get C API of shapelib" },
492 {"type_name", (PyCFunction)shapelib_type_name, METH_VARARGS, "return type as string" },
493 {"part_type_name", (PyCFunction)shapelib_part_type_name, METH_VARARGS, "return part type as string" },
494 {NULL}
495 };
496
497 PyMODINIT_FUNC initshapelib(void)
498 {
499 PyObject* module = Py_InitModule("shapelib", shapelib_methods);
500 if (!module) return;
501
502 PYSHAPELIB_ADD_TYPE(PySHPObjectType, "SHPObject");
503 PYSHAPELIB_ADD_TYPE(PyShapeFileType, "ShapeFile");
504
505 PYSHAPELIB_ADD_CONSTANT(SHPT_NULL);
506 PYSHAPELIB_ADD_CONSTANT(SHPT_POINT);
507 PYSHAPELIB_ADD_CONSTANT(SHPT_ARC);
508 PYSHAPELIB_ADD_CONSTANT(SHPT_POLYGON);
509 PYSHAPELIB_ADD_CONSTANT(SHPT_MULTIPOINT);
510 PYSHAPELIB_ADD_CONSTANT(SHPT_POINTZ);
511 PYSHAPELIB_ADD_CONSTANT(SHPT_ARCZ);
512 PYSHAPELIB_ADD_CONSTANT(SHPT_POLYGONZ);
513 PYSHAPELIB_ADD_CONSTANT(SHPT_MULTIPOINTZ);
514 PYSHAPELIB_ADD_CONSTANT(SHPT_POINTM);
515 PYSHAPELIB_ADD_CONSTANT(SHPT_ARCM);
516 PYSHAPELIB_ADD_CONSTANT(SHPT_POLYGONM);
517 PYSHAPELIB_ADD_CONSTANT(SHPT_MULTIPOINTM);
518 PYSHAPELIB_ADD_CONSTANT(SHPT_MULTIPATCH);
519 PYSHAPELIB_ADD_CONSTANT(SHPP_TRISTRIP);
520 PYSHAPELIB_ADD_CONSTANT(SHPP_TRIFAN);
521 PYSHAPELIB_ADD_CONSTANT(SHPP_OUTERRING);
522 PYSHAPELIB_ADD_CONSTANT(SHPP_INNERRING);
523 PYSHAPELIB_ADD_CONSTANT(SHPP_FIRSTRING);
524 PYSHAPELIB_ADD_CONSTANT(SHPP_RING);
525 }
526

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26