/[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 2742 - (show annotations)
Wed Mar 14 16:26:14 2007 UTC (18 years ago) by bramz
File MIME type: text/plain
File size: 15365 byte(s)
pyshapelib: rewritten dbflib to use hand-crafted Python bindings instead of SWIG generated ones.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26