root/PCL/trunk/PCL-Core/cartography/geometry/_geommodule.c

Revision 544 (checked in by seang, 2 years ago)

merged changes from r464:543 of the minimal-dependencies branch, added a few missing module inits, a couple fixes to build and pass the tests

Line 
1 /*
2 # =============================================================================
3 # Python Cartographic Library. Copyright (C) 2006 Sean C. Gillies
4 #
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the Free
7 # Software Foundation; either version 2 of the License, or (at your option)
8 # any later version.
9 #
10 # This program is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 # details.
14 #
15 # You should have received a copy of the GNU General Public License along with
16 # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 # Place, Suite 330, Boston, MA 02111-1307 USA
18 #
19 # Contact email: sgillies@frii.com
20 # =============================================================================
21 */
22
23 #include "Python.h"
24 #include "structmember.h"
25
26 #include "geos_c.h"
27 #include "proj_api.h"
28
29 static PyObject *GEOSError;
30
31 typedef struct {
32     PyObject_HEAD
33     GEOSCoordSeq seq;
34     /* Flag for whether seq is an owned (1) or borrowed (0) reference to
35        allocated memory */
36     int owns;
37 } CoordSeq;
38
39 staticforward PyTypeObject CoordinateSequenceType;
40
41 typedef struct {
42     PyObject_HEAD
43     GEOSGeom geom;
44     /* Flag for whether seq is an owned (1) or borrowed (0) reference to
45        allocated memory */
46     int owns;
47 } Geometry;
48
49 staticforward PyTypeObject GeometryType;
50
51 /*
52 ==============================================================================
53  CoordinateSequence
54 ==============================================================================
55 */
56
57 /* === Alloc/dealloc === */
58
59 PyObject *
60 CoordSeq_New(GEOSCoordSeq s)
61 {
62     CoordSeq *self;
63    
64     if (!s)
65         return NULL;
66    
67     self = PyObject_NEW(CoordSeq, &CoordinateSequenceType);
68     if (self == NULL)
69     {
70         GEOSCoordSeq_destroy(self->seq);
71         return NULL;
72     }
73    
74     self->seq = s;
75     self->owns = 1;
76     return (PyObject *) self;
77 }
78
79 static PyObject *
80 _createCoordSeq(PyObject *self, PyObject *args)
81 {
82     int size=1;
83     int dims=3;
84     GEOSCoordSeq s;
85    
86     if (!PyArg_ParseTuple(args, "i|i", &size, &dims))
87         return NULL;
88        
89     if (size < 1)
90     {
91         PyErr_SetString(PyExc_ValueError, "Sequence must have size >=1");
92         return NULL;
93     }
94     if (dims < 2 || dims > 3)
95     {
96         PyErr_SetString(PyExc_ValueError, "Dimensions must be 2 or 3");
97         return NULL;
98     }
99    
100     s = (GEOSCoordSeq) GEOSCoordSeq_create(size, dims);
101     if (!s)
102         return NULL;
103    
104     return CoordSeq_New(s);
105 }
106
107 static void
108 CoordSeq_dealloc(CoordSeq *self)
109 {
110     if (self->owns && self->seq != NULL)
111     {
112         GEOSCoordSeq_destroy(self->seq);
113     }
114     self->seq = NULL;
115     self->ob_type->tp_free((PyObject*) self);
116 }
117
118 static PyObject *
119 CoordSeq_clone(CoordSeq *self)
120 {
121     CoordSeq *s;
122     GEOSCoordSeq new;
123
124     s = (CoordSeq *) self;
125     new = GEOSCoordSeq_clone(s->seq);
126     if (!new)
127         return NULL;
128
129     return (PyObject *) CoordSeq_New(new);
130 }
131
132 /* === Methods === */
133
134 static PyObject *
135 CoordSeq_getSize(CoordSeq *self)
136 {
137     unsigned int size;
138     if (GEOSCoordSeq_getSize(self->seq, &size) == 0)
139     {
140         PyErr_SetString(PyExc_Exception, "Failed to get sequence size");
141         return NULL;
142     }   
143     return Py_BuildValue("i", size);
144 }
145
146 static PyObject *
147 CoordSeq_getDimensions(CoordSeq *self)
148 {
149     unsigned int dims;
150     if (!GEOSCoordSeq_getDimensions(self->seq, &dims))
151     {
152         PyErr_SetString(PyExc_Exception, "Failed to get sequence dimensions");
153         return NULL;
154     }   
155     return Py_BuildValue("i", dims);
156 }
157
158 static PyObject *
159 CoordSeq_getX(CoordSeq *self, PyObject *item)
160 {
161     unsigned int num;
162     double value;
163     long n;
164    
165     if (!PyInt_Check(item))
166     {
167                 PyErr_SetString(PyExc_TypeError, "index must be an integer");
168                 return NULL;
169         }
170    
171     GEOSCoordSeq_getSize(self->seq, &num);
172     if (num == 0)
173     {
174         PyErr_SetString(PyExc_Exception, "Sequence has no coordinates");
175         return NULL;
176     }
177
178     n = PyInt_AS_LONG(item);
179     if (n < 0 || n >= num)
180     {
181         PyErr_Format(PyExc_IndexError,
182                 "Index is beyond valid range [0:%d]", num);
183         return NULL;
184     }
185    
186     if (!GEOSCoordSeq_getX(self->seq, (int)n, &value))
187     {
188         PyErr_SetString(PyExc_Exception, "Failed to get X");
189         return NULL;
190     }
191     return Py_BuildValue("d", value);
192 }
193
194 static PyObject *
195 CoordSeq_getY(CoordSeq *self, PyObject *item)
196 {
197     unsigned int num;
198     double value;
199     long n;
200    
201     if (!PyInt_Check(item))
202     {
203                 PyErr_SetString(PyExc_TypeError, "index must be an integer");
204                 return NULL;
205         }
206    
207     GEOSCoordSeq_getSize(self->seq, &num);
208     if (num == 0)
209     {
210         PyErr_SetString(PyExc_Exception, "Sequence has no coordinates");
211         return NULL;
212     }
213
214     n = PyInt_AS_LONG(item);
215     if (n < 0 || n >= num)
216     {
217         PyErr_Format(PyExc_IndexError,
218                 "Index is beyond valid range [0:%d]", num);
219         return NULL;
220     }
221    
222     if (!GEOSCoordSeq_getY(self->seq, (int)n, &value))
223     {
224         PyErr_SetString(PyExc_Exception, "Failed to get Y");
225         return NULL;
226     }
227     return Py_BuildValue("d", value);
228 }
229
230 static PyObject *
231 CoordSeq_getZ(CoordSeq *self, PyObject *item)
232 {
233     unsigned int num;
234     double value;
235     long n;
236    
237     if (!PyInt_Check(item))
238     {
239                 PyErr_SetString(PyExc_TypeError, "index must be an integer");
240                 return NULL;
241         }
242    
243     GEOSCoordSeq_getSize(self->seq, &num);
244     if (num == 0)
245     {
246         PyErr_SetString(PyExc_Exception, "Sequence has no coordinates");
247         return NULL;
248     }
249
250     n = PyInt_AS_LONG(item);
251     if (n < 0 || n >= num)
252     {
253         PyErr_Format(PyExc_IndexError,
254                 "Index is beyond valid range [0:%d]", num);
255         return NULL;
256     }
257    
258     if (!GEOSCoordSeq_getZ(self->seq, (int)n, &value))
259     {
260         PyErr_SetString(PyExc_Exception, "Failed to get Z");
261         return NULL;
262     }
263     return Py_BuildValue("d", value);
264 }
265
266 static PyObject *
267 CoordSeq_setX(CoordSeq *self, PyObject *args)
268 {
269     int n;
270     unsigned int num;
271     double value;
272     if (!PyArg_ParseTuple(args, "id", &n, &value))
273     {
274                 return NULL;
275         }
276    
277     GEOSCoordSeq_getSize(self->seq, &num);
278     if (num == 0)
279     {
280         PyErr_SetString(PyExc_Exception, "Sequence has no coordinates");
281         return NULL;
282     }
283
284     if (n < 0 || n >= num)
285     {
286         PyErr_Format(PyExc_IndexError,
287                 "Index is beyond valid range [0:%d]", num);
288         return NULL;
289     }
290    
291     if (!GEOSCoordSeq_setX(self->seq, (int)n, value))
292     {
293         PyErr_SetString(PyExc_Exception, "Failed to set X");
294         return NULL;
295     }
296    
297     Py_INCREF(Py_None);
298     return Py_None;
299 }
300
301 static PyObject *
302 CoordSeq_setY(CoordSeq *self, PyObject *args)
303 {
304     int n;
305     unsigned int num;
306     double value;
307     if (!PyArg_ParseTuple(args, "id", &n, &value))
308     {
309                 return NULL;
310         }
311    
312     GEOSCoordSeq_getSize(self->seq, &num);
313     if (num == 0)
314     {
315         PyErr_SetString(PyExc_Exception, "Sequence has no coordinates");
316         return NULL;
317     }
318    
319     if (n < 0 || n >= num)
320     {
321         PyErr_Format(PyExc_IndexError,
322                      "Index is beyond valid range [0:%d]", num);
323         return NULL;
324     }
325    
326     if (!GEOSCoordSeq_setY(self->seq, (int)n, value))
327     {
328         PyErr_SetString(PyExc_Exception, "Failed to set Y");
329         return NULL;
330     }
331    
332     Py_INCREF(Py_None);
333     return Py_None;
334 }
335
336 static PyObject *
337 CoordSeq_setZ(CoordSeq *self, PyObject *args)
338 {
339     int n;
340     unsigned int num;
341     double value;
342     if (!PyArg_ParseTuple(args, "id", &n, &value))
343     {
344                 return NULL;
345         }
346    
347     GEOSCoordSeq_getSize(self->seq, &num);
348     if (num == 0)
349     {
350         PyErr_SetString(PyExc_Exception, "Sequence has no coordinates");
351         return NULL;
352     }
353    
354     if (n < 0 || n >= num)
355     {
356         PyErr_Format(PyExc_IndexError,
357                      "Index is beyond valid range [0:%d]", num);
358         return NULL;
359     }
360    
361     if (!GEOSCoordSeq_setZ(self->seq, (int)n, value))
362     {
363         PyErr_SetString(PyExc_Exception, "Failed to set Z");
364         return NULL;
365     }
366    
367     Py_INCREF(Py_None);
368     return Py_None;
369 }
370
371 /* === Define Methods === */
372
373 static PyMethodDef coordseq_methods[] = {
374     {"getSize", (PyCFunction)CoordSeq_getSize, METH_NOARGS, "Returns number of coordinates in the sequence"},
375     {"getDimensions", (PyCFunction)CoordSeq_getDimensions, METH_NOARGS, "Returns number of coordinate dimensions"},
376     {"clone", (PyCFunction)CoordSeq_clone, METH_NOARGS, "Returns clone"},
377     {"getX", (PyCFunction)CoordSeq_getX, METH_O, "Get Nth X, index starting at 0"},
378     {"getY", (PyCFunction)CoordSeq_getY, METH_O, "Get Nth Y, index starting at 0"},
379     {"getZ", (PyCFunction)CoordSeq_getZ, METH_O, "Get Nth Z, index starting at 0"},
380     {"setX", (PyCFunction)CoordSeq_setX, METH_VARARGS, "Set Nth X, index starting at 0"},
381     {"setY", (PyCFunction)CoordSeq_setY, METH_VARARGS, "Set Nth Y, index starting at 0"},
382     {"setZ", (PyCFunction)CoordSeq_setZ, METH_VARARGS, "Set Nth Z, index starting at 0"},
383     {NULL}
384 };
385
386 /* === Define Type === */
387
388 static PyTypeObject CoordinateSequenceType = {
389     PyObject_HEAD_INIT(NULL)
390     0,                              /*ob_size*/
391     "GEOSCoordinateSequence", /*tp_name*/
392     sizeof(CoordSeq),               /*tp_basicsize*/
393     0,                              /*tp_itemsize*/
394     (destructor)CoordSeq_dealloc,   /*tp_dealloc*/
395     0,                              /*tp_print*/
396     0,                              /*tp_getattr*/
397     0,                              /*tp_setattr*/
398     0,                              /*tp_compare*/
399     0,                              /*tp_repr*/
400     0,                              /*tp_as_number*/
401     0,                              /*tp_as_sequence*/
402     0,                              /*tp_as_mapping*/
403     0,                              /*tp_hash */
404     0,                              /*tp_call*/
405     0,                              /*tp_str*/
406     0,                              /*tp_getattro*/
407     0,                              /*tp_setattro*/
408     0,                              /*tp_as_buffer*/
409     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
410     "A GEOS Coordinate Sequence",           /* tp_doc */
411     0,                         /* tp_traverse */
412     0,                         /* tp_clear */
413     0,                         /* tp_richcompare */
414     0,                         /* tp_weaklistoffset */
415     0,                         /* tp_iter */
416     0,                         /* tp_iternext */
417     coordseq_methods,             /* tp_methods */
418     0,                     /* tp_members */
419     0,                         /* tp_getset */
420     0,                         /* tp_base */
421     0,                         /* tp_dict */
422     0,                         /* tp_descr_get */
423     0,                         /* tp_descr_set */
424     0,                         /* tp_dictoffset */
425     0,      /* tp_init */
426     0,                         /* tp_alloc */
427     0,                 /* tp_new */
428 };
429
430 /*
431 ==============================================================================
432  Geometry
433 ==============================================================================
434 */
435
436 /* === Alloc/dealloc === */
437
438 static void
439 Geometry_dealloc(Geometry *self)
440 {
441     if (self->owns && self->geom != NULL)
442     {
443         GEOSGeom_destroy(self->geom);
444     }
445     self->geom = NULL;
446     self->ob_type->tp_free((PyObject*) self);
447 }
448
449 PyObject *
450 Geometry_New(GEOSGeom g)
451 {
452     Geometry *self;
453    
454     if (!g)
455         return NULL;
456    
457     self = PyObject_NEW(Geometry, &GeometryType);
458     if (self == NULL)
459     {
460         GEOSGeom_destroy(g);
461         return NULL;
462     }
463    
464     self->geom = g;
465     self->owns = 1;
466     return (PyObject *) self;
467 }
468
469 static PyObject *
470 Geometry_clone(PyObject *self)
471 {
472     Geometry *g;
473     GEOSGeom new;
474
475     g = (Geometry *) self;
476     if (!g->geom)
477     {
478         PyErr_SetString(PyExc_Exception, "NULL GEOSGeom");
479         return NULL;
480     }
481    
482     new = GEOSGeom_clone(g->geom);
483     if (!new)
484         return NULL;
485
486     return (PyObject *) Geometry_New(new);
487 }
488
489 static PyObject *
490 _createGeomFromWKB(PyObject *self, PyObject *args)
491 {
492     unsigned char *data=NULL;
493     int size;
494     GEOSGeom g;
495    
496     if (!PyArg_ParseTuple(args, "s#", &data, &size))
497         return NULL;
498
499     g = GEOSGeomFromWKB_buf(data, (size_t)size);
500     if (!g)
501     {
502         /* Rely on exception set by GEOS through error_handler */
503         return NULL;
504     }
505        
506     return Geometry_New(g);
507 }
508
509 static PyObject *
510 _updateGeomFromWKB(PyObject *self, PyObject *args)
511 {
512     unsigned char *data=NULL;
513     int size;
514     GEOSGeom g;
515     Geometry *gs;
516    
517     if (!PyArg_ParseTuple(args, "s#", &data, &size))
518         return NULL;
519
520     g = GEOSGeomFromWKB_buf(data, (size_t)size);
521     if (!g)
522     {
523         /* Rely on exception set by GEOS through error_handler */
524         return NULL;
525     }
526
527     gs = (Geometry *) self;
528     if (gs->geom)
529         GEOSGeom_destroy(gs->geom);
530     gs->geom = g;
531     gs->owns = 1;
532    
533     Py_INCREF(Py_None);
534     return Py_None;
535 }
536    
537 static PyObject *
538 _createGeomFromWKT(PyObject *self, PyObject *args)
539 {
540     char *data;
541     GEOSGeom g;
542    
543     if (!PyArg_ParseTuple(args, "s", &data))
544         return NULL;
545        
546     g = GEOSGeomFromWKT(data);
547     if (!g)
548     {
549         /* Rely on exception set by GEOS through error_handler */
550         return NULL;
551     }
552    
553     return Geometry_New(g);
554 }
555
556 static PyObject *
557 _updateGeomFromWKT(PyObject *self, PyObject *args)
558 {
559     char *data;
560     GEOSGeom g;
561     Geometry *gs;
562
563     if (!PyArg_ParseTuple(args, "s", &data))
564         return NULL;
565        
566     g = GEOSGeomFromWKT(data);
567     if (!g)
568     {
569         /* Rely on exception set by GEOS through error_handler */
570         return NULL;
571     }
572
573     gs = (Geometry *) self;
574     if (gs->geom)
575         GEOSGeom_destroy(gs->geom);
576     gs->geom = g;
577     gs->owns = 1;
578    
579     Py_INCREF(Py_None);
580     return Py_None;
581 }
582    
583 static PyObject *
584 _createGeomFromCoordSeq(PyObject *self, PyObject *args)
585 {
586     PyObject *seq=NULL;
587     int typeid;
588     GEOSGeom g;
589     CoordSeq *s;
590     PyObject *geom;
591     unsigned int size=0;
592    
593     if (!PyArg_ParseTuple(args, "O!i", &CoordinateSequenceType, &seq,  &typeid))
594         return NULL;
595
596     s = (CoordSeq *) seq;
597
598     GEOSCoordSeq_getSize(s->seq, &size);
599     if (size < 1)
600     {
601         PyErr_SetString(PyExc_ValueError, "Geometry can not be created from a zero length sequence");
602         return NULL;
603     }
604    
605     switch (typeid)
606     {
607         case GEOS_POINT:
608