source: trunk/php/geos.c

Last change on this file was 4109, checked in by strk, 9 months ago

Add a GEOSGeom_setPrecision funciton in C-API and PHP

Also fixes a bug in GeometryEditor? that failed to update
GeometryFactory? for empty polygons (#749)

File size: 74.1 KB
Line 
1/***********************************************************************
2 *
3 *    GEOS - Geometry Engine Open Source
4 *    http://trac.osgeo.org/geos
5 *
6 *    Copyright (C) 2010 Sandro Santilli <strk@keybit.net>
7 *
8 *    This library is free software; you can redistribute it and/or
9 *    modify it under the terms of the GNU Lesser General Public
10 *    License as published by the Free Software Foundation; either
11 *    version 2.1 of the License, or (at your option) any later version.
12 *
13 *    This library is distributed in the hope that it will be useful,
14 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 *    Lesser General Public License for more details.
17 *
18 *    You should have received a copy of the GNU General Public License
19 *    along with this program; if not, write to the Free Software
20 *    Foundation, Inc., 51 Franklin St, Fifth Floor,
21 *    Boston, MA  02110-1301  USA
22 *
23 ***********************************************************************/
24
25/* PHP stuff */
26#include "php.h"
27#include "ext/standard/info.h" /* for php_info_... */
28#include "Zend/zend_exceptions.h" /* for zend_throw_exception_object */
29
30/* GEOS stuff */
31#include "geos_c.h"
32
33/* Own stuff */
34#include "php_geos.h"
35
36PHP_MINIT_FUNCTION(geos);
37PHP_MSHUTDOWN_FUNCTION(geos);
38PHP_RINIT_FUNCTION(geos);
39PHP_RSHUTDOWN_FUNCTION(geos);
40PHP_MINFO_FUNCTION(geos);
41PHP_FUNCTION(GEOSVersion);
42PHP_FUNCTION(GEOSPolygonize);
43PHP_FUNCTION(GEOSLineMerge);
44PHP_FUNCTION(GEOSSharedPaths);
45PHP_FUNCTION(GEOSRelateMatch);
46
47#if PHP_VERSION_ID < 50399
48#define zend_function_entry function_entry
49#endif
50
51static zend_function_entry geos_functions[] = {
52    PHP_FE(GEOSVersion, NULL)
53    PHP_FE(GEOSPolygonize, NULL)
54    PHP_FE(GEOSLineMerge, NULL)
55    PHP_FE(GEOSSharedPaths, NULL)
56    PHP_FE(GEOSRelateMatch, NULL)
57    {NULL, NULL, NULL}
58};
59
60zend_module_entry geos_module_entry = {
61    STANDARD_MODULE_HEADER,
62    PHP_GEOS_EXTNAME,
63    geos_functions,
64    PHP_MINIT(geos),              /* module init function */
65    PHP_MSHUTDOWN(geos),          /* module shutdown function */
66    PHP_RINIT(geos),              /* request init function */
67    PHP_RSHUTDOWN(geos),          /* request shutdown function */
68    PHP_MINFO(geos),              /* module info function */
69    PHP_GEOS_VERSION,
70    STANDARD_MODULE_PROPERTIES
71};
72
73#ifdef COMPILE_DL_GEOS
74ZEND_GET_MODULE(geos)
75#endif
76
77/* -- Utility functions ---------------------- */
78
79static void noticeHandler(const char *fmt, ...)
80{
81    TSRMLS_FETCH();
82    char message[256];
83    va_list args;
84    va_start(args, fmt);
85    vsnprintf(message, sizeof(message) - 1, fmt, args);
86    va_end(args);
87
88    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s", message);
89}
90
91static void errorHandler(const char *fmt, ...)
92{
93    TSRMLS_FETCH();
94    char message[256];
95    va_list args;
96    va_start(args, fmt);
97    vsnprintf(message, sizeof(message) - 1, fmt, args);
98    va_end(args);
99
100    /* TODO: use a GEOSException ? */
101    zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C),
102        1 TSRMLS_CC, "%s", message); 
103
104}
105
106typedef struct Proxy_t {
107    zend_object std;
108    void* relay;
109} Proxy;
110
111static void 
112setRelay(zval* val, void* obj) {
113    TSRMLS_FETCH();
114    Proxy* proxy = (Proxy*)zend_object_store_get_object(val TSRMLS_CC);
115    proxy->relay = obj;
116}
117
118static inline void *
119getRelay(zval* val, zend_class_entry* ce) {
120    TSRMLS_FETCH();
121    Proxy *proxy =  (Proxy*)zend_object_store_get_object(val TSRMLS_CC);
122    if ( proxy->std.ce != ce ) {
123        php_error_docref(NULL TSRMLS_CC, E_ERROR,
124            "Relay object is not an %s", ce->name);
125    }
126    if ( ! proxy->relay ) {
127        php_error_docref(NULL TSRMLS_CC, E_ERROR,
128            "Relay object for object of type %s is not set", ce->name);
129    }
130    return proxy->relay;
131}
132
133static long getZvalAsLong(zval* val)
134{
135    long ret;
136    zval tmp;
137
138    tmp = *val;
139    zval_copy_ctor(&tmp);
140    convert_to_long(&tmp);
141    ret = Z_LVAL(tmp);
142    zval_dtor(&tmp);
143    return ret;
144}
145
146static long getZvalAsDouble(zval* val)
147{
148    double ret;
149    zval tmp;
150
151    tmp = *val;
152    zval_copy_ctor(&tmp);
153    convert_to_double(&tmp);
154    ret = Z_DVAL(tmp);
155    zval_dtor(&tmp);
156    return ret;
157}
158
159static zend_object_value
160Gen_create_obj (zend_class_entry *type,
161    zend_objects_free_object_storage_t st, zend_object_handlers* handlers)
162{
163    TSRMLS_FETCH();
164    zend_object_value retval;
165
166    Proxy *obj = (Proxy *)emalloc(sizeof(Proxy));
167    memset(obj, 0, sizeof(Proxy));
168    obj->std.ce = type;
169
170    ALLOC_HASHTABLE(obj->std.properties);
171    zend_hash_init(obj->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
172#if PHP_VERSION_ID < 50399
173    zend_hash_copy(obj->std.properties, &type->default_properties,
174        (copy_ctor_func_t)zval_add_ref, NULL, sizeof(zval *));
175#else
176    object_properties_init(&(obj->std), type);
177#endif
178
179    retval.handle = zend_objects_store_put(obj, NULL, st, NULL TSRMLS_CC);
180    retval.handlers = handlers;
181
182    return retval;
183}
184
185
186/* -- class GEOSGeometry -------------------- */
187
188PHP_METHOD(Geometry, __construct);
189PHP_METHOD(Geometry, __toString);
190PHP_METHOD(Geometry, project);
191PHP_METHOD(Geometry, interpolate);
192PHP_METHOD(Geometry, buffer);
193PHP_METHOD(Geometry, offsetCurve);
194PHP_METHOD(Geometry, envelope);
195PHP_METHOD(Geometry, intersection);
196PHP_METHOD(Geometry, convexHull);
197PHP_METHOD(Geometry, difference);
198PHP_METHOD(Geometry, symDifference);
199PHP_METHOD(Geometry, boundary);
200PHP_METHOD(Geometry, union); /* also does union cascaded */
201PHP_METHOD(Geometry, pointOnSurface); 
202PHP_METHOD(Geometry, centroid); 
203PHP_METHOD(Geometry, relate); 
204PHP_METHOD(Geometry, relateBoundaryNodeRule); 
205PHP_METHOD(Geometry, simplify); /* also does topology-preserving */
206PHP_METHOD(Geometry, normalize);
207PHP_METHOD(Geometry, setPrecision);
208PHP_METHOD(Geometry, getPrecision);
209PHP_METHOD(Geometry, extractUniquePoints); 
210PHP_METHOD(Geometry, disjoint);
211PHP_METHOD(Geometry, touches);
212PHP_METHOD(Geometry, intersects);
213PHP_METHOD(Geometry, crosses);
214PHP_METHOD(Geometry, within);
215PHP_METHOD(Geometry, contains);
216PHP_METHOD(Geometry, overlaps);
217PHP_METHOD(Geometry, covers);
218PHP_METHOD(Geometry, coveredBy);
219PHP_METHOD(Geometry, equals);
220PHP_METHOD(Geometry, equalsExact);
221PHP_METHOD(Geometry, isEmpty);
222PHP_METHOD(Geometry, checkValidity);
223PHP_METHOD(Geometry, isSimple);
224PHP_METHOD(Geometry, isRing);
225PHP_METHOD(Geometry, hasZ);
226PHP_METHOD(Geometry, isClosed);
227PHP_METHOD(Geometry, typeName);
228PHP_METHOD(Geometry, typeId);
229PHP_METHOD(Geometry, getSRID);
230PHP_METHOD(Geometry, setSRID);
231PHP_METHOD(Geometry, numGeometries);
232PHP_METHOD(Geometry, geometryN);
233PHP_METHOD(Geometry, numInteriorRings);
234PHP_METHOD(Geometry, numPoints);
235PHP_METHOD(Geometry, getX);
236PHP_METHOD(Geometry, getY);
237PHP_METHOD(Geometry, interiorRingN);
238PHP_METHOD(Geometry, exteriorRing);
239PHP_METHOD(Geometry, numCoordinates);
240PHP_METHOD(Geometry, dimension);
241PHP_METHOD(Geometry, coordinateDimension);
242PHP_METHOD(Geometry, pointN);
243PHP_METHOD(Geometry, startPoint);
244PHP_METHOD(Geometry, endPoint);
245PHP_METHOD(Geometry, area);
246PHP_METHOD(Geometry, length);
247PHP_METHOD(Geometry, distance);
248PHP_METHOD(Geometry, hausdorffDistance);
249PHP_METHOD(Geometry, snapTo);
250PHP_METHOD(Geometry, node);
251PHP_METHOD(Geometry, delaunayTriangulation);
252PHP_METHOD(Geometry, voronoiDiagram);
253PHP_METHOD(Geometry, clipByRect);
254
255static zend_function_entry Geometry_methods[] = {
256    PHP_ME(Geometry, __construct, NULL, 0)
257    PHP_ME(Geometry, __toString, NULL, 0)
258    PHP_ME(Geometry, project, NULL, 0)
259    PHP_ME(Geometry, interpolate, NULL, 0)
260    PHP_ME(Geometry, buffer, NULL, 0)
261    PHP_ME(Geometry, offsetCurve, NULL, 0)
262    PHP_ME(Geometry, envelope, NULL, 0)
263    PHP_ME(Geometry, intersection, NULL, 0)
264    PHP_ME(Geometry, convexHull, NULL, 0)
265    PHP_ME(Geometry, difference, NULL, 0)
266    PHP_ME(Geometry, symDifference, NULL, 0)
267    PHP_ME(Geometry, boundary, NULL, 0)
268    PHP_ME(Geometry, union, NULL, 0)
269    PHP_ME(Geometry, pointOnSurface, NULL, 0)
270    PHP_ME(Geometry, centroid, NULL, 0)
271    PHP_ME(Geometry, relate, NULL, 0)
272    PHP_ME(Geometry, relateBoundaryNodeRule, NULL, 0)
273    PHP_ME(Geometry, simplify, NULL, 0)
274    PHP_ME(Geometry, normalize, NULL, 0)
275    PHP_ME(Geometry, setPrecision, NULL, 0)
276    PHP_ME(Geometry, getPrecision, NULL, 0)
277    PHP_ME(Geometry, extractUniquePoints, NULL, 0)
278    PHP_ME(Geometry, disjoint, NULL, 0)
279    PHP_ME(Geometry, touches, NULL, 0)
280    PHP_ME(Geometry, intersects, NULL, 0)
281    PHP_ME(Geometry, crosses, NULL, 0)
282    PHP_ME(Geometry, within, NULL, 0)
283    PHP_ME(Geometry, contains, NULL, 0)
284    PHP_ME(Geometry, overlaps, NULL, 0)
285    PHP_ME(Geometry, covers, NULL, 0)
286    PHP_ME(Geometry, coveredBy, NULL, 0)
287    PHP_ME(Geometry, equals, NULL, 0)
288    PHP_ME(Geometry, equalsExact, NULL, 0)
289    PHP_ME(Geometry, isEmpty, NULL, 0)
290    PHP_ME(Geometry, checkValidity, NULL, 0)
291    PHP_ME(Geometry, isSimple, NULL, 0)
292    PHP_ME(Geometry, isRing, NULL, 0)
293    PHP_ME(Geometry, hasZ, NULL, 0)
294    PHP_ME(Geometry, isClosed, NULL, 0)
295    PHP_ME(Geometry, typeName, NULL, 0)
296    PHP_ME(Geometry, typeId, NULL, 0)
297    PHP_ME(Geometry, getSRID, NULL, 0)
298    PHP_ME(Geometry, setSRID, NULL, 0)
299    PHP_ME(Geometry, numGeometries, NULL, 0)
300    PHP_ME(Geometry, geometryN, NULL, 0)
301    PHP_ME(Geometry, numInteriorRings, NULL, 0)
302    PHP_ME(Geometry, numPoints, NULL, 0)
303    PHP_ME(Geometry, getX, NULL, 0)
304    PHP_ME(Geometry, getY, NULL, 0)
305    PHP_ME(Geometry, interiorRingN, NULL, 0)
306    PHP_ME(Geometry, exteriorRing, NULL, 0)
307    PHP_ME(Geometry, numCoordinates, NULL, 0)
308    PHP_ME(Geometry, dimension, NULL, 0)
309    PHP_ME(Geometry, coordinateDimension, NULL, 0)
310    PHP_ME(Geometry, pointN, NULL, 0)
311    PHP_ME(Geometry, startPoint, NULL, 0)
312    PHP_ME(Geometry, endPoint, NULL, 0)
313    PHP_ME(Geometry, area, NULL, 0)
314    PHP_ME(Geometry, length, NULL, 0)
315    PHP_ME(Geometry, distance, NULL, 0)
316    PHP_ME(Geometry, hausdorffDistance, NULL, 0)
317    PHP_ME(Geometry, snapTo, NULL, 0)
318    PHP_ME(Geometry, node, NULL, 0)
319    PHP_ME(Geometry, delaunayTriangulation, NULL, 0)
320    PHP_ME(Geometry, voronoiDiagram, NULL, 0)
321    PHP_ME(Geometry, clipByRect, NULL, 0)
322    {NULL, NULL, NULL}
323};
324
325static zend_class_entry *Geometry_ce_ptr;
326
327static zend_object_handlers Geometry_object_handlers;
328
329/* Geometry serializer */
330
331static GEOSWKBWriter* Geometry_serializer = 0;
332
333static GEOSWKBWriter* getGeometrySerializer()
334{
335    if ( ! Geometry_serializer ) {
336        Geometry_serializer = GEOSWKBWriter_create();
337        GEOSWKBWriter_setIncludeSRID(Geometry_serializer, 1);
338        GEOSWKBWriter_setOutputDimension(Geometry_serializer, 3);
339    }
340    return Geometry_serializer;
341}
342
343static void delGeometrySerializer()
344{
345    if ( Geometry_serializer ) {
346        GEOSWKBWriter_destroy(Geometry_serializer);
347    }
348}
349
350/* Geometry deserializer */
351
352static GEOSWKBReader* Geometry_deserializer = 0;
353
354static GEOSWKBReader* getGeometryDeserializer()
355{
356    if ( ! Geometry_deserializer ) {
357        Geometry_deserializer = GEOSWKBReader_create();
358    }
359    return Geometry_deserializer;
360}
361
362static void delGeometryDeserializer()
363{
364    if ( Geometry_deserializer ) {
365        GEOSWKBReader_destroy(Geometry_deserializer);
366    }
367}
368
369/* Serializer function for GEOSGeometry */
370
371static int
372Geometry_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len,
373        zend_serialize_data *data TSRMLS_DC)
374{
375    GEOSWKBWriter *serializer;
376    GEOSGeometry *geom;
377    char* ret;
378    size_t retsize;
379
380
381    serializer = getGeometrySerializer();
382    geom = (GEOSGeometry*)getRelay(object, Geometry_ce_ptr);
383
384    /* NOTE: we might be fine using binary here */
385    ret = (char*)GEOSWKBWriter_writeHEX(serializer, geom, &retsize);
386    /* we'll probably get an exception if ret is null */
387    if ( ! ret ) return FAILURE;
388
389    *buffer = (unsigned char*)estrndup(ret, retsize);
390    GEOSFree(ret);
391
392    *buf_len = retsize;
393
394    return SUCCESS; 
395}
396
397static int
398Geometry_deserialize(zval **object, zend_class_entry *ce, const unsigned char *buf,
399        zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC)
400{
401    GEOSWKBReader* deserializer;
402    GEOSGeometry* geom;
403
404    deserializer = getGeometryDeserializer();
405    geom = GEOSWKBReader_readHEX(deserializer, buf, buf_len);
406
407    /* TODO: check zend_class_entry being what we expect! */
408    if ( ce != Geometry_ce_ptr ) {
409        php_error_docref(NULL TSRMLS_CC, E_ERROR,
410                "Geometry_deserialize called with unexpected zend_class_entry");
411        return FAILURE;
412    }
413    object_init_ex(*object, ce);
414    setRelay(*object, geom);
415
416    return SUCCESS;
417}
418
419/*
420 * Push components of the given geometry
421 * to the given array zval.
422 * Components geometries are cloned.
423 * NOTE: collection components are not descended into
424 */
425static void
426dumpGeometry(GEOSGeometry* g, zval* array)
427{
428    TSRMLS_FETCH();
429    int ngeoms, i;
430
431    /*
432    MAKE_STD_ZVAL(array);
433    array_init(array);
434    */
435
436    ngeoms = GEOSGetNumGeometries(g);
437    for (i=0; i<ngeoms; ++i)
438    {
439        zval *tmp;
440        GEOSGeometry* cc;
441        const GEOSGeometry* c = GEOSGetGeometryN(g, i);
442        if ( ! c ) continue; /* should get an exception */
443        /* we _need_ to clone as this one is owned by 'g' */
444        cc = GEOSGeom_clone(c);
445        if ( ! cc ) continue; /* should get an exception */
446
447        MAKE_STD_ZVAL(tmp);
448        object_init_ex(tmp, Geometry_ce_ptr);
449        setRelay(tmp, cc);
450        add_next_index_zval(array, tmp); 
451    }
452}
453
454
455static void
456Geometry_dtor (void *object TSRMLS_DC)
457{
458    Proxy *obj = (Proxy *)object;
459    GEOSGeom_destroy((GEOSGeometry*)obj->relay);
460
461    zend_hash_destroy(obj->std.properties);
462    FREE_HASHTABLE(obj->std.properties);
463
464    efree(obj);
465}
466
467static zend_object_value
468Geometry_create_obj (zend_class_entry *type TSRMLS_DC)
469{
470    return Gen_create_obj(type, Geometry_dtor, &Geometry_object_handlers);
471}
472
473
474PHP_METHOD(Geometry, __construct)
475{
476    php_error_docref(NULL TSRMLS_CC, E_ERROR,
477            "GEOSGeometry can't be constructed using new, check WKTReader");
478
479}
480
481PHP_METHOD(Geometry, __toString)
482{
483    GEOSGeometry *geom;
484    GEOSWKTWriter *writer;
485    char *wkt;
486    char *ret;
487
488    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
489    writer = GEOSWKTWriter_create();
490    /* NOTE: if we get an exception before reaching
491     *       GEOSWKTWriter_destory below we'll be leaking memory.
492     *       One fix could be storing the object in a refcounted
493     *       zval.
494     */
495    GEOSWKTWriter_setTrim(writer, 1);
496
497    wkt = GEOSWKTWriter_write(writer, geom);
498    /* we'll probably get an exception if wkt is null */
499    if ( ! wkt ) RETURN_NULL();
500
501    GEOSWKTWriter_destroy(writer);
502   
503
504    ret = estrdup(wkt);
505    GEOSFree(wkt);
506
507    RETURN_STRING(ret, 0);
508}
509
510PHP_METHOD(Geometry, project)
511{
512    GEOSGeometry *this;
513    GEOSGeometry *other;
514    zval *zobj;
515    zend_bool normalized = 0;
516    double ret;
517
518    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
519
520    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|b", &zobj,
521            &normalized) == FAILURE) {
522        RETURN_NULL();
523    }
524    other = getRelay(zobj, Geometry_ce_ptr);
525
526    if ( normalized ) {
527        ret = GEOSProjectNormalized(this, other);
528    } else {
529        ret = GEOSProject(this, other);
530    }
531    if ( ret < 0 ) RETURN_NULL(); /* should get an exception first */
532
533    RETURN_DOUBLE(ret);
534}
535
536PHP_METHOD(Geometry, interpolate)
537{
538    GEOSGeometry *this;
539    double dist;
540    GEOSGeometry *ret;
541    zend_bool normalized = 0;
542
543    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
544
545    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|b",
546            &dist, &normalized) == FAILURE) {
547        RETURN_NULL();
548    }
549
550    if ( normalized ) {
551        ret = GEOSInterpolateNormalized(this, dist);
552    } else {
553        ret = GEOSInterpolate(this, dist);
554    }
555    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
556
557    /* return_value is a zval */
558    object_init_ex(return_value, Geometry_ce_ptr);
559    setRelay(return_value, ret);
560}
561
562/**
563 * GEOSGeometry::buffer(dist, [<styleArray>])
564 *
565 * styleArray keys supported:
566 *  'quad_segs'
567 *       Type: int
568 *       Number of segments used to approximate
569 *       a quarter circle (defaults to 8).
570 *  'endcap'
571 *       Type: long
572 *       Endcap style (defaults to GEOSBUF_CAP_ROUND)
573 *  'join'
574 *       Type: long
575 *       Join style (defaults to GEOSBUF_JOIN_ROUND)
576 *  'mitre_limit'
577 *       Type: double
578 *       mitre ratio limit (only affects joins with GEOSBUF_JOIN_MITRE style)
579 *       'miter_limit' is also accepted as a synonym for 'mitre_limit'.
580 *  'single_sided'
581 *       Type: bool
582 *       If true buffer lines only on one side, so that the input line
583 *       will be a portion of the boundary of the returned polygon.
584 *       Only applies to lineal input. Defaults to false.
585 */
586PHP_METHOD(Geometry, buffer)
587{
588    GEOSGeometry *this;
589    double dist;
590    GEOSGeometry *ret;
591    GEOSBufferParams *params;
592    static const double default_mitreLimit = 5.0;
593    static const int default_endCapStyle = GEOSBUF_CAP_ROUND;
594    static const int default_joinStyle = GEOSBUF_JOIN_ROUND;
595    static const int default_quadSegs = 8;
596    long int quadSegs = default_quadSegs;
597    long int endCapStyle = default_endCapStyle;
598    long int joinStyle = default_joinStyle;
599    double mitreLimit = default_mitreLimit;
600    long singleSided = 0;
601    zval *style_val = NULL;
602    zval **data;
603    HashTable *style;
604    char *key;
605    ulong index;
606
607    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
608
609    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|a",
610            &dist, &style_val) == FAILURE) {
611        RETURN_NULL();
612    }
613
614    params = GEOSBufferParams_create();
615
616    if ( style_val )
617    {
618        style = HASH_OF(style_val);
619        while(zend_hash_get_current_key(style, &key, &index, 0)
620              == HASH_KEY_IS_STRING)
621        {
622            if(!strcmp(key, "quad_segs"))
623            {
624                zend_hash_get_current_data(style, (void**)&data);
625                quadSegs = getZvalAsLong(*data);
626                GEOSBufferParams_setQuadrantSegments(params, quadSegs);
627            }
628            else if(!strcmp(key, "endcap"))
629            {
630                zend_hash_get_current_data(style, (void**)&data);
631                endCapStyle = getZvalAsLong(*data);
632                GEOSBufferParams_setEndCapStyle(params, endCapStyle);
633            }
634            else if(!strcmp(key, "join"))
635            {
636                zend_hash_get_current_data(style, (void**)&data);
637                joinStyle = getZvalAsLong(*data);
638                GEOSBufferParams_setJoinStyle(params, joinStyle);
639            }
640            else if(!strcmp(key, "mitre_limit"))
641            {
642                zend_hash_get_current_data(style, (void**)&data);
643                mitreLimit = getZvalAsDouble(*data);
644                GEOSBufferParams_setMitreLimit(params, mitreLimit);
645            }
646            else if(!strcmp(key, "single_sided"))
647            {
648                zend_hash_get_current_data(style, (void**)&data);
649                singleSided = getZvalAsLong(*data);
650                GEOSBufferParams_setSingleSided(params, singleSided);
651            }
652
653            zend_hash_move_forward(style);
654        }
655    }
656
657    ret = GEOSBufferWithParams(this, params, dist);
658    GEOSBufferParams_destroy(params);
659    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
660
661    /* return_value is a zval */
662    object_init_ex(return_value, Geometry_ce_ptr);
663    setRelay(return_value, ret);
664}
665
666/**
667 * GEOSGeometry::offsetCurve(dist, [<styleArray>])
668 *
669 * styleArray keys supported:
670 *  'quad_segs'
671 *       Type: int
672 *       Number of segments used to approximate
673 *       a quarter circle (defaults to 8).
674 *  'join'
675 *       Type: long
676 *       Join style (defaults to GEOSBUF_JOIN_ROUND)
677 *  'mitre_limit'
678 *       Type: double
679 *       mitre ratio limit (only affects joins with GEOSBUF_JOIN_MITRE style)
680 *       'miter_limit' is also accepted as a synonym for 'mitre_limit'.
681 */
682PHP_METHOD(Geometry, offsetCurve)
683{
684    GEOSGeometry *this;
685    double dist;
686    GEOSGeometry *ret;
687    static const double default_mitreLimit = 5.0;
688    static const int default_joinStyle = GEOSBUF_JOIN_ROUND;
689    static const int default_quadSegs = 8;
690    long int quadSegs = default_quadSegs;
691    long int joinStyle = default_joinStyle;
692    double mitreLimit = default_mitreLimit;
693    zval *style_val = NULL;
694    zval **data;
695    HashTable *style;
696    char *key;
697    ulong index;
698
699    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
700
701    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|a",
702            &dist, &style_val) == FAILURE) {
703        RETURN_NULL();
704    }
705
706    if ( style_val )
707    {
708        style = HASH_OF(style_val);
709        while(zend_hash_get_current_key(style, &key, &index, 0)
710              == HASH_KEY_IS_STRING)
711        {
712            if(!strcmp(key, "quad_segs"))
713            {
714                zend_hash_get_current_data(style, (void**)&data);
715                quadSegs = getZvalAsLong(*data);
716            }
717            else if(!strcmp(key, "join"))
718            {
719                zend_hash_get_current_data(style, (void**)&data);
720                joinStyle = getZvalAsLong(*data);
721            }
722            else if(!strcmp(key, "mitre_limit"))
723            {
724                zend_hash_get_current_data(style, (void**)&data);
725                mitreLimit = getZvalAsDouble(*data);
726            }
727
728            zend_hash_move_forward(style);
729        }
730    }
731
732    ret = GEOSOffsetCurve(this, dist, quadSegs, joinStyle, mitreLimit);
733    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
734
735    /* return_value is a zval */
736    object_init_ex(return_value, Geometry_ce_ptr);
737    setRelay(return_value, ret);
738}
739
740PHP_METHOD(Geometry, envelope)
741{
742    GEOSGeometry *this;
743    GEOSGeometry *ret;
744
745    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
746
747    ret = GEOSEnvelope(this);
748    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
749
750    /* return_value is a zval */
751    object_init_ex(return_value, Geometry_ce_ptr);
752    setRelay(return_value, ret);
753}
754
755PHP_METHOD(Geometry, intersection)
756{
757    GEOSGeometry *this;
758    GEOSGeometry *other;
759    GEOSGeometry *ret;
760    zval *zobj;
761
762    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
763
764    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
765            == FAILURE) {
766        RETURN_NULL();
767    }
768    other = getRelay(zobj, Geometry_ce_ptr);
769
770    ret = GEOSIntersection(this, other);
771    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
772
773    /* return_value is a zval */
774    object_init_ex(return_value, Geometry_ce_ptr);
775    setRelay(return_value, ret);
776}
777
778/**
779 * GEOSGeometry GEOSGeometry::clipByRect(xmin,ymin,xmax,ymax)
780 */
781PHP_METHOD(Geometry, clipByRect)
782{
783    GEOSGeometry *this;
784    GEOSGeometry *ret;
785    double xmin,ymin,xmax,ymax;
786
787    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
788
789    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dddd",
790            &xmin, &ymin, &xmax, &ymax) == FAILURE) {
791        RETURN_NULL();
792    }
793
794    ret = GEOSClipByRect(this, xmin, ymin, xmax, ymax);
795    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
796
797    /* return_value is a zval */
798    object_init_ex(return_value, Geometry_ce_ptr);
799    setRelay(return_value, ret);
800}
801
802PHP_METHOD(Geometry, convexHull)
803{
804    GEOSGeometry *this;
805    GEOSGeometry *ret;
806
807    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
808
809    ret = GEOSConvexHull(this);
810    if ( ret == NULL ) RETURN_NULL(); /* should get an exception first */
811
812    /* return_value is a zval */
813    object_init_ex(return_value, Geometry_ce_ptr);
814    setRelay(return_value, ret);
815}
816
817PHP_METHOD(Geometry, difference)
818{
819    GEOSGeometry *this;
820    GEOSGeometry *other;
821    GEOSGeometry *ret;
822    zval *zobj;
823
824    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
825
826    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
827            == FAILURE) {
828        RETURN_NULL();
829    }
830    other = getRelay(zobj, Geometry_ce_ptr);
831
832    ret = GEOSDifference(this, other);
833    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
834
835    /* return_value is a zval */
836    object_init_ex(return_value, Geometry_ce_ptr);
837    setRelay(return_value, ret);
838}
839
840PHP_METHOD(Geometry, symDifference)
841{
842    GEOSGeometry *this;
843    GEOSGeometry *other;
844    GEOSGeometry *ret;
845    zval *zobj;
846
847    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
848
849    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
850            == FAILURE) {
851        RETURN_NULL();
852    }
853    other = getRelay(zobj, Geometry_ce_ptr);
854
855    ret = GEOSSymDifference(this, other);
856    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
857
858    /* return_value is a zval */
859    object_init_ex(return_value, Geometry_ce_ptr);
860    setRelay(return_value, ret);
861}
862
863PHP_METHOD(Geometry, boundary)
864{
865    GEOSGeometry *this;
866    GEOSGeometry *ret;
867
868    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
869
870    ret = GEOSBoundary(this);
871    if ( ret == NULL ) RETURN_NULL(); /* should get an exception first */
872
873    /* return_value is a zval */
874    object_init_ex(return_value, Geometry_ce_ptr);
875    setRelay(return_value, ret);
876}
877
878/**
879 * GEOSGeometry::union(otherGeom)
880 * GEOSGeometry::union()
881 */
882PHP_METHOD(Geometry, union)
883{
884    GEOSGeometry *this;
885    GEOSGeometry *other;
886    GEOSGeometry *ret;
887    zval *zobj = NULL;
888
889    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
890
891    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|o", &zobj)
892            == FAILURE) {
893        RETURN_NULL();
894    }
895
896    if ( zobj ) {
897        other = getRelay(zobj, Geometry_ce_ptr);
898        ret = GEOSUnion(this, other);
899    } else {
900        ret = GEOSUnaryUnion(this);
901    }
902
903    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
904
905    /* return_value is a zval */
906    object_init_ex(return_value, Geometry_ce_ptr);
907    setRelay(return_value, ret);
908}
909
910/**
911 * GEOSGeometry::pointOnSurface()
912 */
913PHP_METHOD(Geometry, pointOnSurface)
914{
915    GEOSGeometry *this;
916    GEOSGeometry *ret;
917
918    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
919
920    ret = GEOSPointOnSurface(this);
921    if ( ret == NULL ) RETURN_NULL(); /* should get an exception first */
922
923    /* return_value is a zval */
924    object_init_ex(return_value, Geometry_ce_ptr);
925    setRelay(return_value, ret);
926}
927
928/**
929 * GEOSGeometry::centroid()
930 */
931PHP_METHOD(Geometry, centroid)
932{
933    GEOSGeometry *this;
934    GEOSGeometry *ret;
935
936    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
937
938    ret = GEOSGetCentroid(this);
939    if ( ret == NULL ) RETURN_NULL(); /* should get an exception first */
940
941    /* return_value is a zval */
942    object_init_ex(return_value, Geometry_ce_ptr);
943    setRelay(return_value, ret);
944}
945
946/**
947 * GEOSGeometry::relate(otherGeom)
948 * GEOSGeometry::relate(otherGeom, pattern)
949 */
950PHP_METHOD(Geometry, relate)
951{
952    GEOSGeometry *this;
953    GEOSGeometry *other;
954    zval *zobj;
955    char* pat = NULL;
956    int patlen;
957    int retInt;
958    zend_bool retBool;
959    char* retStr;
960
961    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
962
963    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|s",
964        &zobj, &pat, &patlen) == FAILURE)
965    {
966        RETURN_NULL();
967    }
968
969    other = getRelay(zobj, Geometry_ce_ptr);
970
971    if ( ! pat ) {
972        /* we'll compute it */
973        pat = GEOSRelate(this, other);
974        if ( ! pat ) RETURN_NULL(); /* should get an exception first */
975        retStr = estrdup(pat);
976        GEOSFree(pat);
977        RETURN_STRING(retStr, 0);
978    } else {
979        retInt = GEOSRelatePattern(this, other, pat);
980        if ( retInt == 2 ) RETURN_NULL(); /* should get an exception first */
981        retBool = retInt;
982        RETURN_BOOL(retBool);
983    }
984
985}
986
987/**
988 * GEOSGeometry::relateBoundaryNodeRule(otherGeom, rule)
989 */
990PHP_METHOD(Geometry, relateBoundaryNodeRule)
991{
992    GEOSGeometry *this;
993    GEOSGeometry *other;
994    zval *zobj;
995    char* pat;
996    long int bnr = GEOSRELATE_BNR_OGC;
997    char* retStr;
998
999    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1000
1001    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ol",
1002        &zobj, &bnr) == FAILURE)
1003    {
1004        RETURN_NULL();
1005    }
1006
1007    other = getRelay(zobj, Geometry_ce_ptr);
1008
1009    /* we'll compute it */
1010    pat = GEOSRelateBoundaryNodeRule(this, other, bnr);
1011    if ( ! pat ) RETURN_NULL(); /* should get an exception first */
1012    retStr = estrdup(pat);
1013    GEOSFree(pat);
1014    RETURN_STRING(retStr, 0);
1015}
1016
1017/**
1018 * GEOSGeometry GEOSGeometry::simplify(tolerance)
1019 * GEOSGeometry GEOSGeometry::simplify(tolerance, preserveTopology)
1020 */
1021PHP_METHOD(Geometry, simplify)
1022{
1023    GEOSGeometry *this;
1024    double tolerance;
1025    zend_bool preserveTopology = 0;
1026    GEOSGeometry *ret;
1027
1028    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1029
1030    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|b",
1031            &tolerance, &preserveTopology) == FAILURE) {
1032        RETURN_NULL();
1033    }
1034
1035    if ( preserveTopology ) {
1036        ret = GEOSTopologyPreserveSimplify(this, tolerance);
1037    } else {
1038        ret = GEOSSimplify(this, tolerance);
1039    }
1040
1041    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1042
1043    /* return_value is a zval */
1044    object_init_ex(return_value, Geometry_ce_ptr);
1045    setRelay(return_value, ret);
1046}
1047
1048/**
1049 * GEOSGeometry GEOSGeometry::setPrecision(gridsize, [flags])
1050 */
1051PHP_METHOD(Geometry, setPrecision)
1052{
1053    GEOSGeometry *this;
1054    double gridSize;
1055    long int flags = 0;
1056    GEOSGeometry *ret;
1057
1058    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1059
1060    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|l",
1061            &gridSize, &flags) == FAILURE) {
1062        RETURN_NULL();
1063    }
1064
1065    ret = GEOSGeom_setPrecision(this, gridSize, flags);
1066
1067    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1068
1069    /* return_value is a zval */
1070    object_init_ex(return_value, Geometry_ce_ptr);
1071    setRelay(return_value, ret);
1072}
1073
1074/**
1075 * double GEOSGeometry::getPrecision()
1076 */
1077PHP_METHOD(Geometry, getPrecision)
1078{
1079    GEOSGeometry *geom;
1080    double prec;
1081
1082    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1083
1084    prec = GEOSGeom_getPrecision(geom);
1085    if ( prec < 0 ) RETURN_NULL(); /* should get an exception first */
1086
1087    RETURN_DOUBLE(prec);
1088}
1089
1090/**
1091 * GEOSGeometry GEOSGeometry::normalize()
1092 */
1093PHP_METHOD(Geometry, normalize)
1094{
1095    GEOSGeometry *this;
1096    GEOSGeometry *ret;
1097
1098    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1099
1100    ret = GEOSGeom_clone(this);
1101
1102    if ( ! ret ) RETURN_NULL();
1103
1104    GEOSNormalize(ret); /* exception should be gotten automatically */
1105
1106    /* return_value is a zval */
1107    object_init_ex(return_value, Geometry_ce_ptr);
1108    setRelay(return_value, ret);
1109}
1110
1111/**
1112 * GEOSGeometry GEOSGeometry::extractUniquePoints()
1113 */
1114PHP_METHOD(Geometry, extractUniquePoints)
1115{
1116    GEOSGeometry *this;
1117    GEOSGeometry *ret;
1118
1119    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1120
1121    ret = GEOSGeom_extractUniquePoints(this);
1122    if ( ret == NULL ) RETURN_NULL(); /* should get an exception first */
1123
1124    /* return_value is a zval */
1125    object_init_ex(return_value, Geometry_ce_ptr);
1126    setRelay(return_value, ret);
1127}
1128
1129/**
1130 * bool GEOSGeometry::disjoint(GEOSGeometry)
1131 */
1132PHP_METHOD(Geometry, disjoint)
1133{
1134    GEOSGeometry *this;
1135    GEOSGeometry *other;
1136    int ret;
1137    zend_bool retBool;
1138    zval *zobj;
1139
1140    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1141
1142    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1143            == FAILURE) {
1144        RETURN_NULL();
1145    }
1146    other = getRelay(zobj, Geometry_ce_ptr);
1147
1148    ret = GEOSDisjoint(this, other);
1149    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1150
1151    /* return_value is a zval */
1152    retBool = ret;
1153    RETURN_BOOL(retBool);
1154}
1155
1156/**
1157 * bool GEOSGeometry::touches(GEOSGeometry)
1158 */
1159PHP_METHOD(Geometry, touches)
1160{
1161    GEOSGeometry *this;
1162    GEOSGeometry *other;
1163    int ret;
1164    zend_bool retBool;
1165    zval *zobj;
1166
1167    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1168
1169    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1170            == FAILURE) {
1171        RETURN_NULL();
1172    }
1173    other = getRelay(zobj, Geometry_ce_ptr);
1174
1175    ret = GEOSTouches(this, other);
1176    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1177
1178    /* return_value is a zval */
1179    retBool = ret;
1180    RETURN_BOOL(retBool);
1181}
1182
1183/**
1184 * bool GEOSGeometry::intersects(GEOSGeometry)
1185 */
1186PHP_METHOD(Geometry, intersects)
1187{
1188    GEOSGeometry *this;
1189    GEOSGeometry *other;
1190    int ret;
1191    zend_bool retBool;
1192    zval *zobj;
1193
1194    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1195
1196    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1197            == FAILURE) {
1198        RETURN_NULL();
1199    }
1200    other = getRelay(zobj, Geometry_ce_ptr);
1201
1202    ret = GEOSIntersects(this, other);
1203    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1204
1205    /* return_value is a zval */
1206    retBool = ret;
1207    RETURN_BOOL(retBool);
1208}
1209
1210/**
1211 * bool GEOSGeometry::crosses(GEOSGeometry)
1212 */
1213PHP_METHOD(Geometry, crosses)
1214{
1215    GEOSGeometry *this;
1216    GEOSGeometry *other;
1217    int ret;
1218    zend_bool retBool;
1219    zval *zobj;
1220
1221    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1222
1223    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1224            == FAILURE) {
1225        RETURN_NULL();
1226    }
1227    other = getRelay(zobj, Geometry_ce_ptr);
1228
1229    ret = GEOSCrosses(this, other);
1230    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1231
1232    /* return_value is a zval */
1233    retBool = ret;
1234    RETURN_BOOL(retBool);
1235}
1236
1237/**
1238 * bool GEOSGeometry::within(GEOSGeometry)
1239 */
1240PHP_METHOD(Geometry, within)
1241{
1242    GEOSGeometry *this;
1243    GEOSGeometry *other;
1244    int ret;
1245    zend_bool retBool;
1246    zval *zobj;
1247
1248    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1249
1250    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1251            == FAILURE) {
1252        RETURN_NULL();
1253    }
1254    other = getRelay(zobj, Geometry_ce_ptr);
1255
1256    ret = GEOSWithin(this, other);
1257    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1258
1259    /* return_value is a zval */
1260    retBool = ret;
1261    RETURN_BOOL(retBool);
1262}
1263
1264/**
1265 * bool GEOSGeometry::contains(GEOSGeometry)
1266 */
1267PHP_METHOD(Geometry, contains)
1268{
1269    GEOSGeometry *this;
1270    GEOSGeometry *other;
1271    int ret;
1272    zend_bool retBool;
1273    zval *zobj;
1274
1275    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1276
1277    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1278            == FAILURE) {
1279        RETURN_NULL();
1280    }
1281    other = getRelay(zobj, Geometry_ce_ptr);
1282
1283    ret = GEOSContains(this, other);
1284    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1285
1286    /* return_value is a zval */
1287    retBool = ret;
1288    RETURN_BOOL(retBool);
1289}
1290
1291/**
1292 * bool GEOSGeometry::overlaps(GEOSGeometry)
1293 */
1294PHP_METHOD(Geometry, overlaps)
1295{
1296    GEOSGeometry *this;
1297    GEOSGeometry *other;
1298    int ret;
1299    zend_bool retBool;
1300    zval *zobj;
1301
1302    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1303
1304    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1305            == FAILURE) {
1306        RETURN_NULL();
1307    }
1308    other = getRelay(zobj, Geometry_ce_ptr);
1309
1310    ret = GEOSOverlaps(this, other);
1311    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1312
1313    /* return_value is a zval */
1314    retBool = ret;
1315    RETURN_BOOL(retBool);
1316}
1317
1318/**
1319 * bool GEOSGeometry::covers(GEOSGeometry)
1320 */
1321PHP_METHOD(Geometry, covers)
1322{
1323    GEOSGeometry *this;
1324    GEOSGeometry *other;
1325    int ret;
1326    zend_bool retBool;
1327    zval *zobj;
1328
1329    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1330
1331    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1332            == FAILURE) {
1333        RETURN_NULL();
1334    }
1335    other = getRelay(zobj, Geometry_ce_ptr);
1336
1337    ret = GEOSCovers(this, other);
1338    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1339
1340    /* return_value is a zval */
1341    retBool = ret;
1342    RETURN_BOOL(retBool);
1343}
1344
1345/**
1346 * bool GEOSGeometry::coveredBy(GEOSGeometry)
1347 */
1348PHP_METHOD(Geometry, coveredBy)
1349{
1350    GEOSGeometry *this;
1351    GEOSGeometry *other;
1352    int ret;
1353    zend_bool retBool;
1354    zval *zobj;
1355
1356    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1357
1358    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1359            == FAILURE) {
1360        RETURN_NULL();
1361    }
1362    other = getRelay(zobj, Geometry_ce_ptr);
1363
1364    ret = GEOSCoveredBy(this, other);
1365    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1366
1367    /* return_value is a zval */
1368    retBool = ret;
1369    RETURN_BOOL(retBool);
1370}
1371
1372/**
1373 * bool GEOSGeometry::equals(GEOSGeometry)
1374 */
1375PHP_METHOD(Geometry, equals)
1376{
1377    GEOSGeometry *this;
1378    GEOSGeometry *other;
1379    int ret;
1380    zend_bool retBool;
1381    zval *zobj;
1382
1383    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1384
1385    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o",
1386        &zobj) == FAILURE) {
1387        RETURN_NULL();
1388    }
1389    other = getRelay(zobj, Geometry_ce_ptr);
1390
1391    ret = GEOSEquals(this, other);
1392    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1393
1394    /* return_value is a zval */
1395    retBool = ret;
1396    RETURN_BOOL(retBool);
1397}
1398
1399/**
1400 * bool GEOSGeometry::equalsExact(GEOSGeometry)
1401 * bool GEOSGeometry::equalsExact(GEOSGeometry, double tolerance)
1402 */
1403PHP_METHOD(Geometry, equalsExact)
1404{
1405    GEOSGeometry *this;
1406    GEOSGeometry *other;
1407    int ret;
1408    double tolerance = 0;
1409    zend_bool retBool;
1410    zval *zobj;
1411
1412    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1413
1414    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|d",
1415        &zobj, &tolerance) == FAILURE) {
1416        RETURN_NULL();
1417    }
1418    other = getRelay(zobj, Geometry_ce_ptr);
1419
1420    ret = GEOSEqualsExact(this, other, tolerance);
1421    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1422
1423    /* return_value is a zval */
1424    retBool = ret;
1425    RETURN_BOOL(retBool);
1426}
1427
1428/**
1429 * bool GEOSGeometry::isEmpty()
1430 */
1431PHP_METHOD(Geometry, isEmpty)
1432{
1433    GEOSGeometry *this;
1434    int ret;
1435    zend_bool retBool;
1436
1437    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1438
1439    ret = GEOSisEmpty(this);
1440    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1441
1442    /* return_value is a zval */
1443    retBool = ret;
1444    RETURN_BOOL(retBool);
1445}
1446
1447/**
1448 * array GEOSGeometry::checkValidity()
1449 */
1450PHP_METHOD(Geometry, checkValidity)
1451{
1452    GEOSGeometry *this;
1453    GEOSGeometry *location = NULL;
1454    int ret;
1455    char *reason = NULL;
1456    zend_bool retBool;
1457    char *reasonVal = NULL;
1458    zval *locationVal = NULL;
1459    long int flags = 0;
1460
1461    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1462
1463    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l",
1464        &flags) == FAILURE) {
1465        RETURN_NULL();
1466    }
1467
1468    ret = GEOSisValidDetail(this, flags, &reason, &location);
1469    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1470
1471    if ( reason ) {
1472        reasonVal = estrdup(reason);
1473        GEOSFree(reason);
1474    }
1475
1476    if ( location ) {
1477        MAKE_STD_ZVAL(locationVal);
1478        object_init_ex(locationVal, Geometry_ce_ptr);
1479        setRelay(locationVal, location);
1480    }
1481
1482    retBool = ret;
1483
1484    /* return value is an array */
1485    array_init(return_value);
1486    add_assoc_bool(return_value, "valid", retBool); 
1487    if ( reasonVal ) add_assoc_string(return_value, "reason", reasonVal, 0); 
1488    if ( locationVal ) add_assoc_zval(return_value, "location", locationVal); 
1489
1490}
1491
1492/**
1493 * bool GEOSGeometry::isSimple()
1494 */
1495PHP_METHOD(Geometry, isSimple)
1496{
1497    GEOSGeometry *this;
1498    int ret;
1499    zend_bool retBool;
1500
1501    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1502
1503    ret = GEOSisSimple(this);
1504    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1505
1506    /* return_value is a zval */
1507    retBool = ret;
1508    RETURN_BOOL(retBool);
1509}
1510
1511/**
1512 * bool GEOSGeometry::isRing()
1513 */
1514PHP_METHOD(Geometry, isRing)
1515{
1516    GEOSGeometry *this;
1517    int ret;
1518    zend_bool retBool;
1519
1520    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1521
1522    ret = GEOSisRing(this);
1523    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1524
1525    /* return_value is a zval */
1526    retBool = ret;
1527    RETURN_BOOL(retBool);
1528}
1529
1530/**
1531 * bool GEOSGeometry::hasZ()
1532 */
1533PHP_METHOD(Geometry, hasZ)
1534{
1535    GEOSGeometry *this;
1536    int ret;
1537    zend_bool retBool;
1538
1539    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1540
1541    ret = GEOSHasZ(this);
1542    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1543
1544    /* return_value is a zval */
1545    retBool = ret;
1546    RETURN_BOOL(retBool);
1547}
1548
1549/**
1550 * bool GEOSGeometry::isClosed()
1551 */
1552PHP_METHOD(Geometry, isClosed)
1553{
1554    GEOSGeometry *this;
1555    int ret;
1556    zend_bool retBool;
1557
1558    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1559
1560    ret = GEOSisClosed(this);
1561    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1562
1563    /* return_value is a zval */
1564    retBool = ret;
1565    RETURN_BOOL(retBool);
1566}
1567
1568/**
1569 * string GEOSGeometry::typeName()
1570 */
1571PHP_METHOD(Geometry, typeName)
1572{
1573    GEOSGeometry *this;
1574    char *typ;
1575    char *typVal;
1576
1577    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1578
1579    /* TODO: define constant strings instead... */
1580
1581    typ = GEOSGeomType(this);
1582    if ( ! typ ) RETURN_NULL(); /* should get an exception first */
1583
1584    typVal = estrdup(typ);
1585    GEOSFree(typ);
1586
1587    RETURN_STRING(typVal, 0);
1588}
1589
1590/**
1591 * long GEOSGeometry::typeId()
1592 */
1593PHP_METHOD(Geometry, typeId)
1594{
1595    GEOSGeometry *this;
1596    long typ;
1597
1598    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1599
1600    /* TODO: define constant strings instead... */
1601
1602    typ = GEOSGeomTypeId(this);
1603    if ( typ == -1 ) RETURN_NULL(); /* should get an exception first */
1604
1605    RETURN_LONG(typ);
1606}
1607
1608/**
1609 * long GEOSGeometry::getSRID()
1610 */
1611PHP_METHOD(Geometry, getSRID)
1612{
1613    GEOSGeometry *geom;
1614    long int ret;
1615
1616    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1617
1618    ret = GEOSGetSRID(geom);
1619
1620    RETURN_LONG(ret);
1621}
1622
1623/**
1624 * void GEOSGeometry::setSRID(long)
1625 */
1626PHP_METHOD(Geometry, setSRID)
1627{
1628    GEOSGeometry *geom;
1629    long int srid;
1630
1631    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1632
1633    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
1634        &srid) == FAILURE) {
1635        RETURN_NULL();
1636    }
1637
1638    GEOSSetSRID(geom, srid);
1639}
1640
1641/**
1642 * long GEOSGeometry::numGeometries()
1643 */
1644PHP_METHOD(Geometry, numGeometries)
1645{
1646    GEOSGeometry *geom;
1647    long int ret;
1648
1649    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1650
1651    ret = GEOSGetNumGeometries(geom);
1652    if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
1653
1654    RETURN_LONG(ret);
1655}
1656
1657/**
1658 * GEOSGeometry GEOSGeometry::geometryN()
1659 */
1660PHP_METHOD(Geometry, geometryN)
1661{
1662    GEOSGeometry *geom;
1663    const GEOSGeometry *c;
1664    GEOSGeometry *cc;
1665    long int num;
1666
1667    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1668
1669    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
1670        &num) == FAILURE) {
1671        RETURN_NULL();
1672    }
1673
1674    if ( num >= GEOSGetNumGeometries(geom) ) RETURN_NULL(); 
1675    c = GEOSGetGeometryN(geom, num);
1676    if ( ! c ) RETURN_NULL(); /* should get an exception first */
1677    cc = GEOSGeom_clone(c);
1678    if ( ! cc ) RETURN_NULL(); /* should get an exception first */
1679
1680    object_init_ex(return_value, Geometry_ce_ptr);
1681    setRelay(return_value, cc);
1682}
1683
1684/**
1685 * long GEOSGeometry::numInteriorRings()
1686 */
1687PHP_METHOD(Geometry, numInteriorRings)
1688{
1689    GEOSGeometry *geom;
1690    long int ret;
1691
1692    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1693
1694    ret = GEOSGetNumInteriorRings(geom);
1695    if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
1696
1697    RETURN_LONG(ret);
1698}
1699
1700/**
1701 * long GEOSGeometry::numPoints()
1702 */
1703PHP_METHOD(Geometry, numPoints)
1704{
1705    GEOSGeometry *geom;
1706    long int ret;
1707
1708    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1709
1710    ret = GEOSGeomGetNumPoints(geom);
1711    if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
1712
1713    RETURN_LONG(ret);
1714}
1715
1716/**
1717 * double GEOSGeometry::getX()
1718 */
1719PHP_METHOD(Geometry, getX)
1720{
1721    GEOSGeometry *geom;
1722    int ret;
1723    double x;
1724
1725    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1726
1727    ret = GEOSGeomGetX(geom, &x);
1728    if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
1729
1730    RETURN_DOUBLE(x);
1731}
1732
1733/**
1734 * double GEOSGeometry::getY()
1735 */
1736PHP_METHOD(Geometry, getY)
1737{
1738    GEOSGeometry *geom;
1739    int ret;
1740    double y;
1741
1742    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1743
1744    ret = GEOSGeomGetY(geom, &y);
1745    if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
1746
1747    RETURN_DOUBLE(y);
1748}
1749
1750/**
1751 * GEOSGeometry GEOSGeometry::interiorRingN()
1752 */
1753PHP_METHOD(Geometry, interiorRingN)
1754{
1755    GEOSGeometry *geom;
1756    const GEOSGeometry *c;
1757    GEOSGeometry *cc;
1758    long int num;
1759
1760    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1761
1762    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
1763        &num) == FAILURE) {
1764        RETURN_NULL();
1765    }
1766
1767    if ( num >= GEOSGetNumInteriorRings(geom) ) RETURN_NULL(); 
1768    c = GEOSGetInteriorRingN(geom, num);
1769    if ( ! c ) RETURN_NULL(); /* should get an exception first */
1770    cc = GEOSGeom_clone(c);
1771    if ( ! cc ) RETURN_NULL(); /* should get an exception first */
1772
1773    object_init_ex(return_value, Geometry_ce_ptr);
1774    setRelay(return_value, cc);
1775}
1776
1777/**
1778 * GEOSGeometry GEOSGeometry::exteriorRing()
1779 */
1780PHP_METHOD(Geometry, exteriorRing)
1781{
1782    GEOSGeometry *geom;
1783    const GEOSGeometry *c;
1784    GEOSGeometry *cc;
1785
1786    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1787
1788    c = GEOSGetExteriorRing(geom);
1789    if ( ! c ) RETURN_NULL(); /* should get an exception first */
1790    cc = GEOSGeom_clone(c);
1791    if ( ! cc ) RETURN_NULL(); /* should get an exception first */
1792
1793    object_init_ex(return_value, Geometry_ce_ptr);
1794    setRelay(return_value, cc);
1795}
1796
1797/**
1798 * long GEOSGeometry::numCoordinates()
1799 */
1800PHP_METHOD(Geometry, numCoordinates)
1801{
1802    GEOSGeometry *geom;
1803    long int ret;
1804
1805    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1806
1807    ret = GEOSGetNumCoordinates(geom);
1808    if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
1809
1810    RETURN_LONG(ret);
1811}
1812
1813/**
1814 * long GEOSGeometry::dimension()
1815 * 0:puntual 1:lineal 2:areal
1816 */
1817PHP_METHOD(Geometry, dimension)
1818{
1819    GEOSGeometry *geom;
1820    long int ret;
1821
1822    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1823
1824    ret = GEOSGeom_getDimensions(geom);
1825    if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
1826
1827    RETURN_LONG(ret);
1828}
1829
1830/**
1831 * long GEOSGeometry::coordinateDimension()
1832 */
1833PHP_METHOD(Geometry, coordinateDimension)
1834{
1835    GEOSGeometry *geom;
1836    long int ret;
1837
1838    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1839
1840    ret = GEOSGeom_getCoordinateDimension(geom);
1841    if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
1842
1843    RETURN_LONG(ret);
1844}
1845
1846/**
1847 * GEOSGeometry GEOSGeometry::pointN()
1848 */
1849PHP_METHOD(Geometry, pointN)
1850{
1851    GEOSGeometry *geom;
1852    GEOSGeometry *c;
1853    long int num;
1854
1855    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1856
1857    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
1858        &num) == FAILURE) {
1859        RETURN_NULL();
1860    }
1861
1862    if ( num >= GEOSGeomGetNumPoints(geom) ) RETURN_NULL(); 
1863    c = GEOSGeomGetPointN(geom, num);
1864    if ( ! c ) RETURN_NULL(); /* should get an exception first */
1865
1866    object_init_ex(return_value, Geometry_ce_ptr);
1867    setRelay(return_value, c);
1868}
1869
1870/**
1871 * GEOSGeometry GEOSGeometry::startPoint()
1872 */
1873PHP_METHOD(Geometry, startPoint)
1874{
1875    GEOSGeometry *geom;
1876    GEOSGeometry *c;
1877
1878    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1879
1880    c = GEOSGeomGetStartPoint(geom);
1881    if ( ! c ) RETURN_NULL(); /* should get an exception first */
1882
1883    object_init_ex(return_value, Geometry_ce_ptr);
1884    setRelay(return_value, c);
1885}
1886
1887/**
1888 * GEOSGeometry GEOSGeometry::endPoint()
1889 */
1890PHP_METHOD(Geometry, endPoint)
1891{
1892    GEOSGeometry *geom;
1893    GEOSGeometry *c;
1894
1895    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1896
1897    c = GEOSGeomGetEndPoint(geom);
1898    if ( ! c ) RETURN_NULL(); /* should get an exception first */
1899
1900    object_init_ex(return_value, Geometry_ce_ptr);
1901    setRelay(return_value, c);
1902}
1903
1904/**
1905 * double GEOSGeometry::area()
1906 */
1907PHP_METHOD(Geometry, area)
1908{
1909    GEOSGeometry *geom;
1910    double area;
1911    int ret;
1912
1913    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1914
1915    ret = GEOSArea(geom, &area);
1916    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1917
1918    RETURN_DOUBLE(area);
1919}
1920
1921/**
1922 * double GEOSGeometry::length()
1923 */
1924PHP_METHOD(Geometry, length)
1925{
1926    GEOSGeometry *geom;
1927    double length;
1928    int ret;
1929
1930    geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1931
1932    ret = GEOSLength(geom, &length);
1933    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1934
1935    RETURN_DOUBLE(length);
1936}
1937
1938/**
1939 * double GEOSGeometry::distance(GEOSGeometry)
1940 */
1941PHP_METHOD(Geometry, distance)
1942{
1943    GEOSGeometry *this;
1944    GEOSGeometry *other;
1945    zval *zobj;
1946    double dist;
1947    int ret;
1948
1949    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1950
1951    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o",
1952        &zobj) == FAILURE)
1953    {
1954        RETURN_NULL();
1955    }
1956
1957    other = getRelay(zobj, Geometry_ce_ptr);
1958
1959    ret = GEOSDistance(this, other, &dist);
1960    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1961
1962    RETURN_DOUBLE(dist);
1963}
1964
1965/**
1966 * double GEOSGeometry::hausdorffDistance(GEOSGeometry)
1967 */
1968PHP_METHOD(Geometry, hausdorffDistance)
1969{
1970    GEOSGeometry *this;
1971    GEOSGeometry *other;
1972    zval *zobj;
1973    double dist;
1974    int ret;
1975
1976    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1977
1978    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o",
1979        &zobj) == FAILURE)
1980    {
1981        RETURN_NULL();
1982    }
1983
1984    other = getRelay(zobj, Geometry_ce_ptr);
1985
1986    ret = GEOSHausdorffDistance(this, other, &dist);
1987    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1988
1989    RETURN_DOUBLE(dist);
1990}
1991
1992PHP_METHOD(Geometry, snapTo)
1993{
1994    GEOSGeometry *this;
1995    GEOSGeometry *other;
1996    GEOSGeometry *ret;
1997    double tolerance;
1998    zval *zobj;
1999
2000    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2001
2002    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "od", &zobj,
2003            &tolerance) == FAILURE) {
2004        RETURN_NULL();
2005    }
2006    other = getRelay(zobj, Geometry_ce_ptr);
2007
2008    ret = GEOSSnap(this, other, tolerance);
2009    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
2010
2011    /* return_value is a zval */
2012    object_init_ex(return_value, Geometry_ce_ptr);
2013    setRelay(return_value, ret);
2014}
2015
2016PHP_METHOD(Geometry, node)
2017{
2018    GEOSGeometry *this;
2019    GEOSGeometry *ret;
2020
2021    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2022
2023    ret = GEOSNode(this);
2024    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
2025
2026    /* return_value is a zval */
2027    object_init_ex(return_value, Geometry_ce_ptr);
2028    setRelay(return_value, ret);
2029}
2030
2031
2032
2033/* -- class GEOSWKTReader -------------------- */
2034
2035PHP_METHOD(WKTReader, __construct);
2036PHP_METHOD(WKTReader, read);
2037
2038static zend_function_entry WKTReader_methods[] = {
2039    PHP_ME(WKTReader, __construct, NULL, 0)
2040    PHP_ME(WKTReader, read, NULL, 0)
2041    {NULL, NULL, NULL}
2042};
2043
2044static zend_class_entry *WKTReader_ce_ptr;
2045
2046static zend_object_handlers WKTReader_object_handlers;
2047
2048static void
2049WKTReader_dtor (void *object TSRMLS_DC)
2050{
2051    Proxy *obj = (Proxy *)object;
2052    GEOSWKTReader_destroy((GEOSWKTReader*)obj->relay);
2053
2054    zend_hash_destroy(obj->std.properties);
2055    FREE_HASHTABLE(obj->std.properties);
2056
2057    efree(obj);
2058}
2059
2060static zend_object_value
2061WKTReader_create_obj (zend_class_entry *type TSRMLS_DC)
2062{
2063    return Gen_create_obj(type, WKTReader_dtor, &WKTReader_object_handlers);
2064}
2065
2066
2067PHP_METHOD(WKTReader, __construct)
2068{
2069    GEOSWKTReader* obj;
2070    zval *object = getThis();
2071
2072    obj = GEOSWKTReader_create();
2073    if ( ! obj ) {
2074        php_error_docref(NULL TSRMLS_CC, E_ERROR,
2075                "GEOSWKTReader_create() failed (didn't initGEOS?)");
2076    }
2077
2078    setRelay(object, obj);
2079}
2080
2081PHP_METHOD(WKTReader, read)
2082{
2083    GEOSWKTReader *reader;
2084    GEOSGeometry *geom;
2085    char* wkt;
2086    int wktlen;
2087
2088    reader = (GEOSWKTReader*)getRelay(getThis(), WKTReader_ce_ptr);
2089
2090    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
2091        &wkt, &wktlen) == FAILURE)
2092    {
2093        RETURN_NULL();
2094    }
2095
2096    geom = GEOSWKTReader_read(reader, wkt);
2097    /* we'll probably get an exception if geom is null */
2098    if ( ! geom ) RETURN_NULL();
2099 
2100    /* return_value is a zval */
2101    object_init_ex(return_value, Geometry_ce_ptr);
2102    setRelay(return_value, geom);
2103
2104}
2105
2106/* -- class GEOSWKTWriter -------------------- */
2107
2108PHP_METHOD(WKTWriter, __construct);
2109PHP_METHOD(WKTWriter, write);
2110PHP_METHOD(WKTWriter, setTrim);
2111PHP_METHOD(WKTWriter, setRoundingPrecision);
2112PHP_METHOD(WKTWriter, setOutputDimension);
2113PHP_METHOD(WKTWriter, getOutputDimension);
2114PHP_METHOD(WKTWriter, setOld3D);
2115
2116static zend_function_entry WKTWriter_methods[] = {
2117    PHP_ME(WKTWriter, __construct, NULL, 0)
2118    PHP_ME(WKTWriter, write, NULL, 0)
2119    PHP_ME(WKTWriter, setTrim, NULL, 0)
2120    PHP_ME(WKTWriter, setRoundingPrecision, NULL, 0)
2121    PHP_ME(WKTWriter, setOutputDimension, NULL, 0)
2122    PHP_ME(WKTWriter, getOutputDimension, NULL, 0)
2123    PHP_ME(WKTWriter, setOld3D, NULL, 0)
2124    {NULL, NULL, NULL}
2125};
2126
2127static zend_class_entry *WKTWriter_ce_ptr;
2128
2129static zend_object_handlers WKTWriter_object_handlers;
2130
2131static void
2132WKTWriter_dtor (void *object TSRMLS_DC)
2133{
2134    Proxy *obj = (Proxy *)object;
2135    GEOSWKTWriter_destroy((GEOSWKTWriter*)obj->relay);
2136
2137    zend_hash_destroy(obj->std.properties);
2138    FREE_HASHTABLE(obj->std.properties);
2139
2140    efree(obj);
2141}
2142
2143static zend_object_value
2144WKTWriter_create_obj (zend_class_entry *type TSRMLS_DC)
2145{
2146    return Gen_create_obj(type, WKTWriter_dtor, &WKTWriter_object_handlers);
2147}
2148
2149PHP_METHOD(WKTWriter, __construct)
2150{
2151    GEOSWKTWriter* obj;
2152    zval *object = getThis();
2153
2154    obj = GEOSWKTWriter_create();
2155    if ( ! obj ) {
2156        php_error_docref(NULL TSRMLS_CC, E_ERROR,
2157                "GEOSWKTWriter_create() failed (didn't initGEOS?)");
2158    }
2159
2160    setRelay(object, obj);
2161}
2162
2163PHP_METHOD(WKTWriter, write)
2164{
2165    GEOSWKTWriter *writer;
2166    zval *zobj;
2167    GEOSGeometry *geom;
2168    char* wkt;
2169    char* retstr;
2170
2171    writer = (GEOSWKTWriter*)getRelay(getThis(), WKTWriter_ce_ptr);
2172
2173    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
2174        == FAILURE)
2175    {
2176        RETURN_NULL();
2177    }
2178
2179    geom = getRelay(zobj, Geometry_ce_ptr);
2180
2181    wkt = GEOSWKTWriter_write(writer, geom);
2182    /* we'll probably get an exception if wkt is null */
2183    if ( ! wkt ) RETURN_NULL();
2184
2185    retstr = estrdup(wkt);
2186    GEOSFree(wkt);
2187
2188    RETURN_STRING(retstr, 0);
2189}
2190
2191PHP_METHOD(WKTWriter, setTrim)
2192{
2193    GEOSWKTWriter *writer;
2194    zend_bool trimval;
2195    char trim;
2196
2197    writer = (GEOSWKTWriter*)getRelay(getThis(), WKTWriter_ce_ptr);
2198
2199    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &trimval)
2200        == FAILURE)
2201    {
2202        RETURN_NULL();
2203    }
2204
2205    trim = trimval;
2206    GEOSWKTWriter_setTrim(writer, trim);
2207}
2208
2209PHP_METHOD(WKTWriter, setRoundingPrecision)
2210{
2211    GEOSWKTWriter *writer;
2212    long int prec;
2213
2214    writer = (GEOSWKTWriter*)getRelay(getThis(), WKTWriter_ce_ptr);
2215
2216    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &prec)
2217        == FAILURE)
2218    {
2219        RETURN_NULL();
2220    }
2221
2222    GEOSWKTWriter_setRoundingPrecision(writer, prec);
2223}
2224
2225/**
2226 * void GEOSWKTWriter::setOutputDimension()
2227 */
2228PHP_METHOD(WKTWriter, setOutputDimension)
2229{
2230    GEOSWKTWriter *writer;
2231    long int dim;
2232
2233    writer = (GEOSWKTWriter*)getRelay(getThis(), WKTWriter_ce_ptr);
2234
2235    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &dim)
2236        == FAILURE)
2237    {
2238        RETURN_NULL();
2239    }
2240
2241    GEOSWKTWriter_setOutputDimension(writer, dim);
2242}
2243
2244/**
2245 * long GEOSWKTWriter::getOutputDimension()
2246 */
2247PHP_METHOD(WKTWriter, getOutputDimension)
2248{
2249    GEOSWKTWriter *writer;
2250    long int ret;
2251
2252    writer = (GEOSWKTWriter*)getRelay(getThis(), WKTWriter_ce_ptr);
2253
2254    ret = GEOSWKTWriter_getOutputDimension(writer);
2255
2256    RETURN_LONG(ret);
2257}
2258
2259PHP_METHOD(WKTWriter, setOld3D)
2260{
2261    GEOSWKTWriter *writer;
2262    zend_bool bval;
2263    int val;
2264
2265    writer = (GEOSWKTWriter*)getRelay(getThis(), WKTWriter_ce_ptr);
2266
2267    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &bval)
2268        == FAILURE)
2269    {
2270        RETURN_NULL();
2271    }
2272
2273    val = bval;
2274    GEOSWKTWriter_setOld3D(writer, val);
2275}
2276
2277/* -- class GEOSWKBWriter -------------------- */
2278
2279PHP_METHOD(WKBWriter, __construct);
2280PHP_METHOD(WKBWriter, getOutputDimension);
2281PHP_METHOD(WKBWriter, setOutputDimension);
2282PHP_METHOD(WKBWriter, getByteOrder);
2283PHP_METHOD(WKBWriter, setByteOrder);
2284PHP_METHOD(WKBWriter, setIncludeSRID);
2285PHP_METHOD(WKBWriter, getIncludeSRID);
2286PHP_METHOD(WKBWriter, write);
2287PHP_METHOD(WKBWriter, writeHEX);
2288
2289static zend_function_entry WKBWriter_methods[] = {
2290    PHP_ME(WKBWriter, __construct, NULL, 0)
2291    PHP_ME(WKBWriter, getOutputDimension, NULL, 0)
2292    PHP_ME(WKBWriter, setOutputDimension, NULL, 0)
2293    PHP_ME(WKBWriter, getByteOrder, NULL, 0)
2294    PHP_ME(WKBWriter, setByteOrder, NULL, 0)
2295    PHP_ME(WKBWriter, getIncludeSRID, NULL, 0)
2296    PHP_ME(WKBWriter, setIncludeSRID, NULL, 0)
2297    PHP_ME(WKBWriter, write, NULL, 0)
2298    PHP_ME(WKBWriter, writeHEX, NULL, 0)
2299    {NULL, NULL, NULL}
2300};
2301
2302static zend_class_entry *WKBWriter_ce_ptr;
2303
2304static zend_object_handlers WKBWriter_object_handlers;
2305
2306static void
2307WKBWriter_dtor (void *object TSRMLS_DC)
2308{
2309    Proxy *obj = (Proxy *)object;
2310    GEOSWKBWriter_destroy((GEOSWKBWriter*)obj->relay);
2311
2312    zend_hash_destroy(obj->std.properties);
2313    FREE_HASHTABLE(obj->std.properties);
2314
2315    efree(obj);
2316}
2317
2318static zend_object_value
2319WKBWriter_create_obj (zend_class_entry *type TSRMLS_DC)
2320{
2321    return Gen_create_obj(type, WKBWriter_dtor, &WKBWriter_object_handlers);
2322}
2323
2324/**
2325 * GEOSWKBWriter w = new GEOSWKBWriter()
2326 */
2327PHP_METHOD(WKBWriter, __construct)
2328{
2329    GEOSWKBWriter* obj;
2330    zval *object = getThis();
2331
2332    obj = GEOSWKBWriter_create();
2333    if ( ! obj ) {
2334        php_error_docref(NULL TSRMLS_CC, E_ERROR,
2335                "GEOSWKBWriter_create() failed (didn't initGEOS?)");
2336    }
2337
2338    setRelay(object, obj);
2339}
2340
2341/**
2342 * long GEOSWKBWriter::getOutputDimension();
2343 */
2344PHP_METHOD(WKBWriter, getOutputDimension)
2345{
2346    GEOSWKBWriter *writer;
2347    long int ret;
2348
2349    writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2350
2351    ret = GEOSWKBWriter_getOutputDimension(writer);
2352
2353    RETURN_LONG(ret);
2354}
2355
2356/**
2357 * void GEOSWKBWriter::setOutputDimension(dims);
2358 */
2359PHP_METHOD(WKBWriter, setOutputDimension)
2360{
2361    GEOSWKBWriter *writer;
2362    long int dim;
2363
2364    writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2365
2366    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &dim)
2367        == FAILURE)
2368    {
2369        RETURN_NULL();
2370    }
2371
2372    GEOSWKBWriter_setOutputDimension(writer, dim);
2373
2374}
2375
2376/**
2377 * string GEOSWKBWriter::write(GEOSGeometry)
2378 */
2379PHP_METHOD(WKBWriter, write)
2380{
2381    GEOSWKBWriter *writer;
2382    zval *zobj;
2383    GEOSGeometry *geom;
2384    char *ret;
2385    size_t retsize;
2386    char* retstr;
2387
2388    writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2389
2390    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
2391        == FAILURE)
2392    {
2393        RETURN_NULL();
2394    }
2395
2396    geom = getRelay(zobj, Geometry_ce_ptr);
2397
2398    ret = (char*)GEOSWKBWriter_write(writer, geom, &retsize);
2399    /* we'll probably get an exception if ret is null */
2400    if ( ! ret ) RETURN_NULL();
2401
2402    retstr = estrndup(ret, retsize);
2403    GEOSFree(ret);
2404
2405    RETURN_STRINGL(retstr, retsize, 0);
2406}
2407
2408/**
2409 * string GEOSWKBWriter::writeHEX(GEOSGeometry)
2410 */
2411PHP_METHOD(WKBWriter, writeHEX)
2412{
2413    GEOSWKBWriter *writer;
2414    zval *zobj;
2415    GEOSGeometry *geom;
2416    char *ret;
2417    size_t retsize; /* useless... */
2418    char* retstr;
2419
2420    writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2421
2422    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
2423        == FAILURE)
2424    {
2425        RETURN_NULL();
2426    }
2427
2428    geom = getRelay(zobj, Geometry_ce_ptr);
2429
2430    ret = (char*)GEOSWKBWriter_writeHEX(writer, geom, &retsize);
2431    /* we'll probably get an exception if ret is null */
2432    if ( ! ret ) RETURN_NULL();
2433
2434    retstr = estrndup(ret, retsize);
2435    GEOSFree(ret);
2436
2437    RETURN_STRING(retstr, 0);
2438}
2439
2440/**
2441 * long GEOSWKBWriter::getByteOrder();
2442 */
2443PHP_METHOD(WKBWriter, getByteOrder)
2444{
2445    GEOSWKBWriter *writer;
2446    long int ret;
2447
2448    writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2449
2450    ret = GEOSWKBWriter_getByteOrder(writer);
2451
2452    RETURN_LONG(ret);
2453}
2454
2455/**
2456 * void GEOSWKBWriter::setByteOrder(dims);
2457 */
2458PHP_METHOD(WKBWriter, setByteOrder)
2459{
2460    GEOSWKBWriter *writer;
2461    long int dim;
2462
2463    writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2464
2465    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &dim)
2466        == FAILURE)
2467    {
2468        RETURN_NULL();
2469    }
2470
2471    GEOSWKBWriter_setByteOrder(writer, dim);
2472
2473}
2474
2475/**
2476 * bool GEOSWKBWriter::getIncludeSRID();
2477 */
2478PHP_METHOD(WKBWriter, getIncludeSRID)
2479{
2480    GEOSWKBWriter *writer;
2481    int ret;
2482    zend_bool retBool;
2483
2484    writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2485
2486    ret = GEOSWKBWriter_getIncludeSRID(writer);
2487    retBool = ret;
2488
2489    RETURN_BOOL(retBool);
2490}
2491
2492/**
2493 * void GEOSWKBWriter::setIncludeSRID(bool);
2494 */
2495PHP_METHOD(WKBWriter, setIncludeSRID)
2496{
2497    GEOSWKBWriter *writer;
2498    int inc;
2499    zend_bool incVal;
2500
2501    writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2502
2503    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &incVal)
2504        == FAILURE)
2505    {
2506        RETURN_NULL();
2507    }
2508
2509    inc = incVal;
2510    GEOSWKBWriter_setIncludeSRID(writer, inc);
2511}
2512
2513/* -- class GEOSWKBReader -------------------- */
2514
2515PHP_METHOD(WKBReader, __construct);
2516PHP_METHOD(WKBReader, read);
2517PHP_METHOD(WKBReader, readHEX);
2518
2519static zend_function_entry WKBReader_methods[] = {
2520    PHP_ME(WKBReader, __construct, NULL, 0)
2521    PHP_ME(WKBReader, read, NULL, 0)
2522    PHP_ME(WKBReader, readHEX, NULL, 0)
2523    {NULL, NULL, NULL}
2524};
2525
2526static zend_class_entry *WKBReader_ce_ptr;
2527
2528static zend_object_handlers WKBReader_object_handlers;
2529
2530static void
2531WKBReader_dtor (void *object TSRMLS_DC)
2532{
2533    Proxy *obj = (Proxy *)object;
2534    GEOSWKBReader_destroy((GEOSWKBReader*)obj->relay);
2535
2536    zend_hash_destroy(obj->std.properties);
2537    FREE_HASHTABLE(obj->std.properties);
2538
2539    efree(obj);
2540}
2541
2542static zend_object_value
2543WKBReader_create_obj (zend_class_entry *type TSRMLS_DC)
2544{
2545    return Gen_create_obj(type, WKBReader_dtor, &WKBReader_object_handlers);
2546}
2547
2548
2549PHP_METHOD(WKBReader, __construct)
2550{
2551    GEOSWKBReader* obj;
2552    zval *object = getThis();
2553
2554    obj = GEOSWKBReader_create();
2555    if ( ! obj ) {
2556        php_error_docref(NULL TSRMLS_CC, E_ERROR,
2557                "GEOSWKBReader_create() failed (didn't initGEOS?)");
2558    }
2559
2560    setRelay(object, obj);
2561}
2562
2563PHP_METHOD(WKBReader, read)
2564{
2565    GEOSWKBReader *reader;
2566    GEOSGeometry *geom;
2567    unsigned char* wkb;
2568    int wkblen;
2569
2570    reader = (GEOSWKBReader*)getRelay(getThis(), WKBReader_ce_ptr);
2571
2572    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
2573        &wkb, &wkblen) == FAILURE)
2574    {
2575        RETURN_NULL();
2576    }
2577
2578    geom = GEOSWKBReader_read(reader, wkb, wkblen);
2579    /* we'll probably get an exception if geom is null */
2580    if ( ! geom ) RETURN_NULL();
2581
2582    /* return_value is a zval */
2583    object_init_ex(return_value, Geometry_ce_ptr);
2584    setRelay(return_value, geom);
2585
2586}
2587
2588PHP_METHOD(WKBReader, readHEX)
2589{
2590    GEOSWKBReader *reader;
2591    GEOSGeometry *geom;
2592    unsigned char* wkb;
2593    int wkblen;
2594
2595    reader = (GEOSWKBReader*)getRelay(getThis(), WKBReader_ce_ptr);
2596
2597    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
2598        &wkb, &wkblen) == FAILURE)
2599    {
2600        RETURN_NULL();
2601    }
2602
2603    geom = GEOSWKBReader_readHEX(reader, wkb, wkblen);
2604    /* we'll probably get an exception if geom is null */
2605    if ( ! geom ) RETURN_NULL();
2606 
2607    /* return_value is a zval */
2608    object_init_ex(return_value, Geometry_ce_ptr);
2609    setRelay(return_value, geom);
2610
2611}
2612
2613
2614/* -- Free functions ------------------------- */
2615
2616/**
2617 * string GEOSVersion()
2618 */
2619PHP_FUNCTION(GEOSVersion)
2620{
2621    char *str;
2622
2623    str = estrdup(GEOSversion());
2624    RETURN_STRING(str, 0);
2625}
2626
2627/**
2628 * array GEOSPolygonize(GEOSGeometry $geom)
2629 *
2630 * The returned array contains the following elements:
2631 *
2632 *  - 'rings'
2633 *      Type: array of GEOSGeometry
2634 *      Rings that can be formed by the costituent
2635 *      linework of geometry.
2636 *  - 'cut_edges' (optional)
2637 *      Type: array of GEOSGeometry
2638 *      Edges which are connected at both ends but
2639 *      which do not form part of polygon.
2640 *  - 'dangles'
2641 *      Type: array of GEOSGeometry
2642 *      Edges which have one or both ends which are
2643 *      not incident on another edge endpoint
2644 *  - 'invalid_rings'
2645 *      Type: array of GEOSGeometry
2646 *      Edges which form rings which are invalid
2647 *      (e.g. the component lines contain a self-intersection)
2648 *
2649 */
2650PHP_FUNCTION(GEOSPolygonize)
2651{
2652    GEOSGeometry *this;
2653    GEOSGeometry *rings;
2654    GEOSGeometry *cut_edges;
2655    GEOSGeometry *dangles;
2656    GEOSGeometry *invalid_rings;
2657    zval *array_elem;
2658    zval *zobj;
2659
2660    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
2661        == FAILURE)
2662    {
2663        RETURN_NULL();
2664    }
2665    this = getRelay(zobj, Geometry_ce_ptr);
2666
2667    rings = GEOSPolygonize_full(this, &cut_edges, &dangles, &invalid_rings);
2668    if ( ! rings ) RETURN_NULL(); /* should get an exception first */
2669
2670    /* return value should be an array */
2671    array_init(return_value);
2672
2673    MAKE_STD_ZVAL(array_elem);
2674    array_init(array_elem);
2675    dumpGeometry(rings, array_elem);
2676    GEOSGeom_destroy(rings);
2677    add_assoc_zval(return_value, "rings", array_elem); 
2678
2679    MAKE_STD_ZVAL(array_elem);
2680    array_init(array_elem);
2681    dumpGeometry(cut_edges, array_elem);
2682    GEOSGeom_destroy(cut_edges);
2683    add_assoc_zval(return_value, "cut_edges", array_elem);
2684
2685    MAKE_STD_ZVAL(array_elem);
2686    array_init(array_elem);
2687    dumpGeometry(dangles, array_elem);
2688    GEOSGeom_destroy(dangles);
2689    add_assoc_zval(return_value, "dangles", array_elem);
2690
2691    MAKE_STD_ZVAL(array_elem);
2692    array_init(array_elem);
2693    dumpGeometry(invalid_rings, array_elem);
2694    GEOSGeom_destroy(invalid_rings);
2695    add_assoc_zval(return_value, "invalid_rings", array_elem);
2696
2697}
2698
2699/**
2700 * array GEOSLineMerge(GEOSGeometry $geom)
2701 */
2702PHP_FUNCTION(GEOSLineMerge)
2703{
2704    GEOSGeometry *geom_in;
2705    GEOSGeometry *geom_out;
2706    zval *zobj;
2707
2708    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
2709        == FAILURE)
2710    {
2711        RETURN_NULL();
2712    }
2713    geom_in = getRelay(zobj, Geometry_ce_ptr);
2714
2715    geom_out = GEOSLineMerge(geom_in);
2716    if ( ! geom_out ) RETURN_NULL(); /* should get an exception first */
2717
2718    /* return value should be an array */
2719    array_init(return_value);
2720    dumpGeometry(geom_out, return_value);
2721    GEOSGeom_destroy(geom_out);
2722}
2723
2724/**
2725 * GEOSGeometry GEOSSharedPaths(GEOSGeometry $geom1, GEOSGeometry *geom2)
2726 */
2727PHP_FUNCTION(GEOSSharedPaths)
2728{
2729    GEOSGeometry *geom_in_1;
2730    GEOSGeometry *geom_in_2;
2731    GEOSGeometry *geom_out;
2732    zval *zobj1, *zobj2;
2733
2734    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "oo", &zobj1, &zobj2)
2735        == FAILURE)
2736    {
2737        RETURN_NULL();
2738    }
2739    geom_in_1 = getRelay(zobj1, Geometry_ce_ptr);
2740    geom_in_2 = getRelay(zobj2, Geometry_ce_ptr);
2741
2742    geom_out = GEOSSharedPaths(geom_in_1, geom_in_2);
2743    if ( ! geom_out ) RETURN_NULL(); /* should get an exception first */
2744
2745    /* return_value is a zval */
2746    object_init_ex(return_value, Geometry_ce_ptr);
2747    setRelay(return_value, geom_out);
2748}
2749
2750/**
2751 * GEOSGeometry::delaunayTriangulation([<tolerance>], [<onlyEdges>])
2752 *
2753 *  'tolerance'
2754 *       Type: double
2755 *       snapping tolerance to use for improved robustness
2756 *  'onlyEdges'
2757 *       Type: boolean
2758 *       if true will return a MULTILINESTRING, otherwise (the default)
2759 *       it will return a GEOMETRYCOLLECTION containing triangular POLYGONs.
2760 */
2761PHP_METHOD(Geometry, delaunayTriangulation)
2762{
2763    GEOSGeometry *this;
2764    GEOSGeometry *ret;
2765    double tolerance = 0.0;
2766    zend_bool edgeonly = 0;
2767
2768    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2769
2770    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|db",
2771            &tolerance, &edgeonly) == FAILURE) {
2772        RETURN_NULL();
2773    }
2774
2775    ret = GEOSDelaunayTriangulation(this, tolerance, edgeonly ? 1 : 0);
2776    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
2777
2778    /* return_value is a zval */
2779    object_init_ex(return_value, Geometry_ce_ptr);
2780    setRelay(return_value, ret);
2781}
2782
2783/**
2784 * GEOSGeometry::voronoiDiagram([<tolerance>], [<onlyEdges>], [<extent>])
2785 *
2786 *  'tolerance'
2787 *       Type: double
2788 *       snapping tolerance to use for improved robustness
2789 *  'onlyEdges'
2790 *       Type: boolean
2791 *       if true will return a MULTILINESTRING, otherwise (the default)
2792 *       it will return a GEOMETRYCOLLECTION containing POLYGONs.
2793 *  'extent'
2794 *       Type: geometry
2795 *       Clip returned diagram by the extent of the given geometry
2796 */
2797PHP_METHOD(Geometry, voronoiDiagram)
2798{
2799    GEOSGeometry *this;
2800    GEOSGeometry *ret;
2801    zval *zobj = 0;
2802    GEOSGeometry *env = 0;
2803    double tolerance = 0.0;
2804    zend_bool edgeonly = 0;
2805
2806    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2807
2808    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|dbo",
2809            &tolerance, &edgeonly, &zobj) == FAILURE) {
2810        RETURN_NULL();
2811    }
2812
2813    if ( zobj ) env = getRelay(zobj, Geometry_ce_ptr);
2814    ret = GEOSVoronoiDiagram(this, env, tolerance, edgeonly ? 1 : 0);
2815    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
2816
2817    /* return_value is a zval */
2818    object_init_ex(return_value, Geometry_ce_ptr);
2819    setRelay(return_value, ret);
2820}
2821
2822/**
2823 * bool GEOSRelateMatch(string matrix, string pattern)
2824 */
2825PHP_FUNCTION(GEOSRelateMatch)
2826{
2827    char* mat = NULL;
2828    int matlen;
2829    char* pat = NULL;
2830    int patlen;
2831    int ret;
2832    zend_bool retBool;
2833
2834    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",
2835        &mat, &matlen, &pat, &patlen) == FAILURE)
2836    {
2837        RETURN_NULL();
2838    }
2839
2840    ret = GEOSRelatePatternMatch(mat, pat);
2841    if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
2842
2843    /* return_value is a zval */
2844    retBool = ret;
2845    RETURN_BOOL(retBool);
2846}
2847
2848/* ------ Initialization / Deinitialization / Meta ------------------ */
2849
2850/* per-module initialization */
2851PHP_MINIT_FUNCTION(geos)
2852{
2853    zend_class_entry ce;
2854
2855    /* WKTReader */
2856    INIT_CLASS_ENTRY(ce, "GEOSWKTReader", WKTReader_methods);
2857    WKTReader_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
2858    WKTReader_ce_ptr->create_object = WKTReader_create_obj;
2859    memcpy(&WKTReader_object_handlers,
2860        zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2861    WKTReader_object_handlers.clone_obj = NULL;
2862
2863    /* WKTWriter */
2864    INIT_CLASS_ENTRY(ce, "GEOSWKTWriter", WKTWriter_methods);
2865    WKTWriter_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
2866    WKTWriter_ce_ptr->create_object = WKTWriter_create_obj;
2867    memcpy(&WKTWriter_object_handlers,
2868        zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2869    WKTWriter_object_handlers.clone_obj = NULL;
2870
2871    /* Geometry */
2872    INIT_CLASS_ENTRY(ce, "GEOSGeometry", Geometry_methods);
2873    Geometry_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
2874    Geometry_ce_ptr->create_object = Geometry_create_obj;
2875    memcpy(&Geometry_object_handlers,
2876        zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2877    Geometry_object_handlers.clone_obj = NULL;
2878    /* Geometry serialization */
2879    Geometry_ce_ptr->serialize = Geometry_serialize;
2880    Geometry_ce_ptr->unserialize = Geometry_deserialize;
2881
2882    /* WKBWriter */
2883    INIT_CLASS_ENTRY(ce, "GEOSWKBWriter", WKBWriter_methods);
2884    WKBWriter_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
2885    WKBWriter_ce_ptr->create_object = WKBWriter_create_obj;
2886    memcpy(&WKBWriter_object_handlers,
2887        zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2888    WKBWriter_object_handlers.clone_obj = NULL;
2889
2890    /* WKBReader */
2891    INIT_CLASS_ENTRY(ce, "GEOSWKBReader", WKBReader_methods);
2892    WKBReader_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
2893    WKBReader_ce_ptr->create_object = WKBReader_create_obj;
2894    memcpy(&WKBReader_object_handlers,
2895        zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2896    WKBReader_object_handlers.clone_obj = NULL;
2897
2898
2899    /* Constants */
2900    REGISTER_LONG_CONSTANT("GEOSBUF_CAP_ROUND",  GEOSBUF_CAP_ROUND,
2901        CONST_CS|CONST_PERSISTENT);
2902    REGISTER_LONG_CONSTANT("GEOSBUF_CAP_FLAT",   GEOSBUF_CAP_FLAT,
2903        CONST_CS|CONST_PERSISTENT);
2904    REGISTER_LONG_CONSTANT("GEOSBUF_CAP_SQUARE", GEOSBUF_CAP_SQUARE,
2905        CONST_CS|CONST_PERSISTENT);
2906    REGISTER_LONG_CONSTANT("GEOSBUF_JOIN_ROUND", GEOSBUF_JOIN_ROUND,
2907        CONST_CS|CONST_PERSISTENT);
2908    REGISTER_LONG_CONSTANT("GEOSBUF_JOIN_MITRE", GEOSBUF_JOIN_MITRE,
2909        CONST_CS|CONST_PERSISTENT);
2910    REGISTER_LONG_CONSTANT("GEOSBUF_JOIN_BEVEL", GEOSBUF_JOIN_BEVEL,
2911        CONST_CS|CONST_PERSISTENT);
2912
2913    REGISTER_LONG_CONSTANT("GEOS_POINT", GEOS_POINT,
2914        CONST_CS|CONST_PERSISTENT);
2915    REGISTER_LONG_CONSTANT("GEOS_LINESTRING", GEOS_LINESTRING,
2916        CONST_CS|CONST_PERSISTENT);
2917    REGISTER_LONG_CONSTANT("GEOS_LINEARRING", GEOS_LINEARRING,
2918        CONST_CS|CONST_PERSISTENT);
2919    REGISTER_LONG_CONSTANT("GEOS_POLYGON", GEOS_POLYGON,
2920        CONST_CS|CONST_PERSISTENT);
2921    REGISTER_LONG_CONSTANT("GEOS_MULTIPOINT", GEOS_MULTIPOINT,
2922        CONST_CS|CONST_PERSISTENT);
2923    REGISTER_LONG_CONSTANT("GEOS_MULTILINESTRING", GEOS_MULTILINESTRING,
2924        CONST_CS|CONST_PERSISTENT);
2925    REGISTER_LONG_CONSTANT("GEOS_MULTIPOLYGON", GEOS_MULTIPOLYGON,
2926        CONST_CS|CONST_PERSISTENT);
2927    REGISTER_LONG_CONSTANT("GEOS_GEOMETRYCOLLECTION", GEOS_GEOMETRYCOLLECTION,
2928        CONST_CS|CONST_PERSISTENT);
2929
2930    REGISTER_LONG_CONSTANT("GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE",
2931        GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE,
2932        CONST_CS|CONST_PERSISTENT);
2933
2934    REGISTER_LONG_CONSTANT("GEOS_PREC_NO_TOPO", GEOS_PREC_NO_TOPO,
2935        CONST_CS|CONST_PERSISTENT);
2936    REGISTER_LONG_CONSTANT("GEOS_PREC_KEEP_COLLAPSED", GEOS_PREC_NO_TOPO,
2937        CONST_CS|CONST_PERSISTENT);
2938
2939    REGISTER_LONG_CONSTANT("GEOSRELATE_BNR_MOD2", GEOSRELATE_BNR_MOD2,
2940        CONST_CS|CONST_PERSISTENT);
2941    REGISTER_LONG_CONSTANT("GEOSRELATE_BNR_OGC", GEOSRELATE_BNR_OGC,
2942        CONST_CS|CONST_PERSISTENT);
2943    REGISTER_LONG_CONSTANT("GEOSRELATE_BNR_ENDPOINT", GEOSRELATE_BNR_ENDPOINT,
2944        CONST_CS|CONST_PERSISTENT);
2945    REGISTER_LONG_CONSTANT("GEOSRELATE_BNR_MULTIVALENT_ENDPOINT",
2946        GEOSRELATE_BNR_MULTIVALENT_ENDPOINT,
2947        CONST_CS|CONST_PERSISTENT);
2948    REGISTER_LONG_CONSTANT("GEOSRELATE_BNR_MONOVALENT_ENDPOINT",
2949        GEOSRELATE_BNR_MONOVALENT_ENDPOINT,
2950        CONST_CS|CONST_PERSISTENT);
2951
2952    return SUCCESS;
2953}
2954
2955/* per-module shutdown */
2956PHP_MSHUTDOWN_FUNCTION(geos)
2957{
2958    delGeometrySerializer();
2959    delGeometryDeserializer();
2960    return SUCCESS;
2961}
2962
2963/* per-request initialization */
2964PHP_RINIT_FUNCTION(geos)
2965{
2966    initGEOS(noticeHandler, errorHandler);
2967    return SUCCESS;
2968}
2969
2970/* pre-request destruction */
2971PHP_RSHUTDOWN_FUNCTION(geos)
2972{
2973    finishGEOS();
2974    return SUCCESS;
2975}
2976
2977/* module info */
2978PHP_MINFO_FUNCTION(geos)
2979{
2980    php_info_print_table_start();
2981    php_info_print_table_row(2,
2982        "GEOS - Geometry Engine Open Source", "enabled");
2983    php_info_print_table_row(2,
2984        "Version", PHP_GEOS_VERSION);
2985    php_info_print_table_end();
2986}
2987
Note: See TracBrowser for help on using the repository browser.