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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2741 - (hide 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 bramz 2735 #include "shapefil.h"
2     #include "pyshapelib_common.h"
3     #include "pyshapelib_api.h"
4 jan 1611
5 bramz 2735 /* --- SHPObject ----------------------------------------------------------------------------------------------------- */
6 jan 1611
7 bramz 2735 typedef struct
8     {
9     PyObject_HEAD
10     SHPObject* shpObject;
11     }
12     PySHPObject;
13 jan 1611
14 bramz 2741 /* allocator
15     */
16 bramz 2735 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 jan 1611
24 bramz 2741 /* deallocator
25     */
26 bramz 2735 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 jan 1611
33 bramz 2735 /* 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 bramz 2741 if (part_type_list == Py_None)
80     {
81     Py_DECREF(part_type_list);
82     part_type_list = NULL;
83     }
84 bramz 2735 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 jan 1611 /*
179 bramz 2735 * 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 jan 1611 {
186 bramz 2735 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 jan 1611 }
191    
192    
193     /*
194 bramz 2735 * 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 jan 1611
200     static PyObject* build_vertex_list(SHPObject *object, int index, int length);
201    
202 bramz 2735 static PyObject* PySHPObject_vertices(PySHPObject* self)
203 jan 1611 {
204 bramz 2735 PyObject *result = NULL;
205     PyObject *part = NULL;
206     int part_idx, vertex_idx;
207     int length = 0;
208     SHPObject* object = self->shpObject;
209 jan 1611
210 bramz 2735 if (object->nParts > 0)
211     {
212     /* A multipart shape. Usual for SHPT_ARC and SHPT_POLYGON */
213 jan 1611
214 bramz 2735 result = PyList_New(object->nParts);
215 bramz 2741 if (!result)
216     return NULL;
217 jan 1611
218 bramz 2741 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 jan 1611
230 bramz 2741 if (PyList_SetItem(result, part_idx, part) < 0)
231     goto fail;
232 jan 1611
233 bramz 2741 vertex_idx += length;
234     }
235 jan 1611 }
236 bramz 2735 else
237     {
238 bramz 2741 /* only one part. usual for SHPT_POINT */
239     result = build_vertex_list(object, 0, object->nVertices);
240 bramz 2735 }
241 jan 1611
242 bramz 2735 return result;
243 jan 1611
244 bramz 2735 fail:
245     Py_XDECREF(part);
246     Py_DECREF(result);
247     return NULL;
248 jan 1611 }
249    
250    
251     /* Return the length coordinates of the shape object starting at vertex
252 bramz 2735 * 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 jan 1611 {
257 bramz 2735 int i;
258     PyObject * list;
259     PyObject * vertex = NULL;
260 jan 1611
261 bramz 2735 list = PyList_New(length);
262     if (!list)
263 bramz 2741 return NULL;
264 jan 1611
265 bramz 2735 for (i = 0; i < length; i++, index++)
266     {
267 bramz 2741 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 bramz 2735 }
274 jan 1611
275 bramz 2735 return list;
276 jan 1611
277 bramz 2735 fail:
278     Py_XDECREF(vertex);
279     Py_DECREF(list);
280     return NULL;
281 jan 1611 }
282    
283 bramz 2741
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 bramz 2735 static PyObject* PySHPObject_type(PySHPObject* self, void* closure)
315     {
316     return PyInt_FromLong(self->shpObject->nSHPType);
317     }
318 jan 1611
319 bramz 2741
320    
321 bramz 2735 static PyObject* PySHPObject_id(PySHPObject* self, void* closure)
322     {
323     return PyInt_FromLong(self->shpObject->nShapeId);
324     }
325 jan 1611
326 bramz 2741
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 bramz 2735 static PyMethodDef PySHPObject_methods[] =
360     {
361     {"extents", (PyCFunction)PySHPObject_extents, METH_NOARGS, NULL},
362     {"vertices", (PyCFunction)PySHPObject_vertices, METH_NOARGS, NULL},
363 bramz 2741 {"part_types", (PyCFunction)PySHPObject_part_types, METH_NOARGS, NULL},
364 bramz 2735 {NULL}
365     };
366 jan 1611
367 bramz 2735 static PyGetSetDef PySHPObject_getsetters[] =
368 jan 1611 {
369 bramz 2735 {"type", (getter)PySHPObject_type, NULL, NULL },
370     {"id", (getter)PySHPObject_id, NULL, NULL },
371     {NULL}
372     };
373 jan 1611
374 bramz 2735 static PyTypeObject PySHPObjectType = PYSHAPELIB_DEFINE_TYPE(PySHPObject, "shapelib.SHPObject", 0);
375 jan 1611
376    
377 bramz 2735 /* --- ShapeFile ----------------------------------------------------------------------------------------------------- */
378 jan 1611
379 bramz 2735 typedef struct
380     {
381     PyObject_HEAD
382     SHPHandle handle;
383     }
384     PyShapeFile;
385 jan 1611
386 bramz 2741 /* allocator
387     */
388 bramz 2735 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 jan 1611
396 bramz 2741 /* constructor
397     */
398 bramz 2735 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 jan 1611
413 bramz 2735 static PyObject* PyShapeFile_close(PyShapeFile* self)
414     {
415     SHPClose(self->handle);
416     self->handle = NULL;
417     Py_RETURN_NONE;
418     }
419 jan 1611
420 bramz 2741 /* destructor
421     */
422 bramz 2735 static void PyShapeFile_dealloc(PyShapeFile* self)
423     {
424     PyShapeFile_close(self);
425     self->ob_type->tp_free((PyObject*)self);
426     }
427 jan 1611
428 bramz 2735 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 jan 1611
437 bramz 2735 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 jan 1611 {
448 bramz 2735 PyErr_SetString(PyExc_RuntimeError, "failed to read object");
449 jan 1611 return NULL;
450     }
451 bramz 2735
452     result = PyObject_New(PySHPObject, &PySHPObjectType);
453     if (!result)
454 jan 1611 {
455 bramz 2735 return PyErr_NoMemory();
456 jan 1611 }
457 bramz 2735
458     result->shpObject = object;
459     return (PyObject*) result;
460 jan 1611 }
461    
462 bramz 2735 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 jan 1611 }
483    
484 bramz 2735 static PyObject* PyShapeFile_cobject(PyShapeFile* self)
485     {
486     return PyCObject_FromVoidPtr(self->handle, NULL);
487 jan 1611 }
488    
489 bramz 2741 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 bramz 2735 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 jan 1611
507 bramz 2735 static PyGetSetDef PyShapeFile_getsetters[] =
508     {
509     {NULL}
510     };
511 jan 1611
512 bramz 2735 static PyTypeObject PyShapeFileType = PYSHAPELIB_DEFINE_TYPE(PyShapeFile, "shapelib.ShapeFile", 0);
513 jan 1611
514 bramz 2735 /* --- shapelib ------------------------------------------------------------------------------------------------------ */
515 jan 1611
516 bramz 2735 static PyObject* shapelib_open(PyObject* module, PyObject* args)
517     {
518     return PyObject_CallObject((PyObject*)&PyShapeFileType, args);
519 jan 1611 }
520    
521 bramz 2735 static PyObject* shapelib_create(PyObject* module, PyObject* args)
522 jan 1611 {
523 bramz 2735 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 jan 1611 }
534 bramz 2735
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 jan 1611 }
542 bramz 2735
543     return (PyObject*) result;
544     }
545    
546     static PyShapeLibAPI shapelib_the_api =
547     {
548 jan 1611 SHPReadObject,
549     SHPDestroyObject,
550     SHPCreateTree,
551     SHPDestroyTree,
552     SHPTreeFindLikelyShapes
553 bramz 2735 };
554 jan 1611
555 bramz 2735 static PyObject* shapelib_c_api(PyObject* module)
556     {
557     return PyCObject_FromVoidPtr(&shapelib_the_api, NULL);
558     }
559 jan 1611
560 bramz 2735 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 jan 1611
567 bramz 2735 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 jan 1611
574 bramz 2735 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 jan 1611
584 bramz 2735 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 jan 1611

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26