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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26