Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : /*
14 : * @a Wouter Scherphof, Niels Nes, Foteini Alvanaki
15 : * @* The simple geom module
16 : */
17 :
18 : #include "geom.h"
19 : #include "geod.h"
20 : #include "geom_atoms.h"
21 : #include "mal_exception.h"
22 :
23 : mbr mbrNIL = {0}; // will be initialized properly by geom prelude
24 :
25 : /**
26 : * AGGREGATES
27 : **/
28 :
29 : /**
30 : * Collect (Group By implementation)
31 : *
32 : **/
33 : //Gets the type of collection a single geometry should belong to
34 : static int
35 : GEOSGeom_getCollectionType (int GEOSGeom_type) {
36 :
37 : //TODO Remove
38 : (void) geodeticEdgeBoundingBox;
39 :
40 : //Single geometries get collected into a Multi* geometry
41 : if (GEOSGeom_type == GEOS_POINT)
42 : return GEOS_MULTIPOINT;
43 : else if (GEOSGeom_type == GEOS_LINESTRING || GEOSGeom_type == GEOS_LINEARRING)
44 : return GEOS_MULTILINESTRING;
45 : else if (GEOSGeom_type == GEOS_POLYGON)
46 : return GEOS_MULTIPOLYGON;
47 : //Multi* or GeometryCollections get collected into GeometryCollections
48 : else
49 : return GEOS_GEOMETRYCOLLECTION;
50 : }
51 :
52 : /* Group By operation. Joins geometries together in the same group into a MultiGeometry */
53 : str
54 2 : wkbCollectAggrSubGroupedCand(bat *outid, const bat *bid, const bat *gid, const bat *eid, const bat *sid, const bit *skip_nils)
55 : {
56 2 : BAT *b = NULL, *g = NULL, *s = NULL, *out = NULL;
57 2 : BAT *sortedgroups, *sortedorder;
58 2 : BATiter bi;
59 2 : const oid *gids = NULL;
60 2 : str msg = MAL_SUCCEED;
61 2 : const char *err;
62 : //SRID for collection
63 2 : int srid = 0;
64 :
65 2 : oid min, max;
66 2 : BUN ngrp;
67 2 : struct canditer ci;
68 :
69 2 : oid lastGrp = -1;
70 2 : int geomCollectionType = -1;
71 2 : BUN geomCount = 0;
72 2 : wkb **unions = NULL;
73 2 : GEOSGeom *unionGroup = NULL, collection;
74 :
75 : //Not using these variables
76 2 : (void)skip_nils;
77 2 : (void)eid;
78 :
79 : //Get the BAT descriptors for the value, group and candidate bats
80 2 : if ((b = BATdescriptor(*bid)) == NULL ||
81 2 : (gid && !is_bat_nil(*gid) && (g = BATdescriptor(*gid)) == NULL) ||
82 0 : (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL)) {
83 0 : msg = createException(MAL, "geom.Collect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
84 0 : goto free;
85 : }
86 :
87 2 : if ((BATsort(&sortedgroups, &sortedorder, NULL, g, NULL, NULL, false, false, true)) != GDK_SUCCEED) {
88 0 : msg = createException(MAL, "geom.Collect", "BAT sort failed.");
89 0 : goto free;
90 : }
91 :
92 : //Project new order onto input bat IF the sortedorder isn't dense (in which case, the original input order is correct)
93 2 : if (!BATtdense(sortedorder)) {
94 0 : BAT *sortedinput = BATproject(sortedorder, b);
95 0 : BBPreclaim(sortedorder);
96 0 : if (sortedinput == NULL) {
97 0 : BBPreclaim(sortedgroups);
98 0 : msg = createException(MAL, "geom.Collect", GDK_EXCEPTION);
99 0 : goto free;
100 : }
101 0 : BBPunfix(b->batCacheid);
102 0 : BBPunfix(g->batCacheid);
103 0 : b = sortedinput;
104 0 : g = sortedgroups;
105 : }
106 : else {
107 2 : BBPunfix(sortedgroups->batCacheid);
108 2 : BBPunfix(sortedorder->batCacheid);
109 : }
110 :
111 : //Fill in the values of the group aggregate operation
112 2 : if ((err = BATgroupaggrinit(b, g, NULL, s, &min, &max, &ngrp, &ci)) != NULL) {
113 0 : msg = createException(MAL, "geom.Collect", "%s", err);
114 0 : goto free;
115 : }
116 :
117 : //Create a new BAT column of wkb type, with length equal to the number of groups
118 2 : if ((out = COLnew(min, ATOMindex("wkb"), ngrp, TRANSIENT)) == NULL) {
119 0 : msg = createException(MAL, "geom.Collect", SQLSTATE(HY013) MAL_MALLOC_FAIL);
120 0 : goto free;
121 : }
122 :
123 2 : if (ngrp) {
124 : //All unions for output BAT
125 0 : if ((unions = GDKzalloc(sizeof(wkb *) * ngrp)) == NULL) {
126 0 : msg = createException(MAL, "geom.Collect", SQLSTATE(HY013) MAL_MALLOC_FAIL);
127 0 : BBPreclaim(out);
128 0 : goto free;
129 : }
130 :
131 : //Intermediate array for all the geometries in a group
132 0 : if ((unionGroup = GDKzalloc(sizeof(GEOSGeom) * ci.ncand)) == NULL) {
133 0 : msg = createException(MAL, "geom.Collect", SQLSTATE(HY013) MAL_MALLOC_FAIL);
134 0 : BBPreclaim(out);
135 0 : if (unions)
136 0 : GDKfree(unions);
137 0 : goto free;
138 : }
139 :
140 0 : if (g && !BATtdense(g))
141 0 : gids = (const oid *)Tloc(g, 0);
142 0 : bi = bat_iterator(b);
143 :
144 0 : for (BUN i = 0; i < ci.ncand; i++) {
145 0 : oid o = canditer_next(&ci);
146 0 : BUN p = o - b->hseqbase;
147 0 : oid grp = gids ? gids[p] : g ? min + (oid)p : 0;
148 0 : wkb *inWKB = (wkb *)BUNtvar(bi, p);
149 0 : GEOSGeom inGEOM = wkb2geos(inWKB);
150 :
151 :
152 0 : if (grp != lastGrp) {
153 0 : if (lastGrp != (oid)-1) {
154 : //Finish the previous group, move on to the next one
155 0 : collection = GEOSGeom_createCollection_r(geoshandle, geomCollectionType, unionGroup, (unsigned int) geomCount);
156 0 : GEOSSetSRID_r(geoshandle, collection,srid);
157 : //Save collection to unions array as wkb
158 0 : unions[lastGrp] = geos2wkb(collection);
159 :
160 0 : GEOSGeom_destroy_r(geoshandle, collection);
161 0 : GDKfree(unionGroup);
162 :
163 0 : if ((unionGroup = GDKzalloc(sizeof(GEOSGeom) * ci.ncand)) == NULL) {
164 0 : msg = createException(MAL, "geom.Collect", SQLSTATE(HY013) MAL_MALLOC_FAIL);
165 : //Frees
166 0 : bat_iterator_end(&bi);
167 0 : if (unions) {
168 0 : for (BUN i = 0; i < ngrp; i++)
169 0 : GDKfree(unions[i]);
170 0 : GDKfree(unions);
171 : }
172 0 : goto free;
173 : }
174 : }
175 0 : geomCount = 0;
176 0 : lastGrp = grp;
177 0 : geomCollectionType = GEOSGeom_getCollectionType(GEOSGeomTypeId_r(geoshandle, inGEOM));
178 0 : srid = GEOSGetSRID_r(geoshandle, inGEOM);
179 : }
180 0 : unionGroup[geomCount] = inGEOM;
181 0 : geomCount += 1;
182 0 : if (geomCollectionType != GEOS_GEOMETRYCOLLECTION && GEOSGeom_getCollectionType(GEOSGeomTypeId_r(geoshandle, inGEOM)) != geomCollectionType)
183 0 : geomCollectionType = GEOS_GEOMETRYCOLLECTION;
184 : }
185 : //Last collection
186 0 : collection = GEOSGeom_createCollection_r(geoshandle, geomCollectionType, unionGroup, (unsigned int) geomCount);
187 0 : GEOSSetSRID_r(geoshandle, collection,srid);
188 0 : unions[lastGrp] = geos2wkb(collection);
189 :
190 0 : GEOSGeom_destroy_r(geoshandle, collection);
191 0 : GDKfree(unionGroup);
192 :
193 0 : if (BUNappendmulti(out, unions, ngrp, false) != GDK_SUCCEED) {
194 0 : msg = createException(MAL, "geom.Union", SQLSTATE(38000) "BUNappend operation failed");
195 0 : bat_iterator_end(&bi);
196 0 : if (unions) {
197 0 : for (BUN i = 0; i < ngrp; i++)
198 0 : GDKfree(unions[i]);
199 0 : GDKfree(unions);
200 : }
201 0 : goto free;
202 : }
203 :
204 0 : bat_iterator_end(&bi);
205 0 : for (BUN i = 0; i < ngrp; i++)
206 0 : GDKfree(unions[i]);
207 0 : GDKfree(unions);
208 :
209 : }
210 2 : *outid = out->batCacheid;
211 2 : BBPkeepref(out);
212 2 : BBPunfix(b->batCacheid);
213 2 : if (g)
214 2 : BBPunfix(g->batCacheid);
215 2 : if (s)
216 0 : BBPunfix(s->batCacheid);
217 : return MAL_SUCCEED;
218 0 : free:
219 0 : if (b)
220 0 : BBPunfix(b->batCacheid);
221 0 : if (g)
222 0 : BBPunfix(g->batCacheid);
223 0 : if (s)
224 0 : BBPunfix(s->batCacheid);
225 0 : BBPreclaim(out);
226 : return msg;
227 : }
228 :
229 : str
230 2 : wkbCollectAggrSubGrouped(bat *out, const bat *bid, const bat *gid, const bat *eid, const bit *skip_nils)
231 : {
232 2 : return wkbCollectAggrSubGroupedCand(out, bid, gid, eid, NULL, skip_nils);
233 : }
234 :
235 : str
236 5 : wkbCollectAggr (wkb **out, const bat *bid) {
237 5 : str msg = MAL_SUCCEED;
238 5 : BAT *b = NULL;
239 5 : GEOSGeom *unionGroup = NULL, collection;
240 5 : int geomCollectionType = -1;
241 :
242 5 : if ((b = BATdescriptor(*bid)) == NULL) {
243 0 : msg = createException(MAL, "geom.Collect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
244 0 : return msg;
245 : }
246 :
247 5 : BUN count = BATcount(b);
248 :
249 5 : if ((unionGroup = GDKzalloc(sizeof(GEOSGeom) * count)) == NULL) {
250 0 : msg = createException(MAL, "geom.Collect", SQLSTATE(HY013) MAL_MALLOC_FAIL);
251 0 : BBPunfix(b->batCacheid);
252 0 : return msg;
253 : }
254 5 : int srid = -1;
255 :
256 5 : BATiter bi = bat_iterator(b);
257 18 : for (BUN i = 0; i < count; i++) {
258 13 : oid p = i + b->hseqbase;
259 13 : wkb *inWKB = (wkb *)BUNtvar(bi, p);
260 13 : unionGroup[i] = wkb2geos(inWKB);
261 13 : if (srid == -1)
262 5 : srid = GEOSGetSRID_r(geoshandle, unionGroup[i]);
263 :
264 : //Set collection type on first geometry
265 13 : if (geomCollectionType == -1)
266 18 : geomCollectionType = GEOSGeom_getCollectionType(GEOSGeomTypeId_r(geoshandle, unionGroup[i]));
267 : //Then, check if we need to change it a Geometry collection (if the current geometry is different from the previous type)
268 18 : if (geomCollectionType != GEOS_GEOMETRYCOLLECTION && GEOSGeom_getCollectionType(GEOSGeomTypeId_r(geoshandle, unionGroup[i])) != geomCollectionType)
269 6 : geomCollectionType = GEOS_GEOMETRYCOLLECTION;
270 : }
271 5 : collection = GEOSGeom_createCollection_r(geoshandle, geomCollectionType, unionGroup, (unsigned int) count);
272 5 : GEOSSetSRID_r(geoshandle, collection,srid);
273 : //Result
274 5 : (*out) = geos2wkb(collection);
275 5 : if (*out == NULL)
276 0 : msg = createException(MAL, "geom.ConvexHull", SQLSTATE(38000) "Geos operation geos2wkb failed");
277 :
278 : // Cleanup
279 : // Data ownership has been transferred from unionGroup elements to
280 : // collection. Check libgeos GEOSGeom_createCollection_r(geoshandle, ) for more.
281 5 : bat_iterator_end(&bi);
282 5 : GEOSGeom_destroy_r(geoshandle, collection);
283 5 : if (unionGroup)
284 5 : GDKfree(unionGroup);
285 5 : BBPunfix(b->batCacheid);
286 :
287 5 : return msg;
288 : }
289 :
290 : static str
291 13 : wkbCollect (wkb **out, wkb * const *a, wkb * const *b) {
292 13 : str err = MAL_SUCCEED;
293 13 : GEOSGeom collection;
294 : /* geom_a and geom_b */
295 13 : GEOSGeom geoms[2] = {NULL, NULL};
296 13 : int type_a, type_b;
297 :
298 13 : if ((err = wkbGetCompatibleGeometries(a, b, &geoms[0], &geoms[1])) != MAL_SUCCEED)
299 : return err;
300 :
301 : //int srid = GEOSGetSRID_r(geoshandle, ga);
302 13 : type_a = GEOSGeomTypeId_r(geoshandle, geoms[0]);
303 13 : type_b = GEOSGeomTypeId_r(geoshandle, geoms[1]);
304 :
305 : /* NOTE: geoms will be moved to collection. no need for cleanup */
306 13 : if (type_a == type_b)
307 12 : collection = GEOSGeom_createCollection_r(geoshandle, GEOSGeom_getCollectionType(type_a), geoms, (unsigned int) 2);
308 : else
309 7 : collection = GEOSGeom_createCollection_r(geoshandle, GEOS_GEOMETRYCOLLECTION, geoms, (unsigned int) 2);
310 :
311 13 : if ((*out = geos2wkb(collection)) == NULL)
312 0 : err = createException(MAL, "geom.Collect", SQLSTATE(38000) "Geos operation geos2wkb failed");
313 :
314 13 : GEOSGeom_destroy_r(geoshandle, collection);
315 :
316 13 : return err;
317 : }
318 : /**
319 : * Start of old geom module
320 : **/
321 :
322 : int TYPE_mbr;
323 :
324 : static inline int
325 1 : geometryHasZ(int info)
326 : {
327 1 : return (info & 0x02);
328 : }
329 :
330 : static inline int
331 1 : geometryHasM(int info)
332 : {
333 1 : return (info & 0x01);
334 : }
335 :
336 : /* the first argument in the functions is the return variable */
337 :
338 : #ifdef HAVE_PROJ
339 :
340 : /* math.h files do not have M_PI defined */
341 : #ifndef M_PI
342 : #define M_PI ((double) 3.14159265358979323846) /* pi */
343 : #endif
344 :
345 : //TODO Remove?
346 : /** convert degrees to radians */
347 : /*static inline void
348 : degrees2radians(double *x, double *y, double *z)
349 : {
350 : double val = M_PI / 180.0;
351 : *x *= val;
352 : *y *= val;
353 : *z *= val;
354 : }*/
355 :
356 : //TODO Remove?
357 : /** convert radians to degrees */
358 : /*static inline void
359 : radians2degrees(double *x, double *y, double *z)
360 : {
361 : double val = 180.0 / M_PI;
362 : *x *= val;
363 : *y *= val;
364 : *z *= val;
365 : }*/
366 :
367 : static str
368 36 : transformCoordSeq(int idx, int coordinatesNum, PJ *P, const GEOSCoordSequence *gcs_old, GEOSCoordSeq gcs_new)
369 : {
370 36 : double x = 0, y = 0, z = 0;
371 36 : int errorNum = 0;
372 36 : PJ_COORD c, c_out;
373 :
374 72 : if (!GEOSCoordSeq_getX_r(geoshandle, gcs_old, idx, &x) ||
375 72 : !GEOSCoordSeq_getY_r(geoshandle, gcs_old, idx, &y) ||
376 0 : (coordinatesNum > 2 && !GEOSCoordSeq_getZ_r(geoshandle, gcs_old, idx, &z)))
377 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos cannot get coordinates");
378 :
379 36 : c.lpzt.lam=x;
380 36 : c.lpzt.phi=y;
381 36 : c.lpzt.z=z;
382 36 : c.lpzt.t = HUGE_VAL;
383 :
384 36 : c_out = proj_trans(P, PJ_FWD, c);
385 :
386 36 : errorNum = proj_errno(P);
387 36 : if (errorNum != 0) {
388 0 : if (coordinatesNum > 2)
389 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos cannot transform point (%f %f %f): %s\n", x, y, z, proj_errno_string(errorNum));
390 : else
391 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos cannot transform point (%f %f): %s\n", x, y, proj_errno_string(errorNum));
392 : }
393 :
394 72 : if (!GEOSCoordSeq_setX_r(geoshandle, gcs_new, idx,c_out.xy.x) ||
395 72 : !GEOSCoordSeq_setY_r(geoshandle, gcs_new, idx,c_out.xy.y) ||
396 0 : (coordinatesNum > 2 && !GEOSCoordSeq_setZ_r(geoshandle, gcs_new, idx, z)))
397 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos cannot set coordinates");
398 :
399 : return MAL_SUCCEED;
400 : }
401 :
402 : str
403 11 : transformPoint(GEOSGeometry **transformedGeometry, const GEOSGeometry *geosGeometry, PJ *P)
404 : {
405 11 : int coordinatesNum = 0;
406 11 : const GEOSCoordSequence *gcs_old;
407 11 : GEOSCoordSeq gcs_new;
408 11 : str ret = MAL_SUCCEED;
409 :
410 11 : *transformedGeometry = NULL;
411 :
412 : /* get the number of coordinates the geometry has */
413 11 : coordinatesNum = GEOSGeom_getCoordinateDimension_r(geoshandle, geosGeometry);
414 : /* get the coordinates of the points comprising the geometry */
415 11 : gcs_old = GEOSGeom_getCoordSeq_r(geoshandle, geosGeometry);
416 :
417 11 : if (gcs_old == NULL)
418 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
419 :
420 : /* create the coordinates sequence for the transformed geometry */
421 11 : gcs_new = GEOSCoordSeq_create_r(geoshandle, 1, coordinatesNum);
422 11 : if (gcs_new == NULL)
423 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
424 :
425 : /* create the transformed coordinates */
426 11 : ret = transformCoordSeq(0, coordinatesNum, P, gcs_old, gcs_new);
427 11 : if (ret != MAL_SUCCEED) {
428 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
429 0 : return ret;
430 : }
431 :
432 : /* create the geometry from the coordinates sequence */
433 11 : *transformedGeometry = GEOSGeom_createPoint_r(geoshandle, gcs_new);
434 11 : if (*transformedGeometry == NULL) {
435 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
436 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
437 : }
438 :
439 : return MAL_SUCCEED;
440 : }
441 :
442 : str
443 7 : transformLine(GEOSCoordSeq *gcs_new, const GEOSGeometry *geosGeometry, PJ *P)
444 : {
445 7 : int coordinatesNum = 0;
446 7 : const GEOSCoordSequence *gcs_old;
447 7 : unsigned int pointsNum = 0, i = 0;
448 7 : str ret = MAL_SUCCEED;
449 :
450 : /* get the number of coordinates the geometry has */
451 7 : coordinatesNum = GEOSGeom_getCoordinateDimension_r(geoshandle, geosGeometry);
452 : /* get the coordinates of the points comprising the geometry */
453 7 : gcs_old = GEOSGeom_getCoordSeq_r(geoshandle, geosGeometry);
454 :
455 7 : if (gcs_old == NULL)
456 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
457 :
458 : /* get the number of points in the geometry */
459 7 : if (!GEOSCoordSeq_getSize_r(geoshandle, gcs_old, &pointsNum))
460 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getSize failed");
461 :
462 : /* create the coordinates sequence for the transformed geometry */
463 7 : *gcs_new = GEOSCoordSeq_create_r(geoshandle, pointsNum, coordinatesNum);
464 7 : if (*gcs_new == NULL)
465 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSCoordSeq_create failed");
466 :
467 : /* create the transformed coordinates */
468 32 : for (i = 0; i < pointsNum; i++) {
469 25 : ret = transformCoordSeq(i, coordinatesNum, P, gcs_old, *gcs_new);
470 25 : if (ret != MAL_SUCCEED) {
471 0 : GEOSCoordSeq_destroy_r(geoshandle, *gcs_new);
472 0 : *gcs_new = NULL;
473 0 : return ret;
474 : }
475 : }
476 :
477 : return MAL_SUCCEED;
478 : }
479 :
480 : str
481 4 : transformLineString(GEOSGeometry **transformedGeometry, const GEOSGeometry *geosGeometry, PJ *P)
482 : {
483 4 : GEOSCoordSeq coordSeq;
484 4 : str ret = MAL_SUCCEED;
485 :
486 4 : ret = transformLine(&coordSeq, geosGeometry, P);
487 4 : if (ret != MAL_SUCCEED) {
488 0 : *transformedGeometry = NULL;
489 0 : return ret;
490 : }
491 :
492 : /* create the geometry from the coordinates sequence */
493 4 : *transformedGeometry = GEOSGeom_createLineString_r(geoshandle, coordSeq);
494 4 : if (*transformedGeometry == NULL) {
495 0 : GEOSCoordSeq_destroy_r(geoshandle, coordSeq);
496 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSGeom_createLineString failed");
497 : }
498 :
499 : return ret;
500 : }
501 :
502 : str
503 3 : transformLinearRing(GEOSGeometry **transformedGeometry, const GEOSGeometry *geosGeometry, PJ *P)
504 : {
505 3 : GEOSCoordSeq coordSeq = NULL;
506 3 : str ret = MAL_SUCCEED;
507 :
508 3 : ret = transformLine(&coordSeq, geosGeometry, P);
509 3 : if (ret != MAL_SUCCEED) {
510 0 : *transformedGeometry = NULL;
511 0 : return ret;
512 : }
513 :
514 : /* create the geometry from the coordinates sequence */
515 3 : *transformedGeometry = GEOSGeom_createLinearRing_r(geoshandle, coordSeq);
516 3 : if (*transformedGeometry == NULL) {
517 0 : GEOSCoordSeq_destroy_r(geoshandle, coordSeq);
518 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSGeom_createLineString failed");
519 : }
520 :
521 : return ret;
522 : }
523 :
524 : str
525 3 : transformPolygon(GEOSGeometry **transformedGeometry, const GEOSGeometry *geosGeometry, PJ *P, int srid)
526 : {
527 3 : const GEOSGeometry *exteriorRingGeometry;
528 3 : GEOSGeometry *transformedExteriorRingGeometry = NULL;
529 3 : GEOSGeometry **transformedInteriorRingGeometries = NULL;
530 3 : int numInteriorRings = 0, i = 0;
531 3 : str ret = MAL_SUCCEED;
532 :
533 : /* get the exterior ring of the polygon */
534 3 : exteriorRingGeometry = GEOSGetExteriorRing_r(geoshandle, geosGeometry);
535 3 : if (exteriorRingGeometry == NULL) {
536 0 : *transformedGeometry = NULL;
537 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSGetExteriorRing failed");
538 : }
539 :
540 3 : ret = transformLinearRing(&transformedExteriorRingGeometry, exteriorRingGeometry, P);
541 3 : if (ret != MAL_SUCCEED) {
542 0 : *transformedGeometry = NULL;
543 0 : return ret;
544 : }
545 3 : GEOSSetSRID_r(geoshandle, transformedExteriorRingGeometry, srid);
546 :
547 3 : numInteriorRings = GEOSGetNumInteriorRings_r(geoshandle, geosGeometry);
548 3 : if (numInteriorRings == -1) {
549 0 : *transformedGeometry = NULL;
550 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
551 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSGetInteriorRingN failed.");
552 : }
553 :
554 3 : if(numInteriorRings > 0)
555 : {
556 : /* iterate over the interiorRing and transform each one of them */
557 0 : transformedInteriorRingGeometries = GDKmalloc(numInteriorRings * sizeof(GEOSGeometry *));
558 0 : if (transformedInteriorRingGeometries == NULL) {
559 0 : *transformedGeometry = NULL;
560 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
561 0 : throw(MAL, "geom.Transform", SQLSTATE(HY013) MAL_MALLOC_FAIL);
562 : }
563 0 : for (i = 0; i < numInteriorRings; i++) {
564 0 : ret = transformLinearRing(&transformedInteriorRingGeometries[i], GEOSGetInteriorRingN_r(geoshandle, geosGeometry, i), P);
565 0 : if (ret != MAL_SUCCEED) {
566 0 : while (--i >= 0)
567 0 : GEOSGeom_destroy_r(geoshandle, transformedInteriorRingGeometries[i]);
568 0 : GDKfree(transformedInteriorRingGeometries);
569 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
570 0 : *transformedGeometry = NULL;
571 0 : return ret;
572 : }
573 0 : GEOSSetSRID_r(geoshandle, transformedInteriorRingGeometries[i], srid);
574 : }
575 : }
576 :
577 3 : *transformedGeometry = GEOSGeom_createPolygon_r(geoshandle, transformedExteriorRingGeometry, transformedInteriorRingGeometries, numInteriorRings);
578 :
579 3 : if (*transformedGeometry == NULL) {
580 0 : for (i = 0; i < numInteriorRings; i++)
581 0 : GEOSGeom_destroy_r(geoshandle, transformedInteriorRingGeometries[i]);
582 0 : ret = createException(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSGeom_createPolygon failed");
583 : }
584 3 : GDKfree(transformedInteriorRingGeometries);
585 : //GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
586 3 : return ret;
587 : }
588 :
589 : str
590 3 : transformMultiGeometry(GEOSGeometry **transformedGeometry, const GEOSGeometry *geosGeometry, PJ *P, int srid, int geometryType)
591 : {
592 3 : int geometriesNum, subGeometryType, i;
593 3 : GEOSGeometry **transformedMultiGeometries = NULL;
594 3 : const GEOSGeometry *multiGeometry = NULL;
595 3 : str ret = MAL_SUCCEED;
596 :
597 3 : geometriesNum = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
598 3 : if (geometriesNum == -1)
599 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSGetNumGeometries failed");
600 3 : transformedMultiGeometries = GDKmalloc(geometriesNum * sizeof(GEOSGeometry *));
601 3 : if (transformedMultiGeometries == NULL)
602 0 : throw(MAL, "geom.Transform", SQLSTATE(HY013) MAL_MALLOC_FAIL);
603 :
604 18 : for (i = 0; i < geometriesNum; i++) {
605 15 : if ((multiGeometry = GEOSGetGeometryN_r(geoshandle, geosGeometry, i)) == NULL)
606 0 : ret = createException(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSGetGeometryN failed");
607 15 : else if ((subGeometryType = GEOSGeomTypeId_r(geoshandle, multiGeometry) + 1) == 0)
608 0 : ret = createException(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSGeomTypeId failed");
609 : else {
610 15 : switch (subGeometryType) {
611 10 : case wkbPoint_mdb:
612 10 : ret = transformPoint(&transformedMultiGeometries[i], multiGeometry, P);
613 10 : break;
614 3 : case wkbLineString_mdb:
615 3 : ret = transformLineString(&transformedMultiGeometries[i], multiGeometry, P);
616 3 : break;
617 0 : case wkbLinearRing_mdb:
618 0 : ret = transformLinearRing(&transformedMultiGeometries[i], multiGeometry, P);
619 0 : break;
620 2 : case wkbPolygon_mdb:
621 2 : ret = transformPolygon(&transformedMultiGeometries[i], multiGeometry, P, srid);
622 2 : break;
623 0 : default:
624 0 : ret = createException(MAL, "geom.Transform", SQLSTATE(38000) "Geos unknown geometry type");
625 0 : break;
626 : }
627 : }
628 :
629 15 : if (ret != MAL_SUCCEED) {
630 0 : while (--i >= 0)
631 0 : GEOSGeom_destroy_r(geoshandle, transformedMultiGeometries[i]);
632 0 : GDKfree(transformedMultiGeometries);
633 0 : *transformedGeometry = NULL;
634 0 : return ret;
635 : }
636 :
637 15 : GEOSSetSRID_r(geoshandle, transformedMultiGeometries[i], srid);
638 : }
639 :
640 3 : *transformedGeometry = GEOSGeom_createCollection_r(geoshandle, geometryType - 1, transformedMultiGeometries, geometriesNum);
641 3 : if (*transformedGeometry == NULL) {
642 0 : for (i = 0; i < geometriesNum; i++)
643 0 : GEOSGeom_destroy_r(geoshandle, transformedMultiGeometries[i]);
644 0 : ret = createException(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation GEOSGeom_createCollection failed");
645 : }
646 3 : GDKfree(transformedMultiGeometries);
647 :
648 3 : return ret;
649 : }
650 : #endif
651 :
652 : /* It gets a geometry and transforms its coordinates to the provided srid */
653 : str
654 7 : wkbTransform(wkb **transformedWKB, wkb **geomWKB, int *srid_src, int *srid_dst, char **proj4_src_str, char **proj4_dst_str)
655 : {
656 : #ifndef HAVE_PROJ
657 : *transformedWKB = NULL;
658 : (void) geomWKB;
659 : (void) srid_src;
660 : (void) srid_dst;
661 : (void) proj4_src_str;
662 : (void) proj4_dst_str;
663 : throw(MAL, "geom.Transform", SQLSTATE(38000) "PROJ library not found");
664 : #else
665 7 : PJ *P;
666 7 : GEOSGeom geosGeometry, transformedGeosGeometry;
667 7 : int geometryType = -1;
668 :
669 7 : str ret = MAL_SUCCEED;
670 :
671 7 : if (*geomWKB == NULL)
672 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Geos wkb format is null");
673 :
674 7 : if (is_wkb_nil(*geomWKB) ||
675 7 : is_int_nil(*srid_src) ||
676 7 : is_int_nil(*srid_dst) ||
677 7 : strNil(*proj4_src_str) ||
678 7 : strNil(*proj4_dst_str)) {
679 0 : if ((*transformedWKB = wkbNULLcopy()) == NULL)
680 0 : throw(MAL, "geom.Transform", SQLSTATE(HY013) MAL_MALLOC_FAIL);
681 : return MAL_SUCCEED;
682 : }
683 :
684 7 : if (strcmp(*proj4_src_str, "null") == 0)
685 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Cannot find in spatial_ref_sys srid %d\n", *srid_src);
686 7 : if (strcmp(*proj4_dst_str, "null") == 0)
687 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "Cannot find in spatial_ref_sys srid %d\n", *srid_dst);
688 7 : if (strcmp(*proj4_src_str, *proj4_dst_str) == 0) {
689 1 : if ((*transformedWKB = wkbCopy(*geomWKB)) == NULL)
690 0 : throw(MAL, "geom.Transform", SQLSTATE(HY013) MAL_MALLOC_FAIL);
691 : return MAL_SUCCEED;
692 : }
693 : //Create PROJ transformation object with PROJ strings passed as argument
694 6 : P = proj_create_crs_to_crs(PJ_DEFAULT_CTX,
695 : *proj4_src_str,
696 : *proj4_dst_str,
697 : NULL);
698 6 : if (P==0)
699 0 : throw(MAL, "geom.Transform", SQLSTATE(38000) "PROJ initialization failed");
700 :
701 : /* get the geosGeometry from the wkb */
702 6 : geosGeometry = wkb2geos(*geomWKB);
703 : /* get the type of the geometry */
704 6 : geometryType = GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1;
705 :
706 : //TODO: No collection?
707 6 : switch (geometryType) {
708 1 : case wkbPoint_mdb:
709 1 : ret = transformPoint(&transformedGeosGeometry, geosGeometry, P);
710 1 : break;
711 1 : case wkbLineString_mdb:
712 1 : ret = transformLineString(&transformedGeosGeometry, geosGeometry, P);
713 1 : break;
714 0 : case wkbLinearRing_mdb:
715 0 : ret = transformLinearRing(&transformedGeosGeometry, geosGeometry, P);
716 0 : break;
717 1 : case wkbPolygon_mdb:
718 1 : ret = transformPolygon(&transformedGeosGeometry, geosGeometry, P, *srid_dst);
719 1 : break;
720 3 : case wkbMultiPoint_mdb:
721 : case wkbMultiLineString_mdb:
722 : case wkbMultiPolygon_mdb:
723 3 : ret = transformMultiGeometry(&transformedGeosGeometry, geosGeometry, P, *srid_dst, geometryType);
724 3 : break;
725 0 : default:
726 0 : transformedGeosGeometry = NULL;
727 0 : ret = createException(MAL, "geom.Transform", SQLSTATE(38000) "Geos unknown geometry type");
728 : }
729 :
730 6 : if (ret == MAL_SUCCEED && transformedGeosGeometry) {
731 : /* set the new srid */
732 6 : GEOSSetSRID_r(geoshandle, transformedGeosGeometry, *srid_dst);
733 : /* get the wkb */
734 6 : if ((*transformedWKB = geos2wkb(transformedGeosGeometry)) == NULL)
735 0 : ret = createException(MAL, "geom.Transform", SQLSTATE(38000) "Geos operation geos2wkb failed");
736 : /* destroy the geos geometries */
737 6 : GEOSGeom_destroy_r(geoshandle, transformedGeosGeometry);
738 : }
739 6 : proj_destroy(P);
740 6 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
741 :
742 6 : return ret;
743 : #endif
744 : }
745 :
746 : //gets a coord seq and forces it to have dim dimensions adding or removing extra dimensions
747 : static str
748 0 : forceDimCoordSeq(int idx, int coordinatesNum, int dim, const GEOSCoordSequence *gcs_old, GEOSCoordSeq gcs_new)
749 : {
750 0 : double x = 0, y = 0, z = 0;
751 :
752 : //get the coordinates
753 0 : if (!GEOSCoordSeq_getX_r(geoshandle, gcs_old, idx, &x))
754 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getX failed");
755 0 : if (!GEOSCoordSeq_getY_r(geoshandle, gcs_old, idx, &y))
756 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getY failed");
757 0 : if (coordinatesNum > 2 && dim > 2 && //read it only if needed (dim >2)
758 0 : !GEOSCoordSeq_getZ_r(geoshandle, gcs_old, idx, &z))
759 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getZ failed");
760 :
761 : //create the new coordinates
762 0 : if (!GEOSCoordSeq_setX_r(geoshandle, gcs_new, idx, x))
763 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setX failed");
764 0 : if (!GEOSCoordSeq_setY_r(geoshandle, gcs_new, idx, y))
765 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setY failed");
766 0 : if (dim > 2)
767 0 : if (!GEOSCoordSeq_setZ_r(geoshandle, gcs_new, idx, z))
768 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setZ failed");
769 : return MAL_SUCCEED;
770 : }
771 :
772 : static str
773 0 : forceDimPoint(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, int dim)
774 : {
775 0 : int coordinatesNum = 0;
776 0 : const GEOSCoordSequence *gcs_old;
777 0 : GEOSCoordSeq gcs_new;
778 0 : str ret = MAL_SUCCEED;
779 :
780 : /* get the number of coordinates the geometry has */
781 0 : coordinatesNum = GEOSGeom_getCoordinateDimension_r(geoshandle, geosGeometry);
782 : /* get the coordinates of the points comprising the geometry */
783 0 : gcs_old = GEOSGeom_getCoordSeq_r(geoshandle, geosGeometry);
784 :
785 0 : if (gcs_old == NULL) {
786 0 : *outGeometry = NULL;
787 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
788 : }
789 :
790 : /* create the coordinates sequence for the translated geometry */
791 0 : if ((gcs_new = GEOSCoordSeq_create_r(geoshandle, 1, dim)) == NULL) {
792 0 : *outGeometry = NULL;
793 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSCoordSeq_create failed");
794 : }
795 :
796 : /* create the translated coordinates */
797 0 : ret = forceDimCoordSeq(0, coordinatesNum, dim, gcs_old, gcs_new);
798 0 : if (ret != MAL_SUCCEED) {
799 0 : *outGeometry = NULL;
800 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
801 0 : return ret;
802 : }
803 :
804 : /* create the geometry from the coordinates sequence */
805 0 : *outGeometry = GEOSGeom_createPoint_r(geoshandle, gcs_new);
806 0 : if (*outGeometry == NULL) {
807 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
808 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSGeom_createPoint failed");
809 : }
810 :
811 : return MAL_SUCCEED;
812 : }
813 :
814 : static str
815 0 : forceDimLineString(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, int dim)
816 : {
817 0 : int coordinatesNum = 0;
818 0 : const GEOSCoordSequence *gcs_old;
819 0 : GEOSCoordSeq gcs_new;
820 0 : unsigned int pointsNum = 0, i = 0;
821 0 : str ret = MAL_SUCCEED;
822 :
823 : /* get the number of coordinates the geometry has */
824 0 : coordinatesNum = GEOSGeom_getCoordinateDimension_r(geoshandle, geosGeometry);
825 : /* get the coordinates of the points comprising the geometry */
826 0 : gcs_old = GEOSGeom_getCoordSeq_r(geoshandle, geosGeometry);
827 :
828 0 : if (gcs_old == NULL)
829 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
830 :
831 : /* get the number of points in the geometry */
832 0 : if (!GEOSCoordSeq_getSize_r(geoshandle, gcs_old, &pointsNum))
833 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getSize failed");
834 :
835 : /* create the coordinates sequence for the translated geometry */
836 0 : gcs_new = GEOSCoordSeq_create_r(geoshandle, pointsNum, dim);
837 0 : if (gcs_new == NULL)
838 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSCoordSeq_create failed");
839 :
840 : /* create the translated coordinates */
841 0 : for (i = 0; i < pointsNum; i++) {
842 0 : ret = forceDimCoordSeq(i, coordinatesNum, dim, gcs_old, gcs_new);
843 0 : if (ret != MAL_SUCCEED) {
844 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
845 0 : return ret;
846 : }
847 : }
848 :
849 : //create the geometry from the translated coordinates sequence
850 0 : *outGeometry = GEOSGeom_createLineString_r(geoshandle, gcs_new);
851 0 : if (*outGeometry == NULL) {
852 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
853 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSGeom_createLineString failed");
854 : }
855 :
856 : return MAL_SUCCEED;
857 :
858 : }
859 :
860 : //Although linestring and linearRing are essentially the same we need to distinguish that when creating polygon from the rings
861 : static str
862 0 : forceDimLinearRing(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, int dim)
863 : {
864 0 : int coordinatesNum = 0;
865 0 : const GEOSCoordSequence *gcs_old;
866 0 : GEOSCoordSeq gcs_new;
867 0 : unsigned int pointsNum = 0, i = 0;
868 0 : str ret = MAL_SUCCEED;
869 :
870 : /* get the number of coordinates the geometry has */
871 0 : coordinatesNum = GEOSGeom_getCoordinateDimension_r(geoshandle, geosGeometry);
872 : /* get the coordinates of the points comprising the geometry */
873 0 : gcs_old = GEOSGeom_getCoordSeq_r(geoshandle, geosGeometry);
874 :
875 0 : if (gcs_old == NULL)
876 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
877 :
878 : /* get the number of points in the geometry */
879 0 : if (!GEOSCoordSeq_getSize_r(geoshandle, gcs_old, &pointsNum))
880 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getSize failed");
881 :
882 : /* create the coordinates sequence for the translated geometry */
883 0 : gcs_new = GEOSCoordSeq_create_r(geoshandle, pointsNum, dim);
884 0 : if (gcs_new == NULL)
885 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSCoordSeq_create failed");
886 :
887 : /* create the translated coordinates */
888 0 : for (i = 0; i < pointsNum; i++) {
889 0 : ret = forceDimCoordSeq(i, coordinatesNum, dim, gcs_old, gcs_new);
890 0 : if (ret != MAL_SUCCEED) {
891 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
892 0 : return ret;
893 : }
894 : }
895 :
896 : //create the geometry from the translated coordinates sequence
897 0 : *outGeometry = GEOSGeom_createLinearRing_r(geoshandle, gcs_new);
898 0 : if (*outGeometry == NULL) {
899 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
900 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSGeom_createLinearRing failed");
901 : }
902 :
903 : return MAL_SUCCEED;
904 : }
905 :
906 : static str
907 0 : forceDimPolygon(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, int dim)
908 : {
909 0 : const GEOSGeometry *exteriorRingGeometry;
910 0 : GEOSGeometry *transformedExteriorRingGeometry = NULL;
911 0 : GEOSGeometry **transformedInteriorRingGeometries = NULL;
912 0 : int numInteriorRings = 0, i = 0;
913 0 : str ret = MAL_SUCCEED;
914 :
915 : /* get the exterior ring of the polygon */
916 0 : exteriorRingGeometry = GEOSGetExteriorRing_r(geoshandle, geosGeometry);
917 0 : if (!exteriorRingGeometry) {
918 0 : *outGeometry = NULL;
919 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSGetExteriorRing failed");
920 : }
921 :
922 0 : if ((ret = forceDimLinearRing(&transformedExteriorRingGeometry, exteriorRingGeometry, dim)) != MAL_SUCCEED) {
923 0 : *outGeometry = NULL;
924 0 : return ret;
925 : }
926 :
927 0 : numInteriorRings = GEOSGetNumInteriorRings_r(geoshandle, geosGeometry);
928 0 : if (numInteriorRings == -1) {
929 0 : *outGeometry = NULL;
930 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
931 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSGetInteriorRingN failed.");
932 : }
933 :
934 : /* iterate over the interiorRing and translate each one of them */
935 0 : transformedInteriorRingGeometries = GDKmalloc(numInteriorRings * sizeof(GEOSGeometry *));
936 0 : if (transformedInteriorRingGeometries == NULL) {
937 0 : *outGeometry = NULL;
938 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
939 0 : throw(MAL, "geom.ForceDim", SQLSTATE(HY013) MAL_MALLOC_FAIL);
940 : }
941 0 : for (i = 0; i < numInteriorRings; i++) {
942 0 : if ((ret = forceDimLinearRing(&transformedInteriorRingGeometries[i], GEOSGetInteriorRingN_r(geoshandle, geosGeometry, i), dim)) != MAL_SUCCEED) {
943 0 : while (--i >= 0)
944 0 : GEOSGeom_destroy_r(geoshandle, transformedInteriorRingGeometries[i]);
945 0 : GDKfree(transformedInteriorRingGeometries);
946 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
947 0 : *outGeometry = NULL;
948 0 : return ret;
949 : }
950 : }
951 :
952 0 : *outGeometry = GEOSGeom_createPolygon_r(geoshandle, transformedExteriorRingGeometry, transformedInteriorRingGeometries, numInteriorRings);
953 0 : if (*outGeometry == NULL) {
954 0 : for (i = 0; i < numInteriorRings; i++)
955 0 : GEOSGeom_destroy_r(geoshandle, transformedInteriorRingGeometries[i]);
956 0 : ret = createException(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSGeom_createPolygon failed");
957 : }
958 0 : GDKfree(transformedInteriorRingGeometries);
959 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
960 :
961 0 : return ret;
962 : }
963 :
964 : static str forceDimGeometry(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, int dim);
965 : static str
966 0 : forceDimMultiGeometry(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, int dim)
967 : {
968 0 : int geometriesNum, i;
969 0 : GEOSGeometry **transformedMultiGeometries = NULL;
970 0 : str err = MAL_SUCCEED;
971 :
972 0 : geometriesNum = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
973 0 : transformedMultiGeometries = GDKmalloc(geometriesNum * sizeof(GEOSGeometry *));
974 0 : if (transformedMultiGeometries == NULL)
975 0 : throw(MAL, "geom.ForceDim", SQLSTATE(HY013) MAL_MALLOC_FAIL);
976 :
977 : //In order to have the geometries in the output in the same order as in the input
978 : //we should read them and put them in the area in reverse order
979 0 : for (i = geometriesNum - 1; i >= 0; i--) {
980 0 : const GEOSGeometry *multiGeometry = GEOSGetGeometryN_r(geoshandle, geosGeometry, i);
981 :
982 0 : if ((err = forceDimGeometry(&transformedMultiGeometries[i], multiGeometry, dim)) != MAL_SUCCEED) {
983 0 : while (++i < geometriesNum)
984 0 : GEOSGeom_destroy_r(geoshandle, transformedMultiGeometries[i]);
985 0 : GDKfree(transformedMultiGeometries);
986 0 : *outGeometry = NULL;
987 0 : return err;
988 : }
989 : }
990 :
991 0 : *outGeometry = GEOSGeom_createCollection_r(geoshandle, GEOSGeomTypeId_r(geoshandle, geosGeometry), transformedMultiGeometries, geometriesNum);
992 0 : if (*outGeometry == NULL) {
993 0 : for (i = 0; i < geometriesNum; i++)
994 0 : GEOSGeom_destroy_r(geoshandle, transformedMultiGeometries[i]);
995 0 : err = createException(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation GEOSGeom_createCollection failed");
996 : }
997 0 : GDKfree(transformedMultiGeometries);
998 :
999 0 : return err;
1000 : }
1001 :
1002 : static str
1003 0 : forceDimGeometry(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, int dim)
1004 : {
1005 0 : int geometryType = GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1;
1006 :
1007 : //check the type of the geometry
1008 0 : switch (geometryType) {
1009 0 : case wkbPoint_mdb:
1010 0 : return forceDimPoint(outGeometry, geosGeometry, dim);
1011 0 : case wkbLineString_mdb:
1012 : case wkbLinearRing_mdb:
1013 0 : return forceDimLineString(outGeometry, geosGeometry, dim);
1014 0 : case wkbPolygon_mdb:
1015 0 : return forceDimPolygon(outGeometry, geosGeometry, dim);
1016 0 : case wkbMultiPoint_mdb:
1017 : case wkbMultiLineString_mdb:
1018 : case wkbMultiPolygon_mdb:
1019 : case wkbGeometryCollection_mdb:
1020 0 : return forceDimMultiGeometry(outGeometry, geosGeometry, dim);
1021 0 : default:
1022 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation %s unknown geometry type", geom_type2str(geometryType, 0));
1023 : }
1024 : }
1025 :
1026 : str
1027 0 : wkbForceDim(wkb **outWKB, wkb **geomWKB, int *dim)
1028 : {
1029 0 : GEOSGeometry *outGeometry;
1030 0 : GEOSGeom geosGeometry;
1031 0 : str err;
1032 :
1033 0 : if (is_wkb_nil(*geomWKB) || is_int_nil(*dim)) {
1034 0 : if ((*outWKB = wkbNULLcopy()) == NULL)
1035 0 : throw(MAL, "geom.ForceDim", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1036 : return MAL_SUCCEED;
1037 : }
1038 :
1039 0 : geosGeometry = wkb2geos(*geomWKB);
1040 0 : if (geosGeometry == NULL) {
1041 0 : *outWKB = NULL;
1042 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation wkb2geos failed");
1043 : }
1044 :
1045 0 : if ((err = forceDimGeometry(&outGeometry, geosGeometry, *dim)) != MAL_SUCCEED) {
1046 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
1047 0 : *outWKB = NULL;
1048 0 : return err;
1049 : }
1050 :
1051 0 : GEOSSetSRID_r(geoshandle, outGeometry, GEOSGetSRID_r(geoshandle, geosGeometry));
1052 :
1053 0 : *outWKB = geos2wkb(outGeometry);
1054 :
1055 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
1056 0 : GEOSGeom_destroy_r(geoshandle, outGeometry);
1057 :
1058 0 : if (*outWKB == NULL)
1059 0 : throw(MAL, "geom.ForceDim", SQLSTATE(38000) "Geos operation geos2wkb failed");
1060 :
1061 : return MAL_SUCCEED;
1062 : }
1063 :
1064 : static str
1065 0 : segmentizePoint(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry)
1066 : {
1067 0 : const GEOSCoordSequence *gcs_old;
1068 0 : GEOSCoordSeq gcs_new;
1069 :
1070 : //nothing much to do. Just create a copy of the point
1071 : //get the coordinates
1072 0 : if ((gcs_old = GEOSGeom_getCoordSeq_r(geoshandle, geosGeometry)) == NULL) {
1073 0 : *outGeometry = NULL;
1074 0 : throw(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
1075 : }
1076 : //create a copy of it
1077 0 : if ((gcs_new = GEOSCoordSeq_clone_r(geoshandle, gcs_old)) == NULL) {
1078 0 : *outGeometry = NULL;
1079 0 : throw(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_clone failed");
1080 : }
1081 : //create the geometry from the coordinates sequence
1082 0 : *outGeometry = GEOSGeom_createPoint_r(geoshandle, gcs_new);
1083 0 : if (*outGeometry == NULL) {
1084 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1085 0 : throw(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSGeom_createPoint failed");
1086 : }
1087 :
1088 : return MAL_SUCCEED;
1089 : }
1090 :
1091 : static str
1092 0 : segmentizeLineString(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, double sz, int isRing)
1093 : {
1094 0 : int coordinatesNum = 0;
1095 0 : const GEOSCoordSequence *gcs_old;
1096 0 : GEOSCoordSeq gcs_new;
1097 0 : unsigned int pointsNum = 0, additionalPoints = 0, i = 0, j = 0;
1098 0 : double xl = 0.0, yl = 0.0, zl = 0.0;
1099 0 : double *xCoords_org, *yCoords_org, *zCoords_org;
1100 0 : str err = MAL_SUCCEED;
1101 :
1102 : //get the number of coordinates the geometry has
1103 0 : coordinatesNum = GEOSGeom_getCoordinateDimension_r(geoshandle, geosGeometry);
1104 : //get the coordinates of the points comprising the geometry
1105 0 : if ((gcs_old = GEOSGeom_getCoordSeq_r(geoshandle, geosGeometry)) == NULL) {
1106 0 : *outGeometry = NULL;
1107 0 : throw(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
1108 : }
1109 : //get the number of points in the geometry
1110 0 : if (!GEOSCoordSeq_getSize_r(geoshandle, gcs_old, &pointsNum)) {
1111 0 : *outGeometry = NULL;
1112 0 : throw(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getSize failed");
1113 : }
1114 : //store the points so that I do not have to read them multiple times using geos
1115 0 : if ((xCoords_org = GDKmalloc(pointsNum * sizeof(double))) == NULL) {
1116 0 : *outGeometry = NULL;
1117 0 : throw(MAL, "geom.Segmentize", SQLSTATE(HY013) MAL_MALLOC_FAIL " for %u double values", pointsNum);
1118 : }
1119 0 : if ((yCoords_org = GDKmalloc(pointsNum * sizeof(double))) == NULL) {
1120 0 : GDKfree(xCoords_org);
1121 0 : *outGeometry = NULL;
1122 0 : throw(MAL, "geom.Segmentize", SQLSTATE(HY013) MAL_MALLOC_FAIL " for %u double values", pointsNum);
1123 : }
1124 0 : if ((zCoords_org = GDKmalloc(pointsNum * sizeof(double))) == NULL) {
1125 0 : GDKfree(xCoords_org);
1126 0 : GDKfree(yCoords_org);
1127 0 : *outGeometry = NULL;
1128 0 : throw(MAL, "geom.Segmentize", SQLSTATE(HY013) MAL_MALLOC_FAIL " for %u double values", pointsNum);
1129 : }
1130 :
1131 0 : if (!GEOSCoordSeq_getX_r(geoshandle, gcs_old, 0, &xCoords_org[0])) {
1132 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getX failed");
1133 0 : goto bailout;
1134 : }
1135 0 : if (!GEOSCoordSeq_getY_r(geoshandle, gcs_old, 0, &yCoords_org[0])) {
1136 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getY failed");
1137 0 : goto bailout;
1138 : }
1139 0 : if (coordinatesNum > 2 && !GEOSCoordSeq_getZ_r(geoshandle, gcs_old, 0, &zCoords_org[0])) {
1140 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getZ failed");
1141 0 : goto bailout;
1142 : }
1143 :
1144 0 : xl = xCoords_org[0];
1145 0 : yl = yCoords_org[0];
1146 0 : zl = zCoords_org[0];
1147 :
1148 : //check how many new points should be added
1149 0 : for (i = 1; i < pointsNum; i++) {
1150 0 : double dist;
1151 :
1152 0 : if (!GEOSCoordSeq_getX_r(geoshandle, gcs_old, i, &xCoords_org[i])) {
1153 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getX failed");
1154 0 : goto bailout;
1155 : }
1156 0 : if (!GEOSCoordSeq_getY_r(geoshandle, gcs_old, i, &yCoords_org[i])) {
1157 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getY failed");
1158 0 : goto bailout;
1159 : }
1160 0 : if (coordinatesNum > 2 && !GEOSCoordSeq_getZ_r(geoshandle, gcs_old, i, &zCoords_org[i])) {
1161 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getZ failed");
1162 0 : goto bailout;
1163 : }
1164 :
1165 : //compute the distance of the current point to the last added one
1166 0 : while ((dist = sqrt(pow(xl - xCoords_org[i], 2) + pow(yl - yCoords_org[i], 2) + pow(zl - zCoords_org[i], 2))) > sz) {
1167 0 : TRC_DEBUG(GEOM, "Old : (%f, %f, %f) vs (%f, %f, %f) = %f\n", xl, yl, zl, xCoords_org[i], yCoords_org[i], zCoords_org[i], dist);
1168 :
1169 0 : additionalPoints++;
1170 : //compute the point
1171 0 : xl = xl + (xCoords_org[i] - xl) * sz / dist;
1172 0 : yl = yl + (yCoords_org[i] - yl) * sz / dist;
1173 0 : zl = zl + (zCoords_org[i] - zl) * sz / dist;
1174 : }
1175 :
1176 0 : xl = xCoords_org[i];
1177 0 : yl = yCoords_org[i];
1178 0 : zl = zCoords_org[i];
1179 :
1180 : }
1181 :
1182 0 : TRC_DEBUG(GEOM, "Adding %u\n", additionalPoints);
1183 :
1184 : //create the coordinates sequence for the translated geometry
1185 0 : if ((gcs_new = GEOSCoordSeq_create_r(geoshandle, pointsNum + additionalPoints, coordinatesNum)) == NULL) {
1186 0 : *outGeometry = NULL;
1187 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_create failed");
1188 0 : goto bailout;
1189 : }
1190 : //add the first point
1191 0 : if (!GEOSCoordSeq_setX_r(geoshandle, gcs_new, 0, xCoords_org[0])) {
1192 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setX failed");
1193 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1194 0 : goto bailout;
1195 : }
1196 0 : if (!GEOSCoordSeq_setY_r(geoshandle, gcs_new, 0, yCoords_org[0])) {
1197 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setY failed");
1198 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1199 0 : goto bailout;
1200 : }
1201 0 : if (coordinatesNum > 2 && !GEOSCoordSeq_setZ_r(geoshandle, gcs_new, 0, zCoords_org[0])) {
1202 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setZ failed");
1203 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1204 0 : goto bailout;
1205 : }
1206 :
1207 0 : xl = xCoords_org[0];
1208 0 : yl = yCoords_org[0];
1209 0 : zl = zCoords_org[0];
1210 :
1211 : //check and add the rest of the points
1212 0 : for (i = 1; i < pointsNum; i++) {
1213 : //compute the distance of the current point to the last added one
1214 : double dist;
1215 0 : while ((dist = sqrt(pow(xl - xCoords_org[i], 2) + pow(yl - yCoords_org[i], 2) + pow(zl - zCoords_org[i], 2))) > sz) {
1216 0 : TRC_DEBUG(GEOM, "Old: (%f, %f, %f) vs (%f, %f, %f) = %f\n", xl, yl, zl, xCoords_org[i], yCoords_org[i], zCoords_org[i], dist);
1217 :
1218 0 : assert(j < additionalPoints);
1219 :
1220 : //compute intermediate point
1221 0 : xl = xl + (xCoords_org[i] - xl) * sz / dist;
1222 0 : yl = yl + (yCoords_org[i] - yl) * sz / dist;
1223 0 : zl = zl + (zCoords_org[i] - zl) * sz / dist;
1224 :
1225 : //add the intermediate point
1226 0 : if (!GEOSCoordSeq_setX_r(geoshandle, gcs_new, i + j, xl)) {
1227 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setX failed");
1228 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1229 0 : goto bailout;
1230 : }
1231 0 : if (!GEOSCoordSeq_setY_r(geoshandle, gcs_new, i + j, yl)) {
1232 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setY failed");
1233 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1234 0 : goto bailout;
1235 : }
1236 0 : if (coordinatesNum > 2 && !GEOSCoordSeq_setZ_r(geoshandle, gcs_new, i + j, zl)) {
1237 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setZ failed");
1238 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1239 0 : goto bailout;
1240 : }
1241 :
1242 0 : j++;
1243 : }
1244 :
1245 : //add the original point
1246 0 : if (!GEOSCoordSeq_setX_r(geoshandle, gcs_new, i + j, xCoords_org[i])) {
1247 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setX failed");
1248 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1249 0 : goto bailout;
1250 : }
1251 0 : if (!GEOSCoordSeq_setY_r(geoshandle, gcs_new, i + j, yCoords_org[i])) {
1252 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setY failed");
1253 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1254 0 : goto bailout;
1255 : }
1256 0 : if (coordinatesNum > 2 && !GEOSCoordSeq_setZ_r(geoshandle, gcs_new, i + j, zCoords_org[i])) {
1257 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setZ failed");
1258 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1259 0 : goto bailout;
1260 : }
1261 :
1262 0 : xl = xCoords_org[i];
1263 0 : yl = yCoords_org[i];
1264 0 : zl = zCoords_org[i];
1265 :
1266 : }
1267 :
1268 : //create the geometry from the translated coordinates sequence
1269 0 : if (isRing)
1270 0 : *outGeometry = GEOSGeom_createLinearRing_r(geoshandle, gcs_new);
1271 : else
1272 0 : *outGeometry = GEOSGeom_createLineString_r(geoshandle, gcs_new);
1273 :
1274 0 : if (*outGeometry == NULL) {
1275 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSGeom_%s failed", isRing ? "LinearRing" : "LineString");
1276 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1277 : }
1278 :
1279 0 : bailout:
1280 0 : GDKfree(xCoords_org);
1281 0 : GDKfree(yCoords_org);
1282 0 : GDKfree(zCoords_org);
1283 :
1284 0 : return err;
1285 : }
1286 :
1287 : static str
1288 0 : segmentizePolygon(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, double sz)
1289 : {
1290 0 : const GEOSGeometry *exteriorRingGeometry;
1291 0 : GEOSGeometry *transformedExteriorRingGeometry = NULL;
1292 0 : GEOSGeometry **transformedInteriorRingGeometries = NULL;
1293 0 : int numInteriorRings = 0, i = 0;
1294 0 : str err;
1295 :
1296 : /* get the exterior ring of the polygon */
1297 0 : exteriorRingGeometry = GEOSGetExteriorRing_r(geoshandle, geosGeometry);
1298 0 : if (exteriorRingGeometry == NULL) {
1299 0 : *outGeometry = NULL;
1300 0 : throw(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSGetExteriorRing failed");
1301 : }
1302 :
1303 0 : if ((err = segmentizeLineString(&transformedExteriorRingGeometry, exteriorRingGeometry, sz, 1)) != MAL_SUCCEED) {
1304 0 : *outGeometry = NULL;
1305 0 : return err;
1306 : }
1307 :
1308 0 : numInteriorRings = GEOSGetNumInteriorRings_r(geoshandle, geosGeometry);
1309 0 : if (numInteriorRings == -1) {
1310 0 : *outGeometry = NULL;
1311 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
1312 0 : throw(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSGetInteriorRingN failed.");
1313 : }
1314 : //iterate over the interiorRing and segmentize each one of them
1315 0 : transformedInteriorRingGeometries = GDKmalloc(numInteriorRings * sizeof(GEOSGeometry *));
1316 0 : if (transformedInteriorRingGeometries == NULL) {
1317 0 : *outGeometry = NULL;
1318 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
1319 0 : throw(MAL, "geom.Segmentize", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1320 : }
1321 0 : for (i = 0; i < numInteriorRings; i++) {
1322 0 : if ((err = segmentizeLineString(&transformedInteriorRingGeometries[i], GEOSGetInteriorRingN_r(geoshandle, geosGeometry, i), sz, 1)) != MAL_SUCCEED) {
1323 0 : while (--i >= 0)
1324 0 : GEOSGeom_destroy_r(geoshandle, transformedInteriorRingGeometries[i]);
1325 0 : GDKfree(transformedInteriorRingGeometries);
1326 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
1327 0 : *outGeometry = NULL;
1328 0 : return err;
1329 : }
1330 : }
1331 :
1332 0 : *outGeometry = GEOSGeom_createPolygon_r(geoshandle, transformedExteriorRingGeometry, transformedInteriorRingGeometries, numInteriorRings);
1333 0 : if (*outGeometry == NULL) {
1334 0 : for (i = 0; i < numInteriorRings; i++)
1335 0 : GEOSGeom_destroy_r(geoshandle, transformedInteriorRingGeometries[i]);
1336 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSGeom_createPolygon failed");
1337 : }
1338 0 : GDKfree(transformedInteriorRingGeometries);
1339 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
1340 :
1341 0 : return err;
1342 : }
1343 :
1344 : static str segmentizeGeometry(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, double sz);
1345 : static str
1346 0 : segmentizeMultiGeometry(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, double sz)
1347 : {
1348 0 : int geometriesNum, i;
1349 0 : GEOSGeometry **transformedMultiGeometries = NULL;
1350 0 : str err = MAL_SUCCEED;
1351 :
1352 0 : geometriesNum = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
1353 0 : transformedMultiGeometries = GDKmalloc(geometriesNum * sizeof(GEOSGeometry *));
1354 0 : if (transformedMultiGeometries == NULL)
1355 0 : throw(MAL, "geom.Segmentize", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1356 :
1357 : //In order to have the geometries in the output in the same order as in the input
1358 : //we should read them and put them in the area in reverse order
1359 0 : for (i = geometriesNum - 1; i >= 0; i--) {
1360 0 : const GEOSGeometry *multiGeometry = GEOSGetGeometryN_r(geoshandle, geosGeometry, i);
1361 :
1362 0 : if ((err = segmentizeGeometry(&transformedMultiGeometries[i], multiGeometry, sz)) != MAL_SUCCEED) {
1363 0 : while (++i < geometriesNum)
1364 0 : GEOSGeom_destroy_r(geoshandle, transformedMultiGeometries[i]);
1365 0 : GDKfree(transformedMultiGeometries);
1366 0 : *outGeometry = NULL;
1367 0 : return err;
1368 : }
1369 : }
1370 :
1371 0 : *outGeometry = GEOSGeom_createCollection_r(geoshandle, GEOSGeomTypeId_r(geoshandle, geosGeometry), transformedMultiGeometries, geometriesNum);
1372 0 : if (*outGeometry == NULL) {
1373 0 : for (i = 0; i < geometriesNum; i++)
1374 0 : GEOSGeom_destroy_r(geoshandle, transformedMultiGeometries[i]);
1375 0 : err = createException(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation GEOSGeom_createCollection failed");
1376 : }
1377 0 : GDKfree(transformedMultiGeometries);
1378 :
1379 0 : return err;
1380 : }
1381 :
1382 : static str
1383 0 : segmentizeGeometry(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, double sz)
1384 : {
1385 0 : int geometryType = GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1;
1386 :
1387 : //check the type of the geometry
1388 0 : switch (geometryType) {
1389 0 : case wkbPoint_mdb:
1390 0 : return segmentizePoint(outGeometry, geosGeometry);
1391 0 : case wkbLineString_mdb:
1392 : case wkbLinearRing_mdb:
1393 0 : return segmentizeLineString(outGeometry, geosGeometry, sz, 0);
1394 0 : case wkbPolygon_mdb:
1395 0 : return segmentizePolygon(outGeometry, geosGeometry, sz);
1396 0 : case wkbMultiPoint_mdb:
1397 : case wkbMultiLineString_mdb:
1398 : case wkbMultiPolygon_mdb:
1399 : case wkbGeometryCollection_mdb:
1400 0 : return segmentizeMultiGeometry(outGeometry, geosGeometry, sz);
1401 0 : default:
1402 0 : throw(MAL, "geom.Segmentize", SQLSTATE(38000) " Geos %s Unknown geometry type", geom_type2str(geometryType, 0));
1403 : }
1404 : }
1405 :
1406 : str
1407 0 : wkbSegmentize(wkb **outWKB, wkb **geomWKB, dbl *sz)
1408 : {
1409 0 : GEOSGeometry *outGeometry;
1410 0 : GEOSGeom geosGeometry;
1411 0 : str err;
1412 :
1413 0 : if (is_wkb_nil(*geomWKB) || is_dbl_nil(*sz)) {
1414 0 : if ((*outWKB = wkbNULLcopy()) == NULL)
1415 0 : throw(MAL, "geom.Segmentize", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1416 : return MAL_SUCCEED;
1417 : }
1418 :
1419 0 : geosGeometry = wkb2geos(*geomWKB);
1420 0 : if (geosGeometry == NULL) {
1421 0 : *outWKB = NULL;
1422 0 : throw(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation wkb2geos failed");
1423 : }
1424 :
1425 0 : if ((err = segmentizeGeometry(&outGeometry, geosGeometry, *sz)) != MAL_SUCCEED) {
1426 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
1427 0 : *outWKB = NULL;
1428 0 : return err;
1429 : }
1430 :
1431 0 : GEOSSetSRID_r(geoshandle, outGeometry, GEOSGetSRID_r(geoshandle, geosGeometry));
1432 :
1433 0 : *outWKB = geos2wkb(outGeometry);
1434 :
1435 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
1436 0 : GEOSGeom_destroy_r(geoshandle, outGeometry);
1437 :
1438 0 : if (*outWKB == NULL)
1439 0 : throw(MAL, "geom.Segmentize", SQLSTATE(38000) "Geos operation geos2wkb failed");
1440 :
1441 : return MAL_SUCCEED;
1442 : }
1443 :
1444 : //gets a coord seq and moves it dx, dy, dz
1445 : static str
1446 0 : translateCoordSeq(int idx, int coordinatesNum, double dx, double dy, double dz, const GEOSCoordSequence *gcs_old, GEOSCoordSeq gcs_new)
1447 : {
1448 0 : double x = 0, y = 0, z = 0;
1449 :
1450 : //get the coordinates
1451 0 : if (!GEOSCoordSeq_getX_r(geoshandle, gcs_old, idx, &x))
1452 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getX failed");
1453 0 : if (!GEOSCoordSeq_getY_r(geoshandle, gcs_old, idx, &y))
1454 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getY failed");
1455 0 : if (coordinatesNum > 2)
1456 0 : if (!GEOSCoordSeq_getZ_r(geoshandle, gcs_old, idx, &z))
1457 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getZ failed");
1458 :
1459 : //create new coordinates moved by dx, dy, dz
1460 0 : if (!GEOSCoordSeq_setX_r(geoshandle, gcs_new, idx, (x + dx)))
1461 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setX failed");
1462 0 : if (!GEOSCoordSeq_setY_r(geoshandle, gcs_new, idx, (y + dy)))
1463 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setY failed");
1464 0 : if (coordinatesNum > 2)
1465 0 : if (!GEOSCoordSeq_setZ_r(geoshandle, gcs_new, idx, (z + dz)))
1466 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setZ failed");
1467 :
1468 : return MAL_SUCCEED;
1469 : }
1470 :
1471 : static str
1472 0 : translatePoint(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, double dx, double dy, double dz)
1473 : {
1474 0 : int coordinatesNum = 0;
1475 0 : const GEOSCoordSequence *gcs_old;
1476 0 : GEOSCoordSeq gcs_new;
1477 0 : str err;
1478 :
1479 : /* get the number of coordinates the geometry has */
1480 0 : coordinatesNum = GEOSGeom_getCoordinateDimension_r(geoshandle, geosGeometry);
1481 : /* get the coordinates of the points comprising the geometry */
1482 0 : gcs_old = GEOSGeom_getCoordSeq_r(geoshandle, geosGeometry);
1483 :
1484 0 : if (gcs_old == NULL) {
1485 0 : *outGeometry = NULL;
1486 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
1487 : }
1488 :
1489 : /* create the coordinates sequence for the translated geometry */
1490 0 : gcs_new = GEOSCoordSeq_create_r(geoshandle, 1, coordinatesNum);
1491 0 : if (gcs_new == NULL) {
1492 0 : *outGeometry = NULL;
1493 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSCoordSeq_create failed");
1494 : }
1495 :
1496 : /* create the translated coordinates */
1497 0 : if ((err = translateCoordSeq(0, coordinatesNum, dx, dy, dz, gcs_old, gcs_new)) != MAL_SUCCEED) {
1498 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1499 0 : *outGeometry = NULL;
1500 0 : return err;
1501 : }
1502 :
1503 : /* create the geometry from the coordinates sequence */
1504 0 : *outGeometry = GEOSGeom_createPoint_r(geoshandle, gcs_new);
1505 0 : if (*outGeometry == NULL) {
1506 0 : err = createException(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSGeom_createPoint failed");
1507 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1508 : }
1509 :
1510 : return err;
1511 : }
1512 :
1513 : static str
1514 0 : translateLineString(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, double dx, double dy, double dz)
1515 : {
1516 0 : int coordinatesNum = 0;
1517 0 : const GEOSCoordSequence *gcs_old;
1518 0 : GEOSCoordSeq gcs_new;
1519 0 : unsigned int pointsNum = 0, i = 0;
1520 0 : str err;
1521 :
1522 : /* get the number of coordinates the geometry has */
1523 0 : coordinatesNum = GEOSGeom_getCoordinateDimension_r(geoshandle, geosGeometry);
1524 : /* get the coordinates of the points comprising the geometry */
1525 0 : gcs_old = GEOSGeom_getCoordSeq_r(geoshandle, geosGeometry);
1526 :
1527 0 : if (gcs_old == NULL)
1528 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
1529 :
1530 : /* get the number of points in the geometry */
1531 0 : GEOSCoordSeq_getSize_r(geoshandle, gcs_old, &pointsNum);
1532 :
1533 : /* create the coordinates sequence for the translated geometry */
1534 0 : gcs_new = GEOSCoordSeq_create_r(geoshandle, pointsNum, coordinatesNum);
1535 0 : if (gcs_new == NULL) {
1536 0 : *outGeometry = NULL;
1537 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSCoordSeq_create failed");
1538 : }
1539 :
1540 : /* create the translated coordinates */
1541 0 : for (i = 0; i < pointsNum; i++) {
1542 0 : if ((err = translateCoordSeq(i, coordinatesNum, dx, dy, dz, gcs_old, gcs_new)) != MAL_SUCCEED) {
1543 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1544 0 : return err;
1545 : }
1546 : }
1547 :
1548 : //create the geometry from the translated coordinates sequence
1549 0 : *outGeometry = GEOSGeom_createLineString_r(geoshandle, gcs_new);
1550 0 : if (*outGeometry == NULL) {
1551 0 : err = createException(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSGeom_createLineString failed");
1552 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1553 : }
1554 :
1555 : return err;
1556 : }
1557 :
1558 : //Necessary for composing a polygon from rings
1559 : static str
1560 0 : translateLinearRing(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, double dx, double dy, double dz)
1561 : {
1562 0 : int coordinatesNum = 0;
1563 0 : const GEOSCoordSequence *gcs_old;
1564 0 : GEOSCoordSeq gcs_new;
1565 0 : unsigned int pointsNum = 0, i = 0;
1566 0 : str err;
1567 :
1568 : /* get the number of coordinates the geometry has */
1569 0 : coordinatesNum = GEOSGeom_getCoordinateDimension_r(geoshandle, geosGeometry);
1570 : /* get the coordinates of the points comprising the geometry */
1571 0 : gcs_old = GEOSGeom_getCoordSeq_r(geoshandle, geosGeometry);
1572 :
1573 0 : if (gcs_old == NULL)
1574 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
1575 :
1576 : /* get the number of points in the geometry */
1577 0 : GEOSCoordSeq_getSize_r(geoshandle, gcs_old, &pointsNum);
1578 :
1579 : /* create the coordinates sequence for the translated geometry */
1580 0 : gcs_new = GEOSCoordSeq_create_r(geoshandle, pointsNum, coordinatesNum);
1581 0 : if (gcs_new == NULL) {
1582 0 : *outGeometry = NULL;
1583 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSCoordSeq_create failed");
1584 : }
1585 :
1586 : /* create the translated coordinates */
1587 0 : for (i = 0; i < pointsNum; i++) {
1588 0 : if ((err = translateCoordSeq(i, coordinatesNum, dx, dy, dz, gcs_old, gcs_new)) != MAL_SUCCEED) {
1589 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1590 0 : return err;
1591 : }
1592 : }
1593 :
1594 : //create the geometry from the translated coordinates sequence
1595 0 : *outGeometry = GEOSGeom_createLinearRing_r(geoshandle, gcs_new);
1596 0 : if (*outGeometry == NULL) {
1597 0 : err = createException(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSGeom_createLinearRing failed");
1598 0 : GEOSCoordSeq_destroy_r(geoshandle, gcs_new);
1599 : }
1600 :
1601 : return err;
1602 : }
1603 :
1604 : static str
1605 0 : translatePolygon(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, double dx, double dy, double dz)
1606 : {
1607 0 : const GEOSGeometry *exteriorRingGeometry;
1608 0 : GEOSGeometry *transformedExteriorRingGeometry = NULL;
1609 0 : GEOSGeometry **transformedInteriorRingGeometries = NULL;
1610 0 : int numInteriorRings = 0, i = 0;
1611 0 : str err = MAL_SUCCEED;
1612 :
1613 : /* get the exterior ring of the polygon */
1614 0 : exteriorRingGeometry = GEOSGetExteriorRing_r(geoshandle, geosGeometry);
1615 0 : if (exteriorRingGeometry == NULL) {
1616 0 : *outGeometry = NULL;
1617 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSGetExteriorRing failed");
1618 : }
1619 :
1620 0 : if ((err = translateLinearRing(&transformedExteriorRingGeometry, exteriorRingGeometry, dx, dy, dz)) != MAL_SUCCEED) {
1621 0 : *outGeometry = NULL;
1622 0 : return err;
1623 : }
1624 :
1625 0 : numInteriorRings = GEOSGetNumInteriorRings_r(geoshandle, geosGeometry);
1626 0 : if (numInteriorRings == -1) {
1627 0 : *outGeometry = NULL;
1628 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
1629 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSGetInteriorRingN failed.");
1630 : }
1631 :
1632 : /* iterate over the interiorRing and translate each one of them */
1633 0 : transformedInteriorRingGeometries = GDKmalloc(numInteriorRings * sizeof(GEOSGeometry *));
1634 0 : if (transformedInteriorRingGeometries == NULL) {
1635 0 : *outGeometry = NULL;
1636 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
1637 0 : throw(MAL, "geom.Translate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1638 : }
1639 0 : for (i = 0; i < numInteriorRings; i++) {
1640 0 : if ((err = translateLinearRing(&transformedInteriorRingGeometries[i], GEOSGetInteriorRingN_r(geoshandle, geosGeometry, i), dx, dy, dz)) != MAL_SUCCEED) {
1641 0 : while (--i >= 0)
1642 0 : GEOSGeom_destroy_r(geoshandle, transformedInteriorRingGeometries[i]);
1643 0 : GDKfree(transformedInteriorRingGeometries);
1644 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
1645 0 : *outGeometry = NULL;
1646 0 : return err;
1647 : }
1648 : }
1649 :
1650 0 : *outGeometry = GEOSGeom_createPolygon_r(geoshandle, transformedExteriorRingGeometry, transformedInteriorRingGeometries, numInteriorRings);
1651 0 : if (*outGeometry == NULL) {
1652 0 : for (i = 0; i < numInteriorRings; i++)
1653 0 : GEOSGeom_destroy_r(geoshandle, transformedInteriorRingGeometries[i]);
1654 0 : err = createException(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSGeom_createPolygon failed");
1655 : }
1656 0 : GDKfree(transformedInteriorRingGeometries);
1657 0 : GEOSGeom_destroy_r(geoshandle, transformedExteriorRingGeometry);
1658 :
1659 0 : return err;
1660 : }
1661 :
1662 : static str translateGeometry(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, double dx, double dy, double dz);
1663 : static str
1664 0 : translateMultiGeometry(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, double dx, double dy, double dz)
1665 : {
1666 0 : int geometriesNum, i;
1667 0 : GEOSGeometry **transformedMultiGeometries = NULL;
1668 0 : str err = MAL_SUCCEED;
1669 :
1670 0 : geometriesNum = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
1671 0 : transformedMultiGeometries = GDKmalloc(geometriesNum * sizeof(GEOSGeometry *));
1672 0 : if (transformedMultiGeometries == NULL)
1673 0 : throw(MAL, "geom.Translate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1674 :
1675 : //In order to have the geometries in the output in the same order as in the input
1676 : //we should read them and put them in the area in reverse order
1677 0 : for (i = geometriesNum - 1; i >= 0; i--) {
1678 0 : const GEOSGeometry *multiGeometry = GEOSGetGeometryN_r(geoshandle, geosGeometry, i);
1679 :
1680 0 : if ((err = translateGeometry(&transformedMultiGeometries[i], multiGeometry, dx, dy, dz)) != MAL_SUCCEED) {
1681 0 : while (i++ < geometriesNum)
1682 0 : GEOSGeom_destroy_r(geoshandle, transformedMultiGeometries[i]);
1683 0 : GDKfree(transformedMultiGeometries);
1684 0 : *outGeometry = NULL;
1685 0 : return err;
1686 : }
1687 : }
1688 :
1689 0 : *outGeometry = GEOSGeom_createCollection_r(geoshandle, GEOSGeomTypeId_r(geoshandle, geosGeometry), transformedMultiGeometries, geometriesNum);
1690 0 : if (*outGeometry == NULL) {
1691 0 : for (i = 0; i < geometriesNum; i++)
1692 0 : GEOSGeom_destroy_r(geoshandle, transformedMultiGeometries[i]);
1693 0 : err = createException(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation GEOSGeom_createCollection failed");
1694 : }
1695 0 : GDKfree(transformedMultiGeometries);
1696 :
1697 0 : return err;
1698 : }
1699 :
1700 : static str
1701 0 : translateGeometry(GEOSGeometry **outGeometry, const GEOSGeometry *geosGeometry, double dx, double dy, double dz)
1702 : {
1703 0 : int geometryType = GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1;
1704 :
1705 : //check the type of the geometry
1706 0 : switch (geometryType) {
1707 0 : case wkbPoint_mdb:
1708 0 : return translatePoint(outGeometry, geosGeometry, dx, dy, dz);
1709 0 : case wkbLineString_mdb:
1710 : case wkbLinearRing_mdb:
1711 0 : return translateLineString(outGeometry, geosGeometry, dx, dy, dz);
1712 0 : case wkbPolygon_mdb:
1713 0 : return translatePolygon(outGeometry, geosGeometry, dx, dy, dz);
1714 0 : case wkbMultiPoint_mdb:
1715 : case wkbMultiLineString_mdb:
1716 : case wkbMultiPolygon_mdb:
1717 : case wkbGeometryCollection_mdb:
1718 0 : return translateMultiGeometry(outGeometry, geosGeometry, dx, dy, dz);
1719 0 : default:
1720 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos %s unknown geometry type", geom_type2str(geometryType, 0));
1721 : }
1722 : }
1723 :
1724 : str
1725 0 : wkbTranslate(wkb **outWKB, wkb **geomWKB, dbl *dx, dbl *dy, dbl *dz)
1726 : {
1727 0 : GEOSGeometry *outGeometry;
1728 0 : GEOSGeom geosGeometry;
1729 0 : str err;
1730 :
1731 0 : if (is_wkb_nil(*geomWKB) || is_dbl_nil(*dx) || is_dbl_nil(*dy) || is_dbl_nil(*dz)) {
1732 0 : if ((*outWKB = wkbNULLcopy()) == NULL)
1733 0 : throw(MAL, "geom.Translate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1734 : return MAL_SUCCEED;
1735 : }
1736 :
1737 0 : geosGeometry = wkb2geos(*geomWKB);
1738 0 : if (geosGeometry == NULL) {
1739 0 : *outWKB = NULL;
1740 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation wkb2geos failed");
1741 : }
1742 :
1743 0 : if ((err = translateGeometry(&outGeometry, geosGeometry, *dx, *dy, *dz)) != MAL_SUCCEED) {
1744 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
1745 0 : *outWKB = NULL;
1746 0 : return err;
1747 : }
1748 :
1749 0 : GEOSSetSRID_r(geoshandle, outGeometry, GEOSGetSRID_r(geoshandle, geosGeometry));
1750 :
1751 0 : *outWKB = geos2wkb(outGeometry);
1752 :
1753 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
1754 0 : GEOSGeom_destroy_r(geoshandle, outGeometry);
1755 :
1756 0 : if (*outWKB == NULL)
1757 0 : throw(MAL, "geom.Translate", SQLSTATE(38000) "Geos operation geos2wkb failed");
1758 :
1759 : return MAL_SUCCEED;
1760 : }
1761 :
1762 : //It creates a Delaunay triangulation
1763 : //flag = 0 => returns a collection of polygons
1764 : //flag = 1 => returns a multilinestring
1765 : str
1766 4 : wkbDelaunayTriangles(wkb **outWKB, wkb **geomWKB, dbl *tolerance, int *flag)
1767 : {
1768 4 : GEOSGeom outGeometry;
1769 4 : GEOSGeom geosGeometry;
1770 :
1771 4 : if (is_wkb_nil(*geomWKB) || is_dbl_nil(*tolerance) || is_int_nil(*flag)) {
1772 0 : if ((*outWKB = wkbNULLcopy()) == NULL)
1773 0 : throw(MAL, "geom.DelaunayTriangles", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1774 : return MAL_SUCCEED;
1775 : }
1776 :
1777 4 : geosGeometry = wkb2geos(*geomWKB);
1778 4 : outGeometry = GEOSDelaunayTriangulation_r(geoshandle, geosGeometry, *tolerance, *flag);
1779 4 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
1780 4 : if (outGeometry == NULL) {
1781 0 : *outWKB = NULL;
1782 0 : throw(MAL, "geom.DelaunayTriangles", SQLSTATE(38000) "Geos operation GEOSDelaunayTriangulation failed");
1783 : }
1784 :
1785 4 : *outWKB = geos2wkb(outGeometry);
1786 4 : GEOSGeom_destroy_r(geoshandle, outGeometry);
1787 :
1788 4 : if (*outWKB == NULL)
1789 0 : throw(MAL, "geom.DelaunayTriangles", SQLSTATE(38000) "Geos operation geos2wkb failed");
1790 :
1791 : return MAL_SUCCEED;
1792 : }
1793 :
1794 : str
1795 2 : wkbPointOnSurface(wkb **resWKB, wkb **geomWKB)
1796 : {
1797 2 : GEOSGeom geosGeometry, resGeosGeometry;
1798 :
1799 2 : if (is_wkb_nil(*geomWKB)) {
1800 0 : if ((*resWKB = wkbNULLcopy()) == NULL)
1801 0 : throw(MAL, "geom.PointOnSurface", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1802 : return MAL_SUCCEED;
1803 : }
1804 :
1805 2 : geosGeometry = wkb2geos(*geomWKB);
1806 2 : if (geosGeometry == NULL) {
1807 0 : *resWKB = NULL;
1808 0 : throw(MAL, "geom.PointOnSurface", SQLSTATE(38000) "Geos operation wkb2geos failed");
1809 : }
1810 :
1811 2 : resGeosGeometry = GEOSPointOnSurface_r(geoshandle, geosGeometry);
1812 2 : if (resGeosGeometry == NULL) {
1813 0 : *resWKB = NULL;
1814 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
1815 0 : throw(MAL, "geom.PointOnSurface", SQLSTATE(38000) "Geos operation GEOSPointOnSurface failed");
1816 : }
1817 : //set the srid of the point the same as the srid of the input geometry
1818 2 : GEOSSetSRID_r(geoshandle, resGeosGeometry, GEOSGetSRID_r(geoshandle, geosGeometry));
1819 :
1820 2 : *resWKB = geos2wkb(resGeosGeometry);
1821 :
1822 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
1823 2 : GEOSGeom_destroy_r(geoshandle, resGeosGeometry);
1824 :
1825 2 : if (*resWKB == NULL)
1826 0 : throw(MAL, "geom.PointOnSurface", SQLSTATE(38000) "Geos operation geos2wkb failed");
1827 :
1828 : return MAL_SUCCEED;
1829 : }
1830 :
1831 : static str
1832 23 : dumpGeometriesSingle(BAT *idBAT, BAT *geomBAT, const GEOSGeometry *geosGeometry, unsigned int *lvl, const char *path)
1833 : {
1834 23 : char *newPath = NULL;
1835 23 : size_t pathLength = strlen(path);
1836 23 : wkb *singleWKB = geos2wkb(geosGeometry);
1837 23 : str err = MAL_SUCCEED;
1838 :
1839 23 : if (singleWKB == NULL)
1840 0 : throw(MAL, "geom.Dump", SQLSTATE(38000) "Geos operation geos2wkb failed");
1841 :
1842 : //change the path only if it is empty
1843 23 : if (pathLength == 0) {
1844 6 : const int lvlDigitsNum = 10; //MAX_UNIT = 4,294,967,295
1845 :
1846 6 : (*lvl)++;
1847 :
1848 6 : newPath = GDKmalloc(lvlDigitsNum + 1);
1849 6 : if (newPath == NULL) {
1850 0 : GDKfree(singleWKB);
1851 0 : throw(MAL, "geom.Dump", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1852 : }
1853 6 : snprintf(newPath, lvlDigitsNum + 1, "%u", *lvl);
1854 : } else {
1855 : //remove the comma at the end of the path
1856 : #ifdef __COVERITY__
1857 : /* coverity complains about the allocated space being
1858 : * too small, but we just want to reduce the length of
1859 : * the string by one, so the length in the #else part
1860 : * is exactly what we need */
1861 : newPath = GDKmalloc(pathLength + 1);
1862 : #else
1863 17 : newPath = GDKmalloc(pathLength);
1864 : #endif
1865 17 : if (newPath == NULL) {
1866 0 : GDKfree(singleWKB);
1867 0 : throw(MAL, "geom.Dump", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1868 : }
1869 17 : strcpy_len(newPath, path, pathLength);
1870 : }
1871 46 : if (BUNappend(idBAT, newPath, false) != GDK_SUCCEED ||
1872 23 : BUNappend(geomBAT, singleWKB, false) != GDK_SUCCEED)
1873 0 : err = createException(MAL, "geom.Dump", SQLSTATE(38000) "Geos operation BUNappend failed");
1874 :
1875 23 : GDKfree(newPath);
1876 23 : GDKfree(singleWKB);
1877 :
1878 23 : return err;
1879 : }
1880 :
1881 : static str dumpGeometriesGeometry(BAT *idBAT, BAT *geomBAT, const GEOSGeometry *geosGeometry, const char *path);
1882 : static str
1883 12 : dumpGeometriesMulti(BAT *idBAT, BAT *geomBAT, const GEOSGeometry *geosGeometry, const char *path)
1884 : {
1885 12 : int i;
1886 12 : const GEOSGeometry *multiGeometry = NULL;
1887 12 : unsigned int lvl = 0;
1888 12 : size_t pathLength = strlen(path);
1889 12 : char *newPath;
1890 12 : str err = MAL_SUCCEED;
1891 :
1892 12 : int geometriesNum = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
1893 :
1894 12 : pathLength += 10 + 1 + 1; /* 10 for lvl, 1 for ",", 1 for NULL byte */
1895 12 : newPath = GDKmalloc(pathLength);
1896 12 : if (newPath == NULL)
1897 0 : throw(MAL, "geom.Dump", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1898 :
1899 30 : for (i = 0; i < geometriesNum; i++) {
1900 18 : multiGeometry = GEOSGetGeometryN_r(geoshandle, geosGeometry, i);
1901 18 : if (multiGeometry == NULL) {
1902 0 : err = createException(MAL, "geom.Dump", SQLSTATE(38000) "Geos operation GEOSGetGeometryN failed");
1903 0 : break;
1904 : }
1905 18 : lvl++;
1906 :
1907 18 : snprintf(newPath, pathLength, "%s%u,", path, lvl);
1908 :
1909 : //*secondLevel = 0;
1910 18 : err = dumpGeometriesGeometry(idBAT, geomBAT, multiGeometry, newPath);
1911 18 : if (err != MAL_SUCCEED)
1912 : break;
1913 : }
1914 12 : GDKfree(newPath);
1915 12 : return err;
1916 : }
1917 :
1918 : static str
1919 27 : dumpGeometriesGeometry(BAT *idBAT, BAT *geomBAT, const GEOSGeometry *geosGeometry, const char *path)
1920 : {
1921 27 : int geometryType = GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1;
1922 27 : unsigned int lvl = 0;
1923 :
1924 : //check the type of the geometry
1925 27 : switch (geometryType) {
1926 15 : case wkbPoint_mdb:
1927 : case wkbLineString_mdb:
1928 : case wkbLinearRing_mdb:
1929 : case wkbPolygon_mdb:
1930 : //Single Geometry
1931 15 : return dumpGeometriesSingle(idBAT, geomBAT, geosGeometry, &lvl, path);
1932 12 : case wkbMultiPoint_mdb:
1933 : case wkbMultiLineString_mdb:
1934 : case wkbMultiPolygon_mdb:
1935 : case wkbGeometryCollection_mdb:
1936 : //Multi Geometry
1937 : //check if the geometry was empty
1938 12 : if (GEOSisEmpty_r(geoshandle, geosGeometry) == 1) {
1939 8 : str err;
1940 : //handle it as single
1941 8 : if ((err = dumpGeometriesSingle(idBAT, geomBAT, geosGeometry, &lvl, path)) != MAL_SUCCEED)
1942 : return err;
1943 : }
1944 :
1945 12 : return dumpGeometriesMulti(idBAT, geomBAT, geosGeometry, path);
1946 0 : default:
1947 0 : throw(MAL, "geom.Dump", SQLSTATE(38000) "Geos %s unknown geometry type", geom_type2str(geometryType, 0));
1948 : }
1949 : }
1950 :
1951 : str
1952 9 : wkbDump(bat *idBAT_id, bat *geomBAT_id, wkb **geomWKB)
1953 : {
1954 9 : BAT *idBAT = NULL, *geomBAT = NULL;
1955 9 : GEOSGeom geosGeometry;
1956 9 : unsigned int geometriesNum;
1957 9 : str err;
1958 :
1959 9 : if (is_wkb_nil(*geomWKB)) {
1960 :
1961 : //create new empty BAT for the output
1962 0 : if ((idBAT = COLnew(0, TYPE_str, 0, TRANSIENT)) == NULL) {
1963 0 : *idBAT_id = bat_nil;
1964 0 : throw(MAL, "geom.DumpPoints", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1965 : }
1966 :
1967 0 : if ((geomBAT = COLnew(0, ATOMindex("wkb"), 0, TRANSIENT)) == NULL) {
1968 0 : BBPunfix(idBAT->batCacheid);
1969 0 : *geomBAT_id = bat_nil;
1970 0 : throw(MAL, "geom.DumpPoints", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1971 : }
1972 :
1973 0 : *idBAT_id = idBAT->batCacheid;
1974 0 : BBPkeepref(idBAT);
1975 :
1976 0 : *geomBAT_id = geomBAT->batCacheid;
1977 0 : BBPkeepref(geomBAT);
1978 :
1979 0 : return MAL_SUCCEED;
1980 : }
1981 :
1982 9 : geosGeometry = wkb2geos(*geomWKB);
1983 :
1984 : //count the number of geometries
1985 9 : geometriesNum = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
1986 :
1987 9 : if ((idBAT = COLnew(0, TYPE_str, geometriesNum, TRANSIENT)) == NULL) {
1988 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
1989 0 : throw(MAL, "geom.Dump", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1990 : }
1991 :
1992 9 : if ((geomBAT = COLnew(0, ATOMindex("wkb"), geometriesNum, TRANSIENT)) == NULL) {
1993 0 : BBPunfix(idBAT->batCacheid);
1994 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
1995 0 : throw(MAL, "geom.Dump", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1996 : }
1997 :
1998 9 : err = dumpGeometriesGeometry(idBAT, geomBAT, geosGeometry, "");
1999 9 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
2000 9 : if (err != MAL_SUCCEED) {
2001 0 : BBPunfix(idBAT->batCacheid);
2002 0 : BBPunfix(geomBAT->batCacheid);
2003 0 : return err;
2004 : }
2005 :
2006 9 : *idBAT_id = idBAT->batCacheid;
2007 9 : BBPkeepref(idBAT);
2008 9 : *geomBAT_id = geomBAT->batCacheid;
2009 9 : BBPkeepref(geomBAT);
2010 9 : return MAL_SUCCEED;
2011 : }
2012 :
2013 : static str
2014 72 : dumpPointsPoint(BAT *idBAT, BAT *geomBAT, const GEOSGeometry *geosGeometry, unsigned int *lvl, const char *path)
2015 : {
2016 72 : char *newPath = NULL;
2017 72 : size_t pathLength = strlen(path);
2018 72 : wkb *pointWKB = geos2wkb(geosGeometry);
2019 72 : const int lvlDigitsNum = 10; //MAX_UNIT = 4,294,967,295
2020 72 : str err = MAL_SUCCEED;
2021 :
2022 72 : if (pointWKB == NULL)
2023 0 : throw(MAL, "geom.Dump", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2024 :
2025 72 : (*lvl)++;
2026 72 : newPath = GDKmalloc(pathLength + lvlDigitsNum + 1);
2027 72 : if (newPath == NULL) {
2028 0 : GDKfree(pointWKB);
2029 0 : throw(MAL, "geom.Dump", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2030 : }
2031 72 : sprintf(newPath, "%s%u", path, *lvl);
2032 :
2033 144 : if (BUNappend(idBAT, newPath, false) != GDK_SUCCEED ||
2034 72 : BUNappend(geomBAT, pointWKB, false) != GDK_SUCCEED)
2035 0 : err = createException(MAL, "geom.Dump", SQLSTATE(38000) "Geos operation BUNappend failed");
2036 :
2037 72 : GDKfree(newPath);
2038 72 : GDKfree(pointWKB);
2039 :
2040 72 : return err;
2041 : }
2042 :
2043 : static str
2044 16 : dumpPointsLineString(BAT *idBAT, BAT *geomBAT, const GEOSGeometry *geosGeometry, const char *path)
2045 : {
2046 16 : int pointsNum = 0;
2047 16 : str err;
2048 16 : int i = 0;
2049 16 : int check = 0;
2050 16 : unsigned int lvl = 0;
2051 16 : wkb *geomWKB = geos2wkb(geosGeometry);
2052 :
2053 16 : err = wkbNumPoints(&pointsNum, &geomWKB, &check);
2054 16 : GDKfree(geomWKB);
2055 16 : if (err != MAL_SUCCEED)
2056 : return err;
2057 :
2058 86 : for (i = 0; i < pointsNum && err == MAL_SUCCEED; i++) {
2059 70 : GEOSGeometry *pointGeometry = GEOSGeomGetPointN_r(geoshandle, geosGeometry, i);
2060 :
2061 70 : if (pointGeometry == NULL)
2062 0 : throw(MAL, "geom.DumpPoints", SQLSTATE(38000) "Geos operation GEOSGeomGetPointN failed");
2063 :
2064 70 : err = dumpPointsPoint(idBAT, geomBAT, pointGeometry, &lvl, path);
2065 70 : GEOSGeom_destroy_r(geoshandle, pointGeometry);
2066 : }
2067 :
2068 : return err;
2069 : }
2070 :
2071 : static str
2072 9 : dumpPointsPolygon(BAT *idBAT, BAT *geomBAT, const GEOSGeometry *geosGeometry, unsigned int *lvl, const char *path)
2073 : {
2074 9 : const GEOSGeometry *exteriorRingGeometry;
2075 9 : int numInteriorRings = 0, i = 0;
2076 9 : str err;
2077 9 : const int lvlDigitsNum = 10; //MAX_UNIT = 4,294,967,295
2078 9 : size_t pathLength = strlen(path);
2079 9 : char *newPath;
2080 9 : const char extraStr[] = ",";
2081 9 : int extraLength = 1;
2082 :
2083 : //get the exterior ring of the polygon
2084 9 : exteriorRingGeometry = GEOSGetExteriorRing_r(geoshandle, geosGeometry);
2085 9 : if (exteriorRingGeometry == NULL)
2086 0 : throw(MAL, "geom.DumpPoints", SQLSTATE(38000) "Geos operation GEOSGetExteriorRing failed");
2087 :
2088 9 : (*lvl)++;
2089 9 : newPath = GDKmalloc(pathLength + lvlDigitsNum + extraLength + 1);
2090 9 : if (newPath == NULL)
2091 0 : throw(MAL, "geom.DumpPoints", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2092 9 : snprintf(newPath, pathLength + lvlDigitsNum + extraLength + 1,
2093 : "%s%u%s", path, *lvl, extraStr);
2094 :
2095 : //get the points in the exterior ring
2096 9 : err = dumpPointsLineString(idBAT, geomBAT, exteriorRingGeometry, newPath);
2097 9 : GDKfree(newPath);
2098 9 : if (err != MAL_SUCCEED)
2099 : return err;
2100 :
2101 : //check the interior rings
2102 9 : numInteriorRings = GEOSGetNumInteriorRings_r(geoshandle, geosGeometry);
2103 9 : if (numInteriorRings == -1)
2104 0 : throw(MAL, "geom.DumpPoints", SQLSTATE(38000) "Geos operation GEOSGetNumInteriorRings failed");
2105 :
2106 : // iterate over the interiorRing and transform each one of them
2107 14 : for (i = 0; i < numInteriorRings; i++) {
2108 5 : (*lvl)++;
2109 :
2110 5 : newPath = GDKmalloc(pathLength + lvlDigitsNum + extraLength + 1);
2111 5 : if (newPath == NULL)
2112 0 : throw(MAL, "geom.DumpPoints", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2113 5 : snprintf(newPath, pathLength + lvlDigitsNum + extraLength + 1,
2114 : "%s%u%s", path, *lvl, extraStr);
2115 :
2116 5 : err = dumpPointsLineString(idBAT, geomBAT, GEOSGetInteriorRingN_r(geoshandle, geosGeometry, i), newPath);
2117 5 : GDKfree(newPath);
2118 5 : if (err != MAL_SUCCEED)
2119 0 : return err;
2120 : }
2121 :
2122 : return MAL_SUCCEED;
2123 : }
2124 :
2125 : static str dumpPointsGeometry(BAT *idBAT, BAT *geomBAT, const GEOSGeometry *geosGeometry, const char *path);
2126 : static str
2127 4 : dumpPointsMultiGeometry(BAT *idBAT, BAT *geomBAT, const GEOSGeometry *geosGeometry, const char *path)
2128 : {
2129 4 : int geometriesNum, i;
2130 4 : const GEOSGeometry *multiGeometry = NULL;
2131 4 : str err;
2132 4 : unsigned int lvl = 0;
2133 4 : size_t pathLength = strlen(path);
2134 4 : char *newPath = NULL;
2135 4 : const char extraStr[] = ",";
2136 4 : int extraLength = 1;
2137 :
2138 4 : geometriesNum = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
2139 :
2140 18 : for (i = 0; i < geometriesNum; i++) {
2141 10 : const int lvlDigitsNum = 10; //MAX_UNIT = 4,294,967,295
2142 :
2143 10 : multiGeometry = GEOSGetGeometryN_r(geoshandle, geosGeometry, i);
2144 10 : lvl++;
2145 :
2146 10 : newPath = GDKmalloc(pathLength + lvlDigitsNum + extraLength + 1);
2147 10 : if (newPath == NULL)
2148 0 : throw(MAL, "geom.DumpPoints", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2149 10 : snprintf(newPath, pathLength + lvlDigitsNum + extraLength + 1,
2150 : "%s%u%s", path, lvl, extraStr);
2151 :
2152 : //*secondLevel = 0;
2153 10 : err = dumpPointsGeometry(idBAT, geomBAT, multiGeometry, newPath);
2154 10 : GDKfree(newPath);
2155 10 : if (err != MAL_SUCCEED)
2156 0 : return err;
2157 : }
2158 :
2159 : return MAL_SUCCEED;
2160 : }
2161 :
2162 : static str
2163 17 : dumpPointsGeometry(BAT *idBAT, BAT *geomBAT, const GEOSGeometry *geosGeometry, const char *path)
2164 : {
2165 17 : int geometryType = GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1;
2166 17 : unsigned int lvl = 0;
2167 :
2168 : //check the type of the geometry
2169 17 : switch (geometryType) {
2170 2 : case wkbPoint_mdb:
2171 2 : return dumpPointsPoint(idBAT, geomBAT, geosGeometry, &lvl, path);
2172 2 : case wkbLineString_mdb:
2173 : case wkbLinearRing_mdb:
2174 2 : return dumpPointsLineString(idBAT, geomBAT, geosGeometry, path);
2175 9 : case wkbPolygon_mdb:
2176 9 : return dumpPointsPolygon(idBAT, geomBAT, geosGeometry, &lvl, path);
2177 4 : case wkbMultiPoint_mdb:
2178 : case wkbMultiLineString_mdb:
2179 : case wkbMultiPolygon_mdb:
2180 : case wkbGeometryCollection_mdb:
2181 4 : return dumpPointsMultiGeometry(idBAT, geomBAT, geosGeometry, path);
2182 0 : default:
2183 0 : throw(MAL, "geom.DumpPoints", SQLSTATE(38000) "Geoes %s unknown geometry type", geom_type2str(geometryType, 0));
2184 : }
2185 : }
2186 :
2187 : str
2188 7 : wkbDumpPoints(bat *idBAT_id, bat *geomBAT_id, wkb **geomWKB)
2189 : {
2190 7 : BAT *idBAT = NULL, *geomBAT = NULL;
2191 7 : GEOSGeom geosGeometry;
2192 7 : int check = 0;
2193 7 : int pointsNum;
2194 7 : str err;
2195 :
2196 7 : if (is_wkb_nil(*geomWKB)) {
2197 :
2198 : //create new empty BAT for the output
2199 0 : if ((idBAT = COLnew(0, TYPE_str, 0, TRANSIENT)) == NULL) {
2200 0 : *idBAT_id = int_nil;
2201 0 : throw(MAL, "geom.DumpPoints", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2202 : }
2203 :
2204 0 : if ((geomBAT = COLnew(0, ATOMindex("wkb"), 0, TRANSIENT)) == NULL) {
2205 0 : BBPunfix(idBAT->batCacheid);
2206 0 : *geomBAT_id = int_nil;
2207 0 : throw(MAL, "geom.DumpPoints", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2208 : }
2209 :
2210 0 : *idBAT_id = idBAT->batCacheid;
2211 0 : BBPkeepref(idBAT);
2212 :
2213 0 : *geomBAT_id = geomBAT->batCacheid;
2214 0 : BBPkeepref(geomBAT);
2215 :
2216 0 : return MAL_SUCCEED;
2217 : }
2218 :
2219 7 : geosGeometry = wkb2geos(*geomWKB);
2220 :
2221 7 : if ((err = wkbNumPoints(&pointsNum, geomWKB, &check)) != MAL_SUCCEED) {
2222 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
2223 0 : return err;
2224 : }
2225 :
2226 7 : if ((idBAT = COLnew(0, TYPE_str, pointsNum, TRANSIENT)) == NULL) {
2227 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
2228 0 : throw(MAL, "geom.Dump", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2229 : }
2230 :
2231 7 : if ((geomBAT = COLnew(0, ATOMindex("wkb"), pointsNum, TRANSIENT)) == NULL) {
2232 0 : BBPunfix(idBAT->batCacheid);
2233 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
2234 0 : throw(MAL, "geom.Dump", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2235 : }
2236 :
2237 7 : err = dumpPointsGeometry(idBAT, geomBAT, geosGeometry, "");
2238 7 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
2239 7 : if (err != MAL_SUCCEED) {
2240 0 : BBPunfix(idBAT->batCacheid);
2241 0 : BBPunfix(geomBAT->batCacheid);
2242 0 : return err;
2243 : }
2244 :
2245 7 : *idBAT_id = idBAT->batCacheid;
2246 7 : BBPkeepref(idBAT);
2247 7 : *geomBAT_id = geomBAT->batCacheid;
2248 7 : BBPkeepref(geomBAT);
2249 7 : return MAL_SUCCEED;
2250 : }
2251 :
2252 : str
2253 248 : geom_2_geom(wkb **resWKB, wkb **valueWKB, int *columnType, int *columnSRID)
2254 : {
2255 248 : GEOSGeom geosGeometry;
2256 248 : int geoCoordinatesNum = 2;
2257 248 : int valueType = 0;
2258 :
2259 248 : int valueSRID = (*valueWKB)->srid;
2260 :
2261 248 : if (is_wkb_nil(*valueWKB) || is_int_nil(*columnType) || is_int_nil(*columnSRID)) {
2262 0 : *resWKB = wkbNULLcopy();
2263 0 : if (*resWKB == NULL)
2264 0 : throw(MAL, "calc.wkb", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2265 : return MAL_SUCCEED;
2266 : }
2267 :
2268 : /* get the geosGeometry from the wkb */
2269 248 : geosGeometry = wkb2geos(*valueWKB);
2270 247 : if (geosGeometry == NULL)
2271 0 : throw(MAL, "calc.wkb", SQLSTATE(38000) "Geos operation wkb2geos failed");
2272 :
2273 : /* get the number of coordinates the geometry has */
2274 247 : geoCoordinatesNum = GEOSGeom_getCoordinateDimension_r(geoshandle, geosGeometry);
2275 : /* get the type of the geometry */
2276 247 : valueType = (GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1) << 2;
2277 :
2278 247 : if (geoCoordinatesNum > 2)
2279 94 : valueType += (1 << 1);
2280 94 : if (geoCoordinatesNum > 3)
2281 0 : valueType += 1;
2282 :
2283 247 : if (valueSRID != *columnSRID || valueType != *columnType) {
2284 113 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
2285 113 : throw(MAL, "calc.wkb", SQLSTATE(38000) "Geos column needs geometry(%d, %d) and value is geometry(%d, %d)\n", *columnType, *columnSRID, valueType, valueSRID);
2286 : }
2287 :
2288 : /* get the wkb from the geosGeometry */
2289 134 : *resWKB = geos2wkb(geosGeometry);
2290 135 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
2291 :
2292 135 : if (*resWKB == NULL)
2293 0 : throw(MAL, "calc.wkb", SQLSTATE(38000) "Geos operation geos2wkb failed");
2294 :
2295 : return MAL_SUCCEED;
2296 : }
2297 :
2298 : /*check if the geometry has z coordinate*/
2299 : str
2300 1 : geoHasZ(int *res, int *info)
2301 : {
2302 1 : if (is_int_nil(*info))
2303 0 : *res = int_nil;
2304 1 : else if (geometryHasZ(*info))
2305 0 : *res = 1;
2306 : else
2307 1 : *res = 0;
2308 1 : return MAL_SUCCEED;
2309 :
2310 : }
2311 :
2312 : /*check if the geometry has m coordinate*/
2313 : str
2314 1 : geoHasM(int *res, int *info)
2315 : {
2316 1 : if (is_int_nil(*info))
2317 0 : *res = int_nil;
2318 1 : else if (geometryHasM(*info))
2319 0 : *res = 1;
2320 : else
2321 1 : *res = 0;
2322 1 : return MAL_SUCCEED;
2323 : }
2324 :
2325 : /*check the geometry subtype*/
2326 : /*returns the length of the resulting string*/
2327 : str
2328 77 : geoGetType(char **res, int *info, int *flag)
2329 : {
2330 77 : if (is_int_nil(*info) || is_int_nil(*flag)) {
2331 0 : if ((*res = GDKstrdup(str_nil)) == NULL)
2332 0 : throw(MAL, "geom.getType", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2333 : return MAL_SUCCEED;
2334 : }
2335 78 : if ((*res = GDKstrdup(geom_type2str(*info >> 2, *flag))) == NULL)
2336 0 : throw(MAL, "geom.getType", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2337 : return MAL_SUCCEED;
2338 : }
2339 :
2340 : /* initialize geos */
2341 :
2342 : static str
2343 340 : geom_prelude(void)
2344 : {
2345 340 : mbrNIL.xmin = flt_nil;
2346 340 : mbrNIL.xmax = flt_nil;
2347 340 : mbrNIL.ymin = flt_nil;
2348 340 : mbrNIL.ymax = flt_nil;
2349 340 : if (libgeom_init() != GDK_SUCCEED)
2350 0 : throw(MAL, "geom.prelude", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2351 340 : TYPE_mbr = malAtomSize(sizeof(mbr), "mbr");
2352 340 : return MAL_SUCCEED;
2353 : }
2354 :
2355 : static str
2356 339 : geom_epilogue(void *ret)
2357 : {
2358 339 : (void) ret;
2359 339 : return MAL_SUCCEED;
2360 : }
2361 :
2362 : /* create the WKB out of the GEOSGeometry
2363 : * It makes sure to make all checks before returning
2364 : * the input geosGeometry should not be altered by this function
2365 : * return NULL on error */
2366 : wkb *
2367 1115 : geos2wkb(const GEOSGeometry *geosGeometry)
2368 : {
2369 1115 : size_t wkbLen = 0;
2370 1115 : unsigned char *w = NULL;
2371 1115 : wkb *geomWKB;
2372 :
2373 : // if the geosGeometry is NULL create a NULL WKB
2374 1115 : if (geosGeometry == NULL) {
2375 0 : return wkbNULLcopy();
2376 : }
2377 :
2378 1115 : GEOS_setWKBOutputDims_r(geoshandle, GEOSGeom_getCoordinateDimension_r(geoshandle, geosGeometry));
2379 1121 : w = GEOSGeomToWKB_buf_r(geoshandle, geosGeometry, &wkbLen);
2380 :
2381 1111 : if (w == NULL)
2382 : return NULL;
2383 :
2384 1111 : assert(wkbLen <= GDK_int_max);
2385 :
2386 1111 : geomWKB = GDKmalloc(wkb_size(wkbLen));
2387 : //If malloc failed create a NULL wkb
2388 1124 : if (geomWKB == NULL) {
2389 0 : GEOSFree_r(geoshandle, w);
2390 0 : return NULL;
2391 : }
2392 :
2393 1124 : geomWKB->len = (int) wkbLen;
2394 1124 : geomWKB->srid = GEOSGetSRID_r(geoshandle, geosGeometry);
2395 1123 : memcpy(&geomWKB->data, w, wkbLen);
2396 1123 : GEOSFree_r(geoshandle, w);
2397 :
2398 1118 : return geomWKB;
2399 : }
2400 :
2401 : /* gets the mbr from the geometry */
2402 : mbr *
2403 676 : mbrFromGeos(const GEOSGeom geosGeometry)
2404 : {
2405 676 : GEOSGeom envelope;
2406 676 : mbr *geomMBR;
2407 676 : double xmin = 0, ymin = 0, xmax = 0, ymax = 0;
2408 :
2409 676 : geomMBR = GDKmalloc(sizeof(mbr));
2410 681 : if (geomMBR == NULL) //problem in reserving space
2411 : return NULL;
2412 :
2413 : /* if input is null or GEOSEnvelope created exception then create a nill mbr */
2414 681 : if (!geosGeometry || (envelope = GEOSEnvelope_r(geoshandle, geosGeometry)) == NULL) {
2415 0 : *geomMBR = mbrNIL;
2416 0 : return geomMBR;
2417 : }
2418 :
2419 676 : if ((GEOSGeomTypeId_r(geoshandle, envelope) + 1) == wkbPoint_mdb) {
2420 : #if GEOS_CAPI_VERSION_MAJOR >= 1 && GEOS_CAPI_VERSION_MINOR >= 3
2421 420 : const GEOSCoordSequence *coords = GEOSGeom_getCoordSeq_r(geoshandle, envelope);
2422 : #else
2423 : const GEOSCoordSeq coords = GEOSGeom_getCoordSeq_r(geoshandle, envelope);
2424 : #endif
2425 425 : GEOSCoordSeq_getX_r(geoshandle, coords, 0, &xmin);
2426 423 : GEOSCoordSeq_getY_r(geoshandle, coords, 0, &ymin);
2427 419 : assert(GDK_flt_min <= xmin && xmin <= GDK_flt_max);
2428 419 : assert(GDK_flt_min <= ymin && ymin <= GDK_flt_max);
2429 419 : geomMBR->xmin = (float) xmin;
2430 419 : geomMBR->ymin = (float) ymin;
2431 419 : geomMBR->xmax = (float) xmin;
2432 419 : geomMBR->ymax = (float) ymin;
2433 : } else { // GEOSGeomTypeId_r(geoshandle, envelope) == GEOS_POLYGON
2434 : #if GEOS_CAPI_VERSION_MAJOR >= 1 && GEOS_CAPI_VERSION_MINOR >= 3
2435 253 : const GEOSGeometry *ring = GEOSGetExteriorRing_r(geoshandle, envelope);
2436 : #else
2437 : const GEOSGeom ring = GEOSGetExteriorRing_r(geoshandle, envelope);
2438 : #endif
2439 248 : if (ring) {
2440 : #if GEOS_CAPI_VERSION_MAJOR >= 1 && GEOS_CAPI_VERSION_MINOR >= 3
2441 248 : const GEOSCoordSequence *coords = GEOSGeom_getCoordSeq_r(geoshandle, ring);
2442 : #else
2443 : const GEOSCoordSeq coords = GEOSGeom_getCoordSeq_r(geoshandle, ring);
2444 : #endif
2445 251 : GEOSCoordSeq_getX_r(geoshandle, coords, 0, &xmin); //left-lower corner
2446 253 : GEOSCoordSeq_getY_r(geoshandle, coords, 0, &ymin);
2447 248 : GEOSCoordSeq_getX_r(geoshandle, coords, 2, &xmax); //right-upper corner
2448 250 : GEOSCoordSeq_getY_r(geoshandle, coords, 2, &ymax);
2449 243 : assert(GDK_flt_min <= xmin && xmin <= GDK_flt_max);
2450 243 : assert(GDK_flt_min <= ymin && ymin <= GDK_flt_max);
2451 243 : assert(GDK_flt_min <= xmax && xmax <= GDK_flt_max);
2452 243 : assert(GDK_flt_min <= ymax && ymax <= GDK_flt_max);
2453 243 : geomMBR->xmin = (float) xmin;
2454 243 : geomMBR->ymin = (float) ymin;
2455 243 : geomMBR->xmax = (float) xmax;
2456 243 : geomMBR->ymax = (float) ymax;
2457 : }
2458 : }
2459 662 : GEOSGeom_destroy_r(geoshandle, envelope);
2460 660 : return geomMBR;
2461 : }
2462 :
2463 : //Returns the wkb in a hex representation */
2464 : static char hexit[] = "0123456789ABCDEF";
2465 :
2466 : str
2467 0 : wkbAsBinary(char **toStr, wkb **geomWKB)
2468 : {
2469 0 : char *s;
2470 0 : int i;
2471 :
2472 0 : if (is_wkb_nil(*geomWKB)) {
2473 0 : if ((*toStr = GDKstrdup(str_nil)) == NULL)
2474 0 : throw(MAL, "geom.AsBinary", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2475 : return MAL_SUCCEED;
2476 : }
2477 0 : if ((*toStr = GDKmalloc(1 + (*geomWKB)->len * 2)) == NULL)
2478 0 : throw(MAL, "geom.AsBinary", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2479 :
2480 : s = *toStr;
2481 0 : for (i = 0; i < (*geomWKB)->len; i++) {
2482 0 : int val = ((*geomWKB)->data[i] >> 4) & 0xf;
2483 0 : *s++ = hexit[val];
2484 0 : val = (*geomWKB)->data[i] & 0xf;
2485 0 : *s++ = hexit[val];
2486 0 : TRC_DEBUG(GEOM, "%d: First: %c - Second: %c ==> Original %c (%d)\n", i, *(s-2), *(s-1), (*geomWKB)->data[i], (int)((*geomWKB)->data[i]));
2487 : }
2488 0 : *s = '\0';
2489 0 : return MAL_SUCCEED;
2490 : }
2491 :
2492 : static int
2493 23258 : decit(char hex)
2494 : {
2495 23258 : switch (hex) {
2496 : case '0':
2497 : return 0;
2498 : case '1':
2499 : return 1;
2500 : case '2':
2501 : return 2;
2502 : case '3':
2503 : return 3;
2504 : case '4':
2505 : return 4;
2506 : case '5':
2507 : return 5;
2508 : case '6':
2509 : return 6;
2510 : case '7':
2511 : return 7;
2512 : case '8':
2513 : return 8;
2514 : case '9':
2515 : return 9;
2516 : case 'A':
2517 : case 'a':
2518 : return 10;
2519 : case 'B':
2520 : case 'b':
2521 : return 11;
2522 : case 'C':
2523 : case 'c':
2524 : return 12;
2525 : case 'D':
2526 : case 'd':
2527 : return 13;
2528 : case 'E':
2529 : case 'e':
2530 : return 14;
2531 : case 'F':
2532 : case 'f':
2533 : return 15;
2534 : default:
2535 : return -1;
2536 : }
2537 : }
2538 :
2539 : str
2540 289 : wkbFromBinary(wkb **geomWKB, const char **inStr)
2541 : {
2542 289 : size_t strLength, wkbLength, i;
2543 289 : wkb *w;
2544 :
2545 289 : if (strNil(*inStr)) {
2546 0 : if ((*geomWKB = wkbNULLcopy()) == NULL)
2547 0 : throw(MAL, "geom.FromBinary", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2548 : return MAL_SUCCEED;
2549 : }
2550 :
2551 289 : strLength = strlen(*inStr);
2552 289 : if (strLength & 1)
2553 0 : throw(MAL, "geom.FromBinary", SQLSTATE(38000) "Geos odd length input string");
2554 :
2555 289 : wkbLength = strLength / 2;
2556 289 : assert(wkbLength <= GDK_int_max);
2557 :
2558 289 : w = GDKmalloc(wkb_size(wkbLength));
2559 289 : if (w == NULL)
2560 0 : throw(MAL, "geom.FromBinary", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2561 :
2562 : //compute the value for s
2563 11918 : for (i = 0; i < strLength; i += 2) {
2564 11629 : int firstHalf = decit((*inStr)[i]);
2565 11629 : int secondHalf = decit((*inStr)[i + 1]);
2566 11629 : if (firstHalf == -1 || secondHalf == -1) {
2567 0 : GDKfree(w);
2568 0 : throw(MAL, "geom.FromBinary", SQLSTATE(38000) "Geos incorrectly formatted input string");
2569 : }
2570 11629 : w->data[i / 2] = (firstHalf << 4) | secondHalf;
2571 : }
2572 :
2573 289 : w->len = (int) wkbLength;
2574 289 : w->srid = 0;
2575 289 : *geomWKB = w;
2576 :
2577 289 : return MAL_SUCCEED;
2578 : }
2579 :
2580 : str
2581 0 : mbrFromMBR(mbr **w, mbr **src)
2582 : {
2583 0 : *w = GDKmalloc(sizeof(mbr));
2584 0 : if (*w == NULL)
2585 0 : throw(MAL, "calc.mbr", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2586 :
2587 0 : **w = **src;
2588 0 : return MAL_SUCCEED;
2589 : }
2590 :
2591 : str
2592 1 : wkbFromWKB(wkb **w, wkb **src)
2593 : {
2594 1 : *w = GDKmalloc(wkb_size((*src)->len));
2595 1 : if (*w == NULL)
2596 0 : throw(MAL, "calc.wkb", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2597 :
2598 1 : if (is_wkb_nil(*src)) {
2599 0 : **w = wkb_nil;
2600 : } else {
2601 1 : (*w)->len = (*src)->len;
2602 1 : (*w)->srid = (*src)->srid;
2603 1 : memcpy((*w)->data, (*src)->data, (*src)->len);
2604 : }
2605 : return MAL_SUCCEED;
2606 : }
2607 :
2608 : /* creates a wkb from the given textual representation */
2609 : /* int* tpe is needed to verify that the type of the FromText function used is the
2610 : * same with the type of the geometry created from the wkt representation */
2611 : str
2612 1030 : wkbFromText(wkb **geomWKB, str *geomWKT, int *srid, int *tpe)
2613 : {
2614 1030 : size_t len = 0;
2615 1030 : int te = 0;
2616 1030 : str err;
2617 1030 : size_t parsedBytes;
2618 :
2619 1030 : *geomWKB = NULL;
2620 2060 : if (strNil(*geomWKT) || is_int_nil(*srid) || is_int_nil(*tpe)) {
2621 0 : if ((*geomWKB = wkbNULLcopy()) == NULL)
2622 0 : throw(MAL, "wkb.FromText", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2623 : return MAL_SUCCEED;
2624 : }
2625 1031 : err = wkbFROMSTR_withSRID(*geomWKT, &len, geomWKB, *srid, &parsedBytes);
2626 1023 : if (err != MAL_SUCCEED)
2627 : return err;
2628 :
2629 970 : if (is_wkb_nil(*geomWKB) || *tpe == 0 ||
2630 247 : *tpe == wkbGeometryCollection_mdb ||
2631 247 : ((te = *((*geomWKB)->data + 1) & 0x0f) + (*tpe > 2)) == *tpe) {
2632 : return MAL_SUCCEED;
2633 : }
2634 :
2635 49 : GDKfree(*geomWKB);
2636 49 : *geomWKB = NULL;
2637 :
2638 49 : te += (te > 2);
2639 49 : if (*tpe > 0 && te != *tpe)
2640 49 : throw(SQL, "wkb.FromText", SQLSTATE(38000) "Geometry not type '%d: %s' but '%d: %s' instead", *tpe, geom_type2str(*tpe, 0), te, geom_type2str(te, 0));
2641 0 : throw(MAL, "wkb.FromText", SQLSTATE(38000) "%s", "cannot parse string");
2642 : }
2643 :
2644 : /* create textual representation of the wkb */
2645 : str
2646 100 : wkbAsText(char **txt, wkb **geomWKB, int *withSRID)
2647 : {
2648 100 : size_t len = 0;
2649 100 : char *wkt = NULL;
2650 100 : const char sridTxt[] = "SRID:";
2651 :
2652 100 : if (is_wkb_nil(*geomWKB) || (withSRID && is_int_nil(*withSRID))) {
2653 0 : if ((*txt = GDKstrdup(str_nil)) == NULL)
2654 0 : throw(MAL, "geom.AsText", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2655 : return MAL_SUCCEED;
2656 : }
2657 :
2658 100 : if ((*geomWKB)->srid < 0)
2659 0 : throw(MAL, "geom.AsText", SQLSTATE(38000) "Geod negative SRID");
2660 :
2661 100 : if (wkbTOSTR(&wkt, &len, *geomWKB, false) < 0)
2662 0 : throw(MAL, "geom.AsText", SQLSTATE(38000) "Geos failed to create Text from Well Known Format");
2663 :
2664 100 : if (withSRID == NULL || *withSRID == 0) { //accepting NULL withSRID to make internal use of it easier
2665 65 : *txt = wkt;
2666 65 : return MAL_SUCCEED;
2667 : }
2668 :
2669 : /* 10 for maximum number of digits to represent an INT */
2670 35 : len = strlen(wkt) + 10 + strlen(sridTxt) + 2;
2671 35 : *txt = GDKmalloc(len);
2672 35 : if (*txt == NULL) {
2673 0 : GDKfree(wkt);
2674 0 : throw(MAL, "geom.AsText", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2675 : }
2676 :
2677 35 : snprintf(*txt, len, "%s%d;%s", sridTxt, (*geomWKB)->srid, wkt);
2678 :
2679 35 : GDKfree(wkt);
2680 35 : return MAL_SUCCEED;
2681 : }
2682 :
2683 : str
2684 0 : wkbMLineStringToPolygon(wkb **geomWKB, str *geomWKT, int *srid, int *flag)
2685 : {
2686 0 : int itemsNum = 0, i, type = wkbMultiLineString_mdb;
2687 0 : str ret = MAL_SUCCEED;
2688 0 : wkb *inputWKB = NULL;
2689 :
2690 0 : wkb **linestringsWKB;
2691 0 : double *linestringsArea;
2692 0 : bit ordered = 0;
2693 :
2694 0 : if (strNil(*geomWKT) || is_int_nil(*srid) || is_int_nil(*flag)) {
2695 0 : if ((*geomWKB = wkbNULLcopy()) == NULL)
2696 0 : throw(MAL, "geom.MLineStringToPolygon", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2697 : return MAL_SUCCEED;
2698 : }
2699 :
2700 0 : *geomWKB = NULL;
2701 :
2702 : //make wkb from wkt
2703 0 : ret = wkbFromText(&inputWKB, geomWKT, srid, &type);
2704 0 : if (ret != MAL_SUCCEED)
2705 : return ret;
2706 :
2707 : //read the number of linestrings in the input
2708 0 : ret = wkbNumGeometries(&itemsNum, &inputWKB);
2709 0 : if (ret != MAL_SUCCEED) {
2710 0 : GDKfree(inputWKB);
2711 0 : return ret;
2712 : }
2713 :
2714 0 : linestringsWKB = GDKmalloc(itemsNum * sizeof(wkb *));
2715 0 : linestringsArea = GDKmalloc(itemsNum * sizeof(double));
2716 0 : if (linestringsWKB == NULL || linestringsArea == NULL) {
2717 0 : itemsNum = 0;
2718 0 : ret = createException(MAL, "geom.MLineStringToPolygon", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2719 0 : goto bailout;
2720 : }
2721 :
2722 : //create one polygon for each lineString and compute the area of each of them
2723 0 : for (i = 1; i <= itemsNum; i++) {
2724 0 : wkb *polygonWKB;
2725 :
2726 0 : ret = wkbGeometryN(&linestringsWKB[i - 1], &inputWKB, &i);
2727 0 : if (ret != MAL_SUCCEED || linestringsWKB[i - 1] == NULL) {
2728 0 : itemsNum = i - 1;
2729 0 : goto bailout;
2730 : }
2731 :
2732 0 : ret = wkbMakePolygon(&polygonWKB, &linestringsWKB[i - 1], NULL, srid);
2733 0 : if (ret != MAL_SUCCEED) {
2734 0 : itemsNum = i;
2735 0 : goto bailout;
2736 : }
2737 :
2738 0 : ret = wkbArea(&linestringsArea[i - 1], &polygonWKB);
2739 0 : GDKfree(polygonWKB);
2740 0 : if (ret != MAL_SUCCEED) {
2741 0 : itemsNum = i;
2742 0 : goto bailout;
2743 : }
2744 : }
2745 :
2746 0 : GDKfree(inputWKB);
2747 0 : inputWKB = NULL;
2748 :
2749 : //order the linestrings with decreasing (polygons) area
2750 0 : while (!ordered) {
2751 0 : ordered = 1;
2752 :
2753 0 : for (i = 0; i < itemsNum - 1; i++) {
2754 0 : if (linestringsArea[i + 1] > linestringsArea[i]) {
2755 : //switch
2756 0 : wkb *linestringWKB = linestringsWKB[i];
2757 0 : double linestringArea = linestringsArea[i];
2758 :
2759 0 : linestringsWKB[i] = linestringsWKB[i + 1];
2760 0 : linestringsArea[i] = linestringsArea[i + 1];
2761 :
2762 0 : linestringsWKB[i + 1] = linestringWKB;
2763 0 : linestringsArea[i + 1] = linestringArea;
2764 :
2765 0 : ordered = 0;
2766 : }
2767 : }
2768 : }
2769 :
2770 0 : if (*flag == 0) {
2771 : //the biggest polygon is the external shell
2772 0 : GEOSCoordSeq coordSeq_external;
2773 0 : GEOSGeom externalGeometry, linearRingExternalGeometry, *internalGeometries, finalGeometry;
2774 :
2775 0 : externalGeometry = wkb2geos(linestringsWKB[0]);
2776 0 : if (externalGeometry == NULL) {
2777 0 : ret = createException(MAL, "geom.MLineStringToPolygon", SQLSTATE(38000) "Geos operation wkb2geos failed");
2778 0 : goto bailout;
2779 : }
2780 :
2781 0 : coordSeq_external = GEOSCoordSeq_clone_r(geoshandle, GEOSGeom_getCoordSeq_r(geoshandle, externalGeometry));
2782 0 : GEOSGeom_destroy_r(geoshandle, externalGeometry);
2783 0 : if (coordSeq_external == NULL) {
2784 0 : ret = createException(MAL, "geom.MLineStringToPolygon", SQLSTATE(38000) "Geos operation GEOSCoordSeq_clone failed");
2785 0 : goto bailout;
2786 : }
2787 0 : linearRingExternalGeometry = GEOSGeom_createLinearRing_r(geoshandle, coordSeq_external);
2788 0 : if (linearRingExternalGeometry == NULL) {
2789 0 : GEOSCoordSeq_destroy_r(geoshandle, coordSeq_external);
2790 0 : ret = createException(MAL, "geom.MLineStringToPolygon", SQLSTATE(38000) "Geos operation GEOSGeom_createLinearRing failed");
2791 0 : goto bailout;
2792 : }
2793 :
2794 : //all remaining should be internal
2795 0 : internalGeometries = GDKmalloc((itemsNum - 1) * sizeof(GEOSGeom));
2796 0 : if (internalGeometries == NULL) {
2797 0 : GEOSGeom_destroy_r(geoshandle, linearRingExternalGeometry);
2798 0 : ret = createException(MAL, "geom.MLineStringToPolygon", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2799 0 : goto bailout;
2800 : }
2801 0 : for (i = 1; i < itemsNum; i++) {
2802 0 : GEOSCoordSeq coordSeq_internal;
2803 0 : GEOSGeom internalGeometry;
2804 :
2805 0 : internalGeometry = wkb2geos(linestringsWKB[i]);
2806 0 : if (internalGeometry == NULL) {
2807 0 : GEOSGeom_destroy_r(geoshandle, linearRingExternalGeometry);
2808 0 : while (--i >= 1)
2809 0 : GEOSGeom_destroy_r(geoshandle, internalGeometries[i - 1]);
2810 0 : GDKfree(internalGeometries);
2811 0 : ret = createException(MAL, "geom.MLineStringToPolygon", SQLSTATE(38000) "Geos operation wkb2geos failed");
2812 0 : goto bailout;
2813 : }
2814 :
2815 0 : coordSeq_internal = GEOSCoordSeq_clone_r(geoshandle, GEOSGeom_getCoordSeq_r(geoshandle, internalGeometry));
2816 0 : GEOSGeom_destroy_r(geoshandle, internalGeometry);
2817 0 : if (coordSeq_internal == NULL) {
2818 0 : GEOSGeom_destroy_r(geoshandle, linearRingExternalGeometry);
2819 0 : while (--i >= 1)
2820 0 : GEOSGeom_destroy_r(geoshandle, internalGeometries[i - 1]);
2821 0 : GDKfree(internalGeometries);
2822 0 : ret = createException(MAL, "geom.MLineStringToPolygon", SQLSTATE(38000) "Geos operation wkb2geos failed");
2823 0 : goto bailout;
2824 : }
2825 0 : internalGeometries[i - 1] = GEOSGeom_createLinearRing_r(geoshandle, coordSeq_internal);
2826 0 : if (internalGeometries[i - 1] == NULL) {
2827 0 : GEOSGeom_destroy_r(geoshandle, linearRingExternalGeometry);
2828 0 : GEOSCoordSeq_destroy_r(geoshandle, coordSeq_internal);
2829 0 : while (--i >= 1)
2830 0 : GEOSGeom_destroy_r(geoshandle, internalGeometries[i - 1]);
2831 0 : GDKfree(internalGeometries);
2832 0 : ret = createException(MAL, "geom.MLineStringToPolygon", SQLSTATE(38000) "Geos operation GEOSGeom_createLinearRing failed");
2833 0 : goto bailout;
2834 : }
2835 : }
2836 :
2837 0 : finalGeometry = GEOSGeom_createPolygon_r(geoshandle, linearRingExternalGeometry, internalGeometries, itemsNum - 1);
2838 0 : GEOSGeom_destroy_r(geoshandle, linearRingExternalGeometry);
2839 0 : if (finalGeometry == NULL) {
2840 0 : for (i = 0; i < itemsNum - 1; i++)
2841 0 : GEOSGeom_destroy_r(geoshandle, internalGeometries[i]);
2842 0 : GDKfree(internalGeometries);
2843 0 : ret = createException(MAL, "geom.MLineStringToPolygon", SQLSTATE(38000) "Geos error creating Polygon from LinearRing");
2844 0 : goto bailout;
2845 : }
2846 0 : GDKfree(internalGeometries);
2847 : //check of the created polygon is valid
2848 0 : if (GEOSisValid_r(geoshandle, finalGeometry) != 1) {
2849 : //suppress the GEOS message
2850 0 : GDKclrerr();
2851 :
2852 0 : GEOSGeom_destroy_r(geoshandle, finalGeometry);
2853 :
2854 0 : ret = createException(MAL, "geom.MLineStringToPolygon", SQLSTATE(38000) "Geos the provided MultiLineString does not create a valid Polygon");
2855 0 : goto bailout;
2856 : }
2857 :
2858 0 : GEOSSetSRID_r(geoshandle, finalGeometry, *srid);
2859 0 : *geomWKB = geos2wkb(finalGeometry);
2860 0 : GEOSGeom_destroy_r(geoshandle, finalGeometry);
2861 0 : if (*geomWKB == NULL)
2862 0 : ret = createException(MAL, "geom.MLineStringToPolygon", SQLSTATE(38000) "Geos operation geos2wkb failed");
2863 0 : } else if (*flag == 1) {
2864 0 : ret = createException(MAL, "geom.MLineStringToPolygon", SQLSTATE(38000) "Geos multipolygon from string has not been defined");
2865 : } else {
2866 0 : ret = createException(MAL, "geom.MLineStringToPolygon", SQLSTATE(38000) "Geos unknown flag");
2867 : }
2868 :
2869 0 : bailout:
2870 0 : GDKfree(inputWKB);
2871 0 : for (i = 0; i < itemsNum; i++)
2872 0 : GDKfree(linestringsWKB[i]);
2873 0 : GDKfree(linestringsWKB);
2874 0 : GDKfree(linestringsArea);
2875 0 : return ret;
2876 : }
2877 :
2878 : str
2879 68 : wkbMakePoint(wkb **out, dbl *x, dbl *y, dbl *z, dbl *m, int *zmFlag)
2880 : {
2881 68 : GEOSGeom geosGeometry;
2882 68 : GEOSCoordSeq seq;
2883 :
2884 68 : if (is_dbl_nil(*x) || is_dbl_nil(*y) || is_dbl_nil(*z) || is_dbl_nil(*m) || is_int_nil(*zmFlag)) {
2885 0 : if ((*out = wkbNULLcopy()) == NULL)
2886 0 : throw(MAL, "geom.MakePoint", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2887 : return MAL_SUCCEED;
2888 : }
2889 :
2890 : //create the point from the coordinates
2891 68 : switch (*zmFlag) {
2892 56 : case 0: /* x, y */
2893 56 : seq = GEOSCoordSeq_create_r(geoshandle, 1, 2);
2894 56 : break;
2895 12 : case 1: /* x, y, m */
2896 : case 10: /* x, y, z */
2897 12 : seq = GEOSCoordSeq_create_r(geoshandle, 1, 3);
2898 12 : break;
2899 0 : case 11: /* x, y, z, m */
2900 0 : throw(MAL, "geom.MakePoint", SQLSTATE(38000) "Geos POINTZM is not supported");
2901 0 : default:
2902 0 : throw(MAL, "geom.MakePoint", SQLSTATE(38000) "Geos "ILLEGAL_ARGUMENT);
2903 : }
2904 :
2905 68 : if (seq == NULL)
2906 0 : throw(MAL, "geom.MakePoint", SQLSTATE(38000) "Geos operation GEOSCoordSeq_create failed");
2907 :
2908 136 : if (!GEOSCoordSeq_setOrdinate_r(geoshandle, seq, 0, 0, *x) ||
2909 68 : !GEOSCoordSeq_setOrdinate_r(geoshandle, seq, 0, 1, *y) ||
2910 68 : (*zmFlag == 1 && !GEOSCoordSeq_setOrdinate_r(geoshandle, seq, 0, 2, *m)) ||
2911 68 : (*zmFlag == 10 && !GEOSCoordSeq_setOrdinate_r(geoshandle, seq, 0, 2, *z))) {
2912 0 : GEOSCoordSeq_destroy_r(geoshandle, seq);
2913 0 : throw(MAL, "geom.MakePoint", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setOrdinate failed");
2914 : }
2915 :
2916 68 : if ((geosGeometry = GEOSGeom_createPoint_r(geoshandle, seq)) == NULL) {
2917 0 : GEOSCoordSeq_destroy_r(geoshandle, seq);
2918 0 : throw(MAL, "geom.MakePoint", SQLSTATE(38000) "Geos operation GEOSGeometry failed");
2919 : }
2920 :
2921 68 : *out = geos2wkb(geosGeometry);
2922 68 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
2923 :
2924 67 : if (is_wkb_nil(*out)) {
2925 0 : GDKfree(*out);
2926 0 : *out = NULL;
2927 0 : throw(MAL, "geom.MakePoint", SQLSTATE(38000) "Geos to create WKB from GEOSGeometry failed");
2928 : }
2929 :
2930 : return MAL_SUCCEED;
2931 : }
2932 :
2933 : /* common code for functions that return integer */
2934 : static str
2935 161 : wkbBasicInt(int *out, wkb *geom, int (*func) (GEOSContextHandle_t handle, const GEOSGeometry *), const char *name)
2936 : {
2937 161 : GEOSGeom geosGeometry;
2938 161 : str ret = MAL_SUCCEED;
2939 :
2940 161 : if (is_wkb_nil(geom)) {
2941 0 : *out = int_nil;
2942 0 : return MAL_SUCCEED;
2943 : }
2944 :
2945 160 : if ((geosGeometry = wkb2geos(geom)) == NULL)
2946 0 : throw(MAL, name, SQLSTATE(38000) "Geos operation wkb2geos failed");
2947 :
2948 164 : *out = (*func) (geoshandle, geosGeometry);
2949 :
2950 164 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
2951 :
2952 : //if there was an error returned by geos
2953 165 : if (GDKerrbuf && GDKerrbuf[0]) {
2954 : //create an exception with this name
2955 0 : ret = createException(MAL, name, SQLSTATE(38000) "Geos operation %s", GDKerrbuf);
2956 :
2957 : //clear the error buffer
2958 0 : GDKclrerr();
2959 : }
2960 :
2961 : return ret;
2962 : }
2963 :
2964 : /* returns the type of the geometry as a string*/
2965 : str
2966 77 : wkbGeometryType(char **out, wkb **geomWKB, int *flag)
2967 : {
2968 77 : int typeId = 0;
2969 77 : str ret = MAL_SUCCEED;
2970 :
2971 77 : ret = wkbBasicInt(&typeId, *geomWKB, GEOSGeomTypeId_r, "geom.GeometryType");
2972 78 : if (ret != MAL_SUCCEED)
2973 : return ret;
2974 79 : if (!is_int_nil(typeId)) /* geoGetType deals with nil */
2975 79 : typeId = (typeId + 1) << 2;
2976 79 : return geoGetType(out, &typeId, flag);
2977 : }
2978 :
2979 : /* returns the number of dimensions of the geometry */
2980 : str
2981 29 : wkbCoordDim(int *out, wkb **geom)
2982 : {
2983 29 : return wkbBasicInt(out, *geom, GEOSGeom_getCoordinateDimension_r, "geom.CoordDim");
2984 : }
2985 :
2986 : /* returns the inherent dimension of the geometry, e.g 0 for point */
2987 : str
2988 32 : wkbDimension(int *dimension, wkb **geomWKB)
2989 : {
2990 32 : return wkbBasicInt(dimension, *geomWKB, GEOSGeom_getDimensions_r, "geom.Dimension");
2991 : }
2992 :
2993 : /* returns the srid of the geometry */
2994 : str
2995 8 : wkbGetSRID(int *out, wkb **geomWKB)
2996 : {
2997 8 : return wkbBasicInt(out, *geomWKB, GEOSGetSRID_r, "geom.GetSRID");
2998 : }
2999 :
3000 : /* sets the srid of the geometry */
3001 : str
3002 7 : wkbSetSRID(wkb **resultGeomWKB, wkb **geomWKB, int *srid)
3003 : {
3004 7 : GEOSGeom geosGeometry;
3005 :
3006 7 : if (is_wkb_nil(*geomWKB) || is_int_nil(*srid)) {
3007 0 : if ((*resultGeomWKB = wkbNULLcopy()) == NULL)
3008 0 : throw(MAL, "geom.setSRID", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3009 : return MAL_SUCCEED;
3010 : }
3011 7 : if ((geosGeometry = wkb2geos(*geomWKB)) == NULL)
3012 0 : throw(MAL, "geom.setSRID", SQLSTATE(38000) "Geos operation wkb2geos failed");
3013 :
3014 7 : GEOSSetSRID_r(geoshandle, geosGeometry, *srid);
3015 7 : *resultGeomWKB = geos2wkb(geosGeometry);
3016 7 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3017 :
3018 7 : if (*resultGeomWKB == NULL)
3019 0 : throw(MAL, "geom.setSRID", SQLSTATE(38000) "Geos operation geos2wkb failed");
3020 :
3021 : return MAL_SUCCEED;
3022 : }
3023 :
3024 : /* depending on the specific function it returns the X,Y or Z coordinate of a point */
3025 : str
3026 22 : wkbGetCoordinate(dbl *out, wkb **geom, int *dimNum)
3027 : {
3028 22 : GEOSGeom geosGeometry;
3029 22 : const GEOSCoordSequence *gcs;
3030 22 : str err = MAL_SUCCEED;
3031 :
3032 22 : if (is_wkb_nil(*geom) || is_int_nil(*dimNum)) {
3033 0 : *out = dbl_nil;
3034 0 : return MAL_SUCCEED;
3035 : }
3036 :
3037 22 : geosGeometry = wkb2geos(*geom);
3038 22 : if (geosGeometry == NULL) {
3039 0 : *out = dbl_nil;
3040 0 : throw(MAL, "geom.GetCoordinate", SQLSTATE(38000) "Geos operation wkb2geos failed");
3041 : }
3042 :
3043 22 : if ((GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1) != wkbPoint_mdb) {
3044 4 : char *geomSTR;
3045 :
3046 4 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3047 4 : if ((err = wkbAsText(&geomSTR, geom, NULL)) != MAL_SUCCEED)
3048 : return err;
3049 4 : err = createException(MAL, "geom.GetCoordinate", SQLSTATE(38000) "Geometry \"%s\" not a Point", geomSTR);
3050 4 : GDKfree(geomSTR);
3051 4 : return err;
3052 : }
3053 :
3054 18 : gcs = GEOSGeom_getCoordSeq_r(geoshandle, geosGeometry);
3055 : /* gcs shouldn't be freed, it's internal to the GEOSGeom */
3056 :
3057 18 : if (gcs == NULL) {
3058 0 : err = createException(MAL, "geom.GetCoordinate", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
3059 18 : } else if (!GEOSCoordSeq_getOrdinate_r(geoshandle, gcs, 0, *dimNum, out))
3060 0 : err = createException(MAL, "geom.GetCoordinate", SQLSTATE(38000) "Geos operation GEOSCoordSeq_getOrdinate failed");
3061 18 : else if (isnan(*out))
3062 3 : *out = dbl_nil;
3063 18 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3064 :
3065 18 : return err;
3066 : }
3067 :
3068 : /*common code for functions that return geometry */
3069 : static str
3070 33 : wkbBasic(wkb **out, wkb **geom, GEOSGeometry *(*func) (GEOSContextHandle_t handle, const GEOSGeometry *), const char *name)
3071 : {
3072 33 : GEOSGeom geosGeometry, outGeometry;
3073 33 : str err = MAL_SUCCEED;
3074 :
3075 33 : if (is_wkb_nil(*geom)) {
3076 0 : if ((*out = wkbNULLcopy()) == NULL)
3077 0 : throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
3078 : return MAL_SUCCEED;
3079 : }
3080 33 : if ((geosGeometry = wkb2geos(*geom)) == NULL) {
3081 0 : *out = NULL;
3082 0 : throw(MAL, name, SQLSTATE(38000) "Geos operation wkb2geos failed");
3083 : }
3084 :
3085 33 : if ((outGeometry = (*func) (geoshandle, geosGeometry)) == NULL) {
3086 0 : err = createException(MAL, name, SQLSTATE(38000) "Geos operation GEOS%s failed", name + 5);
3087 : } else {
3088 : //set the srid equal to the srid of the initial geometry
3089 33 : if ((*geom)->srid) //GEOSSetSRID has assertion for srid != 0
3090 2 : GEOSSetSRID_r(geoshandle, outGeometry, (*geom)->srid);
3091 :
3092 33 : if ((*out = geos2wkb(outGeometry)) == NULL)
3093 0 : err = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
3094 :
3095 33 : GEOSGeom_destroy_r(geoshandle, outGeometry);
3096 : }
3097 33 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3098 :
3099 32 : return err;
3100 : }
3101 :
3102 : str
3103 32 : wkbBoundary(wkb **boundaryWKB, wkb **geomWKB)
3104 : {
3105 32 : return wkbBasic(boundaryWKB, geomWKB, GEOSBoundary_r, "geom.Boundary");
3106 : }
3107 :
3108 : str
3109 1 : wkbEnvelope(wkb **out, wkb **geom)
3110 : {
3111 1 : return wkbBasic(out, geom, GEOSEnvelope_r, "geom.Envelope");
3112 : }
3113 :
3114 : str
3115 0 : wkbEnvelopeFromCoordinates(wkb **out, dbl *xmin, dbl *ymin, dbl *xmax, dbl *ymax, int *srid)
3116 : {
3117 0 : GEOSGeom geosGeometry, linearRingGeometry;
3118 0 : GEOSCoordSeq coordSeq;
3119 :
3120 0 : if (is_dbl_nil(*xmin) || is_dbl_nil(*ymin) || is_dbl_nil(*xmax) || is_dbl_nil(*ymax) || is_int_nil(*srid)) {
3121 0 : if ((*out = wkbNULLcopy()) == NULL)
3122 0 : throw(MAL, "geom.MakeEnvelope", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3123 : return MAL_SUCCEED;
3124 : }
3125 :
3126 : //create the coordinates sequence
3127 0 : if ((coordSeq = GEOSCoordSeq_create_r(geoshandle, 5, 2)) == NULL)
3128 0 : throw(MAL, "geom.MakeEnvelope", SQLSTATE(38000) "Geos operation GEOSCoordSeq_create failed");
3129 :
3130 : //set the values
3131 0 : if (!GEOSCoordSeq_setX_r(geoshandle, coordSeq, 0, *xmin) ||
3132 0 : !GEOSCoordSeq_setY_r(geoshandle, coordSeq, 0, *ymin) ||
3133 0 : !GEOSCoordSeq_setX_r(geoshandle, coordSeq, 1, *xmin) ||
3134 0 : !GEOSCoordSeq_setY_r(geoshandle, coordSeq, 1, *ymax) ||
3135 0 : !GEOSCoordSeq_setX_r(geoshandle, coordSeq, 2, *xmax) ||
3136 0 : !GEOSCoordSeq_setY_r(geoshandle, coordSeq, 2, *ymax) ||
3137 0 : !GEOSCoordSeq_setX_r(geoshandle, coordSeq, 3, *xmax) ||
3138 0 : !GEOSCoordSeq_setY_r(geoshandle, coordSeq, 3, *ymin) ||
3139 0 : !GEOSCoordSeq_setX_r(geoshandle, coordSeq, 4, *xmin) ||
3140 0 : !GEOSCoordSeq_setY_r(geoshandle, coordSeq, 4, *ymin)) {
3141 0 : GEOSCoordSeq_destroy_r(geoshandle, coordSeq);
3142 0 : throw(MAL, "geom.MakeEnvelope", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setX/Y failed");
3143 : }
3144 :
3145 0 : linearRingGeometry = GEOSGeom_createLinearRing_r(geoshandle, coordSeq);
3146 0 : if (linearRingGeometry == NULL) {
3147 : //Gives segmentation fault GEOSCoordSeq_destroy_r(geoshandle, coordSeq);
3148 0 : GEOSCoordSeq_destroy_r(geoshandle, coordSeq);
3149 0 : throw(MAL, "geom.MakeEnvelope", SQLSTATE(38000) "Geos error creating LinearRing from coordinates");
3150 : }
3151 :
3152 0 : geosGeometry = GEOSGeom_createPolygon_r(geoshandle, linearRingGeometry, NULL, 0);
3153 0 : if (geosGeometry == NULL) {
3154 0 : GEOSGeom_destroy_r(geoshandle, linearRingGeometry);
3155 0 : throw(MAL, "geom.MakeEnvelope", SQLSTATE(38000) "Geos error creating Polygon from LinearRing");
3156 : }
3157 :
3158 0 : GEOSSetSRID_r(geoshandle, geosGeometry, *srid);
3159 :
3160 0 : *out = geos2wkb(geosGeometry);
3161 :
3162 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3163 :
3164 0 : return MAL_SUCCEED;
3165 : }
3166 :
3167 : str
3168 0 : wkbMakePolygon(wkb **out, wkb **external, bat *internalBAT_id, int *srid)
3169 : {
3170 0 : GEOSGeom geosGeometry, externalGeometry, linearRingGeometry;
3171 0 : bit closed = 0;
3172 0 : GEOSCoordSeq coordSeq_copy;
3173 0 : str err;
3174 :
3175 0 : if (is_wkb_nil(*external) || is_int_nil(*srid)) {
3176 0 : if ((*out = wkbNULLcopy()) == NULL)
3177 0 : throw(MAL, "geom.Polygon", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3178 : return MAL_SUCCEED;
3179 : }
3180 :
3181 0 : externalGeometry = wkb2geos(*external);
3182 0 : if (externalGeometry == NULL)
3183 0 : throw(MAL, "geom.Polygon", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3184 :
3185 : //check the type of the external geometry
3186 0 : if ((GEOSGeomTypeId_r(geoshandle, externalGeometry) + 1) != wkbLineString_mdb) {
3187 0 : *out = NULL;
3188 0 : GEOSGeom_destroy_r(geoshandle, externalGeometry);
3189 0 : throw(MAL, "geom.Polygon", SQLSTATE(38000) "Geometries should be LineString");
3190 : }
3191 : //check whether the linestring is closed
3192 0 : if ((err = wkbIsClosed(&closed, external)) != MAL_SUCCEED) {
3193 0 : GEOSGeom_destroy_r(geoshandle, externalGeometry);
3194 0 : return err;
3195 : }
3196 0 : if (!closed) {
3197 0 : *out = NULL;
3198 0 : GEOSGeom_destroy_r(geoshandle, externalGeometry);
3199 0 : throw(MAL, "geom.Polygon", SQLSTATE(38000) "Geos lineString should be closed");
3200 : }
3201 : //create a copy of the coordinates
3202 0 : coordSeq_copy = GEOSCoordSeq_clone_r(geoshandle, GEOSGeom_getCoordSeq_r(geoshandle, externalGeometry));
3203 0 : GEOSGeom_destroy_r(geoshandle, externalGeometry);
3204 0 : if (coordSeq_copy == NULL)
3205 0 : throw(MAL, "geom.Polygon", SQLSTATE(38000) "Geos operation GEOSCoordSeq_clone failed");
3206 :
3207 : //create a linearRing using the copy of the coordinates
3208 0 : linearRingGeometry = GEOSGeom_createLinearRing_r(geoshandle, coordSeq_copy);
3209 0 : if (linearRingGeometry == NULL) {
3210 0 : GEOSCoordSeq_destroy_r(geoshandle, coordSeq_copy);
3211 0 : throw(MAL, "geom.Polygon", SQLSTATE(38000) "Geos operation GEOSGeom_createLinearRing failed");
3212 : }
3213 :
3214 : //create a polygon using the linearRing
3215 0 : if (internalBAT_id == NULL) {
3216 0 : geosGeometry = GEOSGeom_createPolygon_r(geoshandle, linearRingGeometry, NULL, 0);
3217 0 : if (geosGeometry == NULL) {
3218 0 : *out = NULL;
3219 0 : GEOSGeom_destroy_r(geoshandle, linearRingGeometry);
3220 0 : throw(MAL, "geom.Polygon", SQLSTATE(38000) "Geos error creating Polygon from LinearRing");
3221 : }
3222 : } else {
3223 : /* TODO: Looks like incomplete code: what should be
3224 : * done with internalBAT_id? --sjoerd */
3225 : geosGeometry = NULL;
3226 : }
3227 :
3228 0 : GEOSSetSRID_r(geoshandle, geosGeometry, *srid);
3229 :
3230 0 : *out = geos2wkb(geosGeometry);
3231 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3232 :
3233 0 : return MAL_SUCCEED;
3234 : }
3235 :
3236 : //Gets two Point or LineString geometries and returns a line
3237 : str
3238 5 : wkbMakeLine(wkb **out, wkb **geom1WKB, wkb **geom2WKB)
3239 : {
3240 5 : GEOSGeom outGeometry, geom1Geometry, geom2Geometry;
3241 5 : GEOSCoordSeq outCoordSeq = NULL;
3242 5 : const GEOSCoordSequence *geom1CoordSeq = NULL, *geom2CoordSeq = NULL;
3243 5 : unsigned int i = 0, geom1Size = 0, geom2Size = 0;
3244 5 : unsigned geom1Dimension = 0, geom2Dimension = 0;
3245 5 : double x, y, z;
3246 5 : str err = MAL_SUCCEED;
3247 :
3248 5 : *out = NULL;
3249 5 : if (is_wkb_nil(*geom1WKB) || is_wkb_nil(*geom2WKB)) {
3250 0 : if ((*out = wkbNULLcopy()) == NULL)
3251 0 : throw(MAL, "geom.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3252 : return MAL_SUCCEED;
3253 : }
3254 :
3255 5 : geom1Geometry = wkb2geos(*geom1WKB);
3256 5 : if (!geom1Geometry) {
3257 0 : *out = NULL;
3258 0 : throw(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation wkb2geos failed");
3259 : }
3260 :
3261 5 : geom2Geometry = wkb2geos(*geom2WKB);
3262 5 : if (!geom2Geometry) {
3263 0 : *out = NULL;
3264 0 : GEOSGeom_destroy_r(geoshandle, geom1Geometry);
3265 0 : throw(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation wkb2geos failed");
3266 : }
3267 : //make sure the geometries are of the same srid
3268 5 : if (GEOSGetSRID_r(geoshandle, geom1Geometry) != GEOSGetSRID_r(geoshandle, geom2Geometry)) {
3269 0 : err = createException(MAL, "geom.MakeLine", SQLSTATE(38000) "Geometries of different SRID");
3270 0 : goto bailout;
3271 : }
3272 : //check the types of the geometries
3273 7 : if (GEOSGeomTypeId_r(geoshandle, geom1Geometry) + 1 != wkbPoint_mdb &&
3274 2 : GEOSGeomTypeId_r(geoshandle, geom1Geometry) + 1 != wkbLineString_mdb &&
3275 0 : GEOSGeomTypeId_r(geoshandle, geom2Geometry) + 1 != wkbPoint_mdb &&
3276 0 : GEOSGeomTypeId_r(geoshandle, geom2Geometry) + 1 != wkbLineString_mdb) {
3277 0 : err = createException(MAL, "geom.MakeLine", SQLSTATE(38000) "Geometries should be Point or LineString");
3278 0 : goto bailout;
3279 : }
3280 : //get the coordinate sequences of the geometries
3281 5 : if ((geom1CoordSeq = GEOSGeom_getCoordSeq_r(geoshandle, geom1Geometry)) == NULL ||
3282 5 : (geom2CoordSeq = GEOSGeom_getCoordSeq_r(geoshandle, geom2Geometry)) == NULL) {
3283 0 : err = createException(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
3284 0 : goto bailout;
3285 : }
3286 : //make sure that the dimensions of the geometries are the same
3287 10 : if (!GEOSCoordSeq_getDimensions_r(geoshandle, geom1CoordSeq, &geom1Dimension) ||
3288 5 : !GEOSCoordSeq_getDimensions_r(geoshandle, geom2CoordSeq, &geom2Dimension)) {
3289 0 : err = createException(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation GEOSGeom_getDimensions failed");
3290 0 : goto bailout;
3291 : }
3292 5 : if (geom1Dimension != geom2Dimension) {
3293 0 : err = createException(MAL, "geom.MakeLine", SQLSTATE(38000) "Geometries should be of the same dimension");
3294 0 : goto bailout;
3295 : }
3296 : //get the number of coordinates in the two geometries
3297 10 : if (!GEOSCoordSeq_getSize_r(geoshandle, geom1CoordSeq, &geom1Size) ||
3298 5 : !GEOSCoordSeq_getSize_r(geoshandle, geom2CoordSeq, &geom2Size)) {
3299 0 : err = createException(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation GEOSGeom_getSize failed");
3300 0 : goto bailout;
3301 : }
3302 : //create the coordSeq for the new geometry
3303 5 : if ((outCoordSeq = GEOSCoordSeq_create_r(geoshandle, geom1Size + geom2Size, geom1Dimension)) == NULL) {
3304 0 : err = createException(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation GEOSCoordSeq_create failed");
3305 0 : goto bailout;
3306 : }
3307 13 : for (i = 0; i < geom1Size; i++) {
3308 8 : GEOSCoordSeq_getX_r(geoshandle, geom1CoordSeq, i, &x);
3309 8 : GEOSCoordSeq_getY_r(geoshandle, geom1CoordSeq, i, &y);
3310 16 : if (!GEOSCoordSeq_setX_r(geoshandle, outCoordSeq, i, x) ||
3311 8 : !GEOSCoordSeq_setY_r(geoshandle, outCoordSeq, i, y)) {
3312 0 : err = createException(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation GEOSCoordSeq_set[XY] failed");
3313 0 : goto bailout;
3314 : }
3315 8 : if (geom1Dimension > 2) {
3316 0 : GEOSCoordSeq_getZ_r(geoshandle, geom1CoordSeq, i, &z);
3317 0 : if (!GEOSCoordSeq_setZ_r(geoshandle, outCoordSeq, i, z)) {
3318 0 : err = createException(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setZ failed");
3319 0 : goto bailout;
3320 : }
3321 : }
3322 : }
3323 10 : for (i = 0; i < geom2Size; i++) {
3324 5 : GEOSCoordSeq_getX_r(geoshandle, geom2CoordSeq, i, &x);
3325 5 : GEOSCoordSeq_getY_r(geoshandle, geom2CoordSeq, i, &y);
3326 10 : if (!GEOSCoordSeq_setX_r(geoshandle, outCoordSeq, i + geom1Size, x) ||
3327 5 : !GEOSCoordSeq_setY_r(geoshandle, outCoordSeq, i + geom1Size, y)) {
3328 0 : err = createException(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation GEOSCoordSeq_set[XY] failed");
3329 0 : goto bailout;
3330 : }
3331 5 : if (geom2Dimension > 2) {
3332 0 : GEOSCoordSeq_getZ_r(geoshandle, geom2CoordSeq, i, &z);
3333 0 : if (!GEOSCoordSeq_setZ_r(geoshandle, outCoordSeq, i + geom1Size, z)) {
3334 0 : err = createException(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation GEOSCoordSeq_setZ failed");
3335 0 : goto bailout;
3336 : }
3337 : }
3338 : }
3339 :
3340 5 : if ((outGeometry = GEOSGeom_createLineString_r(geoshandle, outCoordSeq)) == NULL) {
3341 0 : err = createException(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation GEOSGeom_createLineString failed");
3342 0 : goto bailout;
3343 : }
3344 5 : outCoordSeq = NULL;
3345 :
3346 5 : GEOSSetSRID_r(geoshandle, outGeometry, GEOSGetSRID_r(geoshandle, geom1Geometry));
3347 5 : *out = geos2wkb(outGeometry);
3348 5 : GEOSGeom_destroy_r(geoshandle, outGeometry);
3349 :
3350 0 : bailout:
3351 5 : if (outCoordSeq)
3352 0 : GEOSCoordSeq_destroy_r(geoshandle, outCoordSeq);
3353 5 : GEOSGeom_destroy_r(geoshandle, geom1Geometry);
3354 5 : GEOSGeom_destroy_r(geoshandle, geom2Geometry);
3355 5 : return err;
3356 : }
3357 :
3358 : //Gets a BAT with geometries and returns a single LineString
3359 : str
3360 1 : wkbMakeLineAggr(wkb **outWKB, bat *bid)
3361 : {
3362 1 : BAT *inBAT = NULL;
3363 1 : BATiter inBAT_iter;
3364 1 : BUN i;
3365 1 : wkb *aWKB, *bWKB;
3366 1 : str err;
3367 :
3368 : //get the BATs
3369 1 : if ((inBAT = BATdescriptor(*bid)) == NULL) {
3370 0 : throw(MAL, "geom.MakeLine", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
3371 : }
3372 :
3373 : /* TODO: what should be returned if the input BAT is less than
3374 : * two rows? --sjoerd */
3375 1 : if (BATcount(inBAT) == 0) {
3376 0 : BBPunfix(inBAT->batCacheid);
3377 0 : if ((*outWKB = wkbNULLcopy()) == NULL)
3378 0 : throw(MAL, "geom.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3379 : return MAL_SUCCEED;
3380 : }
3381 : //iterator over the BATs
3382 1 : inBAT_iter = bat_iterator(inBAT);
3383 1 : aWKB = (wkb *) BUNtvar(inBAT_iter, 0);
3384 1 : if (BATcount(inBAT) == 1) {
3385 0 : bat_iterator_end(&inBAT_iter);
3386 0 : err = wkbFromWKB(outWKB, &aWKB);
3387 0 : BBPunfix(inBAT->batCacheid);
3388 0 : if (err) {
3389 0 : freeException(err);
3390 0 : throw(MAL, "geom.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3391 : }
3392 : return MAL_SUCCEED;
3393 : }
3394 1 : bWKB = (wkb *) BUNtvar(inBAT_iter, 1);
3395 : //create the first line using the first two geometries
3396 1 : err = wkbMakeLine(outWKB, &aWKB, &bWKB);
3397 :
3398 : // add one more segment for each following row
3399 4 : for (i = 2; err == MAL_SUCCEED && i < BATcount(inBAT); i++) {
3400 2 : aWKB = *outWKB;
3401 2 : bWKB = (wkb *) BUNtvar(inBAT_iter, i);
3402 2 : *outWKB = NULL;
3403 :
3404 2 : err = wkbMakeLine(outWKB, &aWKB, &bWKB);
3405 2 : GDKfree(aWKB);
3406 : }
3407 :
3408 1 : bat_iterator_end(&inBAT_iter);
3409 1 : BBPunfix(inBAT->batCacheid);
3410 :
3411 1 : return err;
3412 : }
3413 :
3414 : static str
3415 4 : wkbExtractPointToCoordSeq(GEOSCoordSeq *outCoordSeq, wkb *inWKB, int index) {
3416 4 : double x,y;
3417 4 : str msg = MAL_SUCCEED;
3418 4 : GEOSGeom inGeometry;
3419 4 : const GEOSCoordSequence *inCoordSeq = NULL;
3420 :
3421 4 : inGeometry = wkb2geos(inWKB);
3422 4 : if (!inGeometry) {
3423 0 : throw(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation wkb2geos failed");
3424 : }
3425 4 : inCoordSeq = GEOSGeom_getCoordSeq_r(geoshandle, inGeometry);
3426 4 : GEOSCoordSeq_getX_r(geoshandle, inCoordSeq, 0, &x);
3427 4 : GEOSCoordSeq_getY_r(geoshandle, inCoordSeq, 0, &y);
3428 8 : if (!GEOSCoordSeq_setX_r(geoshandle, *outCoordSeq, index, x) ||
3429 4 : !GEOSCoordSeq_setY_r(geoshandle, *outCoordSeq, index, y)) {
3430 0 : GEOSGeom_destroy_r(geoshandle, inGeometry);
3431 0 : throw(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation GEOSCoordSeq_set[XY] failed");
3432 : }
3433 4 : GEOSGeom_destroy_r(geoshandle, inGeometry);
3434 4 : return msg;
3435 : }
3436 :
3437 : static str
3438 3 : wkbMakeLineAggrArray(wkb **outWKB, wkb **inWKB_array, int size) {
3439 3 : str msg = MAL_SUCCEED;
3440 3 : int i;
3441 3 : wkb *aWKB, *bWKB;
3442 3 : GEOSGeom outGeometry;
3443 3 : GEOSCoordSeq outCoordSeq = NULL;
3444 :
3445 : /* TODO: what should be returned if the input is less than
3446 : * two rows? --sjoerd */
3447 3 : if (size == 0) {
3448 0 : if ((*outWKB = wkbNULLcopy()) == NULL)
3449 0 : throw(MAL, "aggr.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3450 : return MAL_SUCCEED;
3451 : }
3452 3 : aWKB = inWKB_array[0];
3453 3 : if (size == 1) {
3454 1 : msg = wkbFromWKB(outWKB, &aWKB);
3455 1 : if (msg) {
3456 : return msg;
3457 : }
3458 : return MAL_SUCCEED;
3459 : }
3460 2 : bWKB = inWKB_array[1];
3461 : //create the first line using the first two geometries
3462 2 : outCoordSeq = GEOSCoordSeq_create_r(geoshandle, size, 2);
3463 :
3464 2 : msg = wkbExtractPointToCoordSeq(&outCoordSeq, aWKB, 0);
3465 2 : if (msg)
3466 : return msg;
3467 2 : msg = wkbExtractPointToCoordSeq(&outCoordSeq, bWKB, 1);
3468 2 : if (msg)
3469 : return msg;
3470 :
3471 : // add one more segment for each following row
3472 2 : for (i = 2; msg == MAL_SUCCEED && i < size; i++) {
3473 0 : msg = wkbExtractPointToCoordSeq(&outCoordSeq, inWKB_array[i], i);
3474 0 : if (msg)
3475 0 : return msg;
3476 : }
3477 2 : if ((outGeometry = GEOSGeom_createLineString_r(geoshandle, outCoordSeq)) == NULL) {
3478 0 : msg = createException(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation GEOSGeom_createLineString failed");
3479 0 : return msg;
3480 : }
3481 2 : *outWKB = geos2wkb(outGeometry);
3482 2 : GEOSGeom_destroy_r(geoshandle, outGeometry);
3483 : /* no need to clean outCoordSeq. it is destroyed via outGeometry */
3484 2 : return msg;
3485 : }
3486 :
3487 : //TODO Check SRID
3488 : //TODO Check if the input geometries are points
3489 : str
3490 1 : wkbMakeLineAggrSubGroupedCand(bat *outid, const bat *bid, const bat *gid, const bat *eid, const bat *sid, const bit *skip_nils)
3491 : {
3492 1 : BAT *b = NULL, *g = NULL, *s = NULL, *out = NULL;
3493 1 : BAT *sortedgroups, *sortedorder;
3494 1 : BATiter bi;
3495 1 : const oid *gids = NULL;
3496 1 : str msg = MAL_SUCCEED;
3497 :
3498 1 : oid min, max;
3499 1 : BUN ngrp = 0;
3500 1 : struct canditer ci;
3501 :
3502 1 : oid lastGrp = -1;
3503 1 : wkb **lines = NULL, **lineGroup = NULL;
3504 1 : int position = 0;
3505 :
3506 : //Not using these variables
3507 1 : (void) skip_nils;
3508 1 : (void) eid;
3509 :
3510 : //Get the BAT descriptors for the value, group and candidate bats
3511 1 : if ((b = BATdescriptor(*bid)) == NULL ||
3512 1 : (gid && !is_bat_nil(*gid) && (g = BATdescriptor(*gid)) == NULL) ||
3513 0 : (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL)) {
3514 0 : msg = createException(MAL, "aggr.MakeLine", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
3515 0 : goto free;
3516 : }
3517 :
3518 1 : if ((BATsort(&sortedgroups, &sortedorder, NULL, g, NULL, NULL, false, false, true)) != GDK_SUCCEED) {
3519 0 : msg = createException(MAL, "aggr.MakeLine", "BAT sort failed.");
3520 0 : goto free;
3521 : }
3522 :
3523 : //Project new order onto input bat IF the sortedorder isn't dense (in which case, the original input order is correct)
3524 1 : if (!BATtdense(sortedorder)) {
3525 1 : BAT *sortedinput = BATproject(sortedorder, b);
3526 1 : BBPreclaim(sortedorder);
3527 1 : if (sortedinput == NULL) {
3528 0 : BBPreclaim(sortedgroups);
3529 0 : msg = createException(MAL, "aggr.MakeLine", GDK_EXCEPTION);
3530 0 : goto free;
3531 : }
3532 1 : BBPunfix(b->batCacheid);
3533 1 : BBPunfix(g->batCacheid);
3534 1 : b = sortedinput;
3535 1 : g = sortedgroups;
3536 : }
3537 : else {
3538 0 : BBPunfix(sortedgroups->batCacheid);
3539 0 : BBPunfix(sortedorder->batCacheid);
3540 : }
3541 :
3542 : //Fill in the values of the group aggregate operation
3543 1 : if ((msg = (str) BATgroupaggrinit(b, g, NULL, s, &min, &max, &ngrp, &ci)) != NULL) {
3544 0 : msg = createException(MAL, "aggr.MakeLine", "%s", msg);
3545 0 : goto free;
3546 : }
3547 :
3548 : //Create a new BAT column of wkb type, with length equal to the number of groups
3549 1 : if ((out = COLnew(min, ATOMindex("wkb"), ngrp, TRANSIENT)) == NULL) {
3550 0 : msg = createException(MAL, "aggr.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3551 0 : goto free;
3552 : }
3553 :
3554 : //Create an array of WKB to hold the results of the MakeLine
3555 1 : if ((lines = GDKzalloc(sizeof(wkb *) * ngrp)) == NULL) {
3556 0 : msg = createException(MAL, "aggr.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3557 0 : BBPreclaim(out);
3558 0 : goto free;
3559 : }
3560 :
3561 : //Create an array of WKB to hold the points to be made into a line (for one group at a time)
3562 1 : if ((lineGroup = GDKzalloc(sizeof(wkb*) * ci.ncand)) == NULL) {
3563 0 : msg = createException(MAL, "aggr.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3564 0 : BBPreclaim(out);
3565 0 : goto free;
3566 : }
3567 :
3568 1 : if (g && !BATtdense(g))
3569 1 : gids = (const oid *)Tloc(g, 0);
3570 1 : bi = bat_iterator(b);
3571 :
3572 6 : for (BUN i = 0; i < ci.ncand; i++) {
3573 5 : oid o = canditer_next(&ci);
3574 5 : BUN p = o - b->hseqbase;
3575 5 : oid grp = gids ? gids[p] : g ? min + (oid)p : 0;
3576 5 : wkb *inWKB = (wkb *)BUNtvar(bi, p);
3577 :
3578 5 : if (grp != lastGrp) {
3579 3 : if (lastGrp != (oid)-1) {
3580 2 : msg = wkbMakeLineAggrArray(&lines[lastGrp], lineGroup, position);
3581 2 : position = 0;
3582 2 : if (msg != MAL_SUCCEED) {
3583 0 : GDKfree(lineGroup);
3584 0 : goto free;
3585 : }
3586 : }
3587 : lastGrp = grp;
3588 : }
3589 5 : lineGroup[position++] = inWKB;
3590 : }
3591 1 : msg = wkbMakeLineAggrArray(&lines[lastGrp], lineGroup, position);
3592 1 : GDKfree(lineGroup);
3593 1 : if (msg != MAL_SUCCEED)
3594 0 : goto free;
3595 :
3596 1 : if (BUNappendmulti(out, lines, ngrp, false) != GDK_SUCCEED) {
3597 0 : msg = createException(MAL, "geom.Union", SQLSTATE(38000) "BUNappend operation failed");
3598 0 : bat_iterator_end(&bi);
3599 0 : goto free;
3600 : }
3601 :
3602 4 : for (BUN i = 0; i < ngrp; i++)
3603 3 : GDKfree(lines[i]);
3604 1 : GDKfree(lines);
3605 1 : bat_iterator_end(&bi);
3606 :
3607 1 : *outid = out->batCacheid;
3608 1 : BBPkeepref(out);
3609 1 : BBPunfix(b->batCacheid);
3610 1 : if (g)
3611 1 : BBPunfix(g->batCacheid);
3612 1 : if (s)
3613 0 : BBPunfix(s->batCacheid);
3614 : return MAL_SUCCEED;
3615 0 : free:
3616 0 : if (lines) {
3617 0 : for (BUN i = 0; i < ngrp; i++)
3618 0 : GDKfree(lines[i]);
3619 0 : GDKfree(lines);
3620 : }
3621 0 : if (b)
3622 0 : BBPunfix(b->batCacheid);
3623 0 : if (g)
3624 0 : BBPunfix(g->batCacheid);
3625 0 : if (s)
3626 0 : BBPunfix(s->batCacheid);
3627 0 : BBPreclaim(out);
3628 : return msg;
3629 : }
3630 :
3631 : str
3632 1 : wkbMakeLineAggrSubGrouped (bat *out, const bat *bid, const bat *gid, const bat *eid, const bit *skip_nils) {
3633 1 : return wkbMakeLineAggrSubGroupedCand(out,bid,gid,eid,NULL,skip_nils);
3634 : }
3635 :
3636 : /* Returns the first or last point of a linestring */
3637 : static str
3638 2 : wkbBorderPoint(wkb **out, wkb **geom, GEOSGeometry *(*func) (GEOSContextHandle_t handle, const GEOSGeometry *), const char *name)
3639 : {
3640 2 : GEOSGeom geosGeometry;
3641 2 : GEOSGeom new;
3642 2 : str err = MAL_SUCCEED;
3643 :
3644 2 : if (is_wkb_nil(*geom)) {
3645 0 : if ((*out = wkbNULLcopy()) == NULL)
3646 0 : throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
3647 : return MAL_SUCCEED;
3648 : }
3649 :
3650 2 : *out = NULL;
3651 2 : geosGeometry = wkb2geos(*geom);
3652 2 : if (geosGeometry == NULL) {
3653 0 : throw(MAL, name, SQLSTATE(38000) "Geos operation wkb2geos failed");
3654 : }
3655 :
3656 2 : if (GEOSGeomTypeId_r(geoshandle, geosGeometry) != GEOS_LINESTRING) {
3657 0 : err = createException(MAL, name, SQLSTATE(38000) "Geometry not a LineString");
3658 : } else {
3659 2 : new = (*func) (geoshandle, geosGeometry);
3660 2 : if (new == NULL) {
3661 0 : err = createException(MAL, name, SQLSTATE(38000) "Geos operation GEOSGeomGet%s failed", name + 5);
3662 : } else {
3663 2 : *out = geos2wkb(new);
3664 2 : GEOSGeom_destroy_r(geoshandle, new);
3665 : }
3666 : }
3667 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3668 :
3669 2 : return err;
3670 : }
3671 :
3672 : /* Returns the first point in a linestring */
3673 : str
3674 1 : wkbStartPoint(wkb **out, wkb **geom)
3675 : {
3676 1 : return wkbBorderPoint(out, geom, GEOSGeomGetStartPoint_r, "geom.StartPoint");
3677 : }
3678 :
3679 : /* Returns the last point in a linestring */
3680 : str
3681 1 : wkbEndPoint(wkb **out, wkb **geom)
3682 : {
3683 1 : return wkbBorderPoint(out, geom, GEOSGeomGetEndPoint_r, "geom.EndPoint");
3684 : }
3685 :
3686 : static str
3687 58 : numPointsLineString(unsigned int *out, const GEOSGeometry *geosGeometry)
3688 : {
3689 : /* get the coordinates of the points comprising the geometry */
3690 58 : const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r(geoshandle, geosGeometry);
3691 :
3692 58 : if (coordSeq == NULL)
3693 0 : throw(MAL, "geom.NumPoints", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
3694 :
3695 : /* get the number of points in the geometry */
3696 58 : if (!GEOSCoordSeq_getSize_r(geoshandle, coordSeq, out)) {
3697 0 : *out = int_nil;
3698 0 : throw(MAL, "geom.NumPoints", SQLSTATE(38000) "Geos operation GEOSGeomGetNumPoints failed");
3699 : }
3700 :
3701 : return MAL_SUCCEED;
3702 : }
3703 :
3704 : static str
3705 11 : numPointsPolygon(unsigned int *out, const GEOSGeometry *geosGeometry)
3706 : {
3707 11 : const GEOSGeometry *exteriorRingGeometry;
3708 11 : int numInteriorRings = 0, i = 0;
3709 11 : str err;
3710 11 : unsigned int pointsN = 0;
3711 :
3712 : /* get the exterior ring of the polygon */
3713 11 : exteriorRingGeometry = GEOSGetExteriorRing_r(geoshandle, geosGeometry);
3714 11 : if (!exteriorRingGeometry) {
3715 0 : *out = int_nil;
3716 0 : throw(MAL, "geom.NumPoints", SQLSTATE(38000) "Geos operation GEOSGetExteriorRing failed");
3717 : }
3718 : //get the points in the exterior ring
3719 11 : if ((err = numPointsLineString(out, exteriorRingGeometry)) != MAL_SUCCEED) {
3720 0 : *out = int_nil;
3721 0 : return err;
3722 : }
3723 11 : pointsN = *out;
3724 :
3725 : //check the interior rings
3726 11 : numInteriorRings = GEOSGetNumInteriorRings_r(geoshandle, geosGeometry);
3727 11 : if (numInteriorRings == -1) {
3728 0 : *out = int_nil;
3729 0 : throw(MAL, "geom.NumPoints", SQLSTATE(38000) "Geos operation GEOSGetNumInteriorRings failed");
3730 : }
3731 : // iterate over the interiorRing and transform each one of them
3732 16 : for (i = 0; i < numInteriorRings; i++) {
3733 5 : if ((err = numPointsLineString(out, GEOSGetInteriorRingN_r(geoshandle, geosGeometry, i))) != MAL_SUCCEED) {
3734 0 : *out = int_nil;
3735 0 : return err;
3736 : }
3737 5 : pointsN += *out;
3738 : }
3739 :
3740 11 : *out = pointsN;
3741 11 : return MAL_SUCCEED;
3742 : }
3743 :
3744 : static str numPointsGeometry(unsigned int *out, const GEOSGeometry *geosGeometry);
3745 : static str
3746 9 : numPointsMultiGeometry(unsigned int *out, const GEOSGeometry *geosGeometry)
3747 : {
3748 9 : int geometriesNum, i;
3749 9 : const GEOSGeometry *multiGeometry = NULL;
3750 9 : str err;
3751 9 : unsigned int pointsN = 0;
3752 :
3753 9 : geometriesNum = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
3754 :
3755 40 : for (i = 0; i < geometriesNum; i++) {
3756 22 : multiGeometry = GEOSGetGeometryN_r(geoshandle, geosGeometry, i);
3757 22 : if ((err = numPointsGeometry(out, multiGeometry)) != MAL_SUCCEED) {
3758 0 : *out = int_nil;
3759 0 : return err;
3760 : }
3761 22 : pointsN += *out;
3762 : }
3763 :
3764 9 : *out = pointsN;
3765 9 : return MAL_SUCCEED;
3766 : }
3767 :
3768 : static str
3769 62 : numPointsGeometry(unsigned int *out, const GEOSGeometry *geosGeometry)
3770 : {
3771 62 : int geometryType = GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1;
3772 :
3773 : //check the type of the geometry
3774 62 : switch (geometryType) {
3775 42 : case wkbPoint_mdb:
3776 : case wkbLineString_mdb:
3777 : case wkbLinearRing_mdb:
3778 42 : return numPointsLineString(out, geosGeometry);
3779 11 : case wkbPolygon_mdb:
3780 11 : return numPointsPolygon(out, geosGeometry);
3781 9 : case wkbMultiPoint_mdb:
3782 : case wkbMultiLineString_mdb:
3783 : case wkbMultiPolygon_mdb:
3784 : case wkbGeometryCollection_mdb:
3785 9 : return numPointsMultiGeometry(out, geosGeometry);
3786 0 : default:
3787 0 : throw(MAL, "geom.NumPoints", SQLSTATE(38000) "Geos geometry type %s unknown", geom_type2str(geometryType, 0));
3788 : }
3789 : }
3790 :
3791 : /* Returns the number of points in a geometry */
3792 : str
3793 42 : wkbNumPoints(int *out, wkb **geom, int *check)
3794 : {
3795 42 : GEOSGeom geosGeometry;
3796 42 : int geometryType = 0;
3797 42 : str err = MAL_SUCCEED;
3798 42 : char *geomSTR = NULL;
3799 42 : unsigned int pointsNum;
3800 :
3801 42 : if (is_wkb_nil(*geom) || is_int_nil(*check)) {
3802 0 : *out = int_nil;
3803 0 : return MAL_SUCCEED;
3804 : }
3805 :
3806 42 : geosGeometry = wkb2geos(*geom);
3807 42 : if (geosGeometry == NULL) {
3808 0 : *out = int_nil;
3809 0 : throw(MAL, "geom.NumPoints", SQLSTATE(38000) "Geos operation wkb2geos failed");
3810 : }
3811 :
3812 42 : geometryType = GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1;
3813 :
3814 42 : if (*check && geometryType != wkbLineString_mdb) {
3815 2 : *out = int_nil;
3816 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3817 :
3818 2 : if ((err = wkbAsText(&geomSTR, geom, NULL)) == MAL_SUCCEED) {
3819 2 : err = createException(MAL, "geom.NumPoints", SQLSTATE(38000) "Geometry \"%s\" not a LineString", geomSTR);
3820 2 : GDKfree(geomSTR);
3821 : }
3822 2 : return err;
3823 : }
3824 :
3825 40 : if ((err = numPointsGeometry(&pointsNum, geosGeometry)) != MAL_SUCCEED) {
3826 0 : *out = int_nil;
3827 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3828 0 : return err;
3829 : }
3830 :
3831 40 : if (pointsNum > INT_MAX) {
3832 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3833 0 : *out = int_nil;
3834 0 : throw(MAL, "geom.NumPoints", SQLSTATE(38000) "Geos operation Overflow");
3835 : }
3836 :
3837 40 : *out = pointsNum;
3838 40 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3839 :
3840 40 : return MAL_SUCCEED;
3841 : }
3842 :
3843 : /* Returns the n-th point of the geometry */
3844 : str
3845 1 : wkbPointN(wkb **out, wkb **geom, int *n)
3846 : {
3847 1 : int rN = -1;
3848 1 : GEOSGeom geosGeometry;
3849 1 : GEOSGeom new;
3850 1 : str err = MAL_SUCCEED;
3851 :
3852 1 : if (is_wkb_nil(*geom) || is_int_nil(*n)) {
3853 0 : if ((*out = wkbNULLcopy()) == NULL)
3854 0 : throw(MAL, "geom.PointN", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3855 : return MAL_SUCCEED;
3856 : }
3857 :
3858 1 : geosGeometry = wkb2geos(*geom);
3859 1 : if (geosGeometry == NULL) {
3860 0 : *out = NULL;
3861 0 : throw(MAL, "geom.PointN", SQLSTATE(38000) "Geos operation wkb2geos failed");
3862 : }
3863 :
3864 1 : if (GEOSGeomTypeId_r(geoshandle, geosGeometry) != GEOS_LINESTRING) {
3865 0 : *out = NULL;
3866 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3867 0 : throw(MAL, "geom.PointN", SQLSTATE(38000) "Geometry not a LineString");
3868 : }
3869 : //check number of points
3870 1 : rN = GEOSGeomGetNumPoints_r(geoshandle, geosGeometry);
3871 1 : if (rN == -1) {
3872 0 : *out = NULL;
3873 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3874 0 : throw(MAL, "geom.PointN", SQLSTATE(38000) "Geos operation GEOSGeomGetNumPoints failed");
3875 : }
3876 :
3877 1 : if (rN <= *n || *n < 0) {
3878 0 : *out = NULL;
3879 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3880 0 : throw(MAL, "geom.PointN", SQLSTATE(38000) "Geos unable to retrieve point %d (not enough points)", *n);
3881 : }
3882 :
3883 1 : if ((new = GEOSGeomGetPointN_r(geoshandle, geosGeometry, *n)) == NULL) {
3884 0 : err = createException(MAL, "geom.PointN", SQLSTATE(38000) "Geos operation GEOSGeomGetPointN failed");
3885 : } else {
3886 1 : if ((*out = geos2wkb(new)) == NULL)
3887 0 : err = createException(MAL, "geom.PointN", SQLSTATE(38000) "Geos operation GEOSGeomGetPointN failed");
3888 1 : GEOSGeom_destroy_r(geoshandle, new);
3889 : }
3890 1 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3891 :
3892 1 : return err;
3893 : }
3894 :
3895 : /* Returns the exterior ring of the polygon*/
3896 : str
3897 2 : wkbExteriorRing(wkb **exteriorRingWKB, wkb **geom)
3898 : {
3899 2 : GEOSGeom geosGeometry;
3900 2 : const GEOSGeometry *exteriorRingGeometry;
3901 2 : str err = MAL_SUCCEED;
3902 :
3903 2 : if (is_wkb_nil(*geom)) {
3904 0 : if ((*exteriorRingWKB = wkbNULLcopy()) == NULL)
3905 0 : throw(MAL, "geom.ExteriorRing", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3906 : return MAL_SUCCEED;
3907 : }
3908 :
3909 2 : geosGeometry = wkb2geos(*geom);
3910 2 : if (geosGeometry == NULL) {
3911 0 : *exteriorRingWKB = NULL;
3912 0 : throw(MAL, "geom.ExteriorRing", SQLSTATE(38000) "Geos operation wkb2geos failed");
3913 : }
3914 :
3915 2 : if (GEOSGeomTypeId_r(geoshandle, geosGeometry) != GEOS_POLYGON) {
3916 0 : *exteriorRingWKB = NULL;
3917 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3918 0 : throw(MAL, "geom.ExteriorRing", SQLSTATE(38000) "Geometry not a Polygon");
3919 :
3920 : }
3921 : /* get the exterior ring of the geometry */
3922 2 : if ((exteriorRingGeometry = GEOSGetExteriorRing_r(geoshandle, geosGeometry)) == NULL)
3923 0 : err = createException(MAL, "geom.ExteriorRing", SQLSTATE(38000) "Geos operation GEOSGetExteriorRing failed");
3924 : else {
3925 : /* get the wkb representation of it */
3926 2 : if ((*exteriorRingWKB = geos2wkb(exteriorRingGeometry)) == NULL)
3927 0 : err = createException(MAL, "geom.ExteriorRing", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3928 : }
3929 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3930 :
3931 2 : return err;
3932 : }
3933 :
3934 : /* Returns the n-th interior ring of a polygon */
3935 : str
3936 1 : wkbInteriorRingN(wkb **interiorRingWKB, wkb **geom, int *ringNum)
3937 : {
3938 1 : GEOSGeom geosGeometry = NULL;
3939 1 : const GEOSGeometry *interiorRingGeometry;
3940 1 : int rN = -1;
3941 1 : str err = MAL_SUCCEED;
3942 :
3943 : //initialize to NULL
3944 1 : *interiorRingWKB = NULL;
3945 :
3946 1 : if (is_wkb_nil(*geom) || is_int_nil(*ringNum)) {
3947 0 : if ((*interiorRingWKB = wkbNULLcopy()) == NULL)
3948 0 : throw(MAL, "geom.InteriorRingN", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3949 : return MAL_SUCCEED;
3950 : }
3951 :
3952 1 : geosGeometry = wkb2geos(*geom);
3953 1 : if (geosGeometry == NULL) {
3954 0 : *interiorRingWKB = NULL;
3955 0 : throw(MAL, "geom.InteriorRingN", SQLSTATE(38000) "Geos operation wkb2geos failed");
3956 : }
3957 :
3958 1 : if ((GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1) != wkbPolygon_mdb) {
3959 0 : *interiorRingWKB = NULL;
3960 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3961 0 : throw(MAL, "geom.InteriorRingN", SQLSTATE(38000) "Geometry not a Polygon");
3962 :
3963 : }
3964 : //check number of internal rings
3965 1 : rN = GEOSGetNumInteriorRings_r(geoshandle, geosGeometry);
3966 1 : if (rN == -1) {
3967 0 : *interiorRingWKB = NULL;
3968 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3969 0 : throw(MAL, "geom.InteriorRingN", SQLSTATE(38000) "Geos operation GEOSGetInteriorRingN failed.");
3970 : }
3971 :
3972 1 : if (rN < *ringNum || *ringNum <= 0) {
3973 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3974 : //NOT AN ERROR throw(MAL, "geom.interiorRingN", SQLSTATE(38000) "Geos operation GEOSGetInteriorRingN failed. Not enough interior rings");
3975 0 : if ((*interiorRingWKB = wkbNULLcopy()) == NULL)
3976 0 : throw(MAL, "geom.InteriorRingN", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3977 : return MAL_SUCCEED;
3978 : }
3979 :
3980 : /* get the interior ring of the geometry */
3981 1 : if ((interiorRingGeometry = GEOSGetInteriorRingN_r(geoshandle, geosGeometry, *ringNum - 1)) == NULL) {
3982 0 : err = createException(MAL, "geom.InteriorRingN", SQLSTATE(38000) "Geos operation GEOSGetInteriorRingN failed");
3983 : } else {
3984 : /* get the wkb representation of it */
3985 1 : if ((*interiorRingWKB = geos2wkb(interiorRingGeometry)) == NULL)
3986 0 : err = createException(MAL, "geom.InteriorRingN", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3987 : }
3988 1 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3989 :
3990 1 : return err;
3991 : }
3992 :
3993 : /* Returns the number of interior rings in the first polygon of the provided geometry
3994 : * plus the exterior ring depending on the value of exteriorRing*/
3995 : str
3996 27 : wkbNumRings(int *out, wkb **geom, int *exteriorRing)
3997 : {
3998 27 : str ret = MAL_SUCCEED;
3999 27 : bit empty;
4000 27 : GEOSGeom geosGeometry;
4001 :
4002 27 : if (is_wkb_nil(*geom) || is_int_nil(*exteriorRing)) {
4003 0 : *out = int_nil;
4004 0 : return MAL_SUCCEED;
4005 : }
4006 :
4007 : //check if the geometry is empty
4008 27 : if ((ret = wkbIsEmpty(&empty, geom)) != MAL_SUCCEED) {
4009 : return ret;
4010 : }
4011 27 : if (empty) {
4012 : //the geometry is empty
4013 0 : *out = 0;
4014 0 : return MAL_SUCCEED;
4015 : }
4016 : //check the type of the geometry
4017 27 : geosGeometry = wkb2geos(*geom);
4018 :
4019 27 : if (geosGeometry == NULL)
4020 0 : throw(MAL, "geom.NumRings", SQLSTATE(38000) "Geos problem converting WKB to GEOS");
4021 :
4022 27 : if (GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1 == wkbMultiPolygon_mdb) {
4023 : //use the first polygon as done by PostGIS
4024 8 : wkb *new = geos2wkb(GEOSGetGeometryN_r(geoshandle, geosGeometry, 0));
4025 8 : if (new == NULL) {
4026 0 : ret = createException(MAL, "geom.NumRings", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4027 : } else {
4028 8 : ret = wkbBasicInt(out, new, GEOSGetNumInteriorRings_r, "geom.NumRings");
4029 8 : GDKfree(new);
4030 : }
4031 19 : } else if (GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1 == wkbPolygon_mdb) {
4032 9 : ret = wkbBasicInt(out, *geom, GEOSGetNumInteriorRings_r, "geom.NumRings");
4033 : } else {
4034 : //It is not a polygon so the number of rings is 0
4035 10 : *out = -*exteriorRing; /* compensate for += later */
4036 : }
4037 :
4038 27 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4039 :
4040 27 : if (ret != MAL_SUCCEED)
4041 : return ret;
4042 :
4043 27 : *out += *exteriorRing;
4044 :
4045 27 : return MAL_SUCCEED;
4046 : }
4047 :
4048 : /* it handles functions that take as input a single geometry and return Boolean */
4049 : static str
4050 810 : wkbBasicBoolean(bit *out, wkb **geom, char (*func) (GEOSContextHandle_t handle, const GEOSGeometry *), const char *name)
4051 : {
4052 810 : int ret;
4053 810 : GEOSGeom geosGeometry;
4054 :
4055 810 : if (is_wkb_nil(*geom)) {
4056 0 : *out = bit_nil;
4057 0 : return MAL_SUCCEED;
4058 : }
4059 :
4060 806 : geosGeometry = wkb2geos(*geom);
4061 812 : if (geosGeometry == NULL)
4062 0 : throw(MAL, name, SQLSTATE(38000) "Geos operation wkb2geom failed");
4063 :
4064 812 : ret = (*func) (geoshandle, geosGeometry); //it is supposed to return char but treating it as such gives wrong results
4065 810 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4066 :
4067 814 : if (ret == 2) {
4068 0 : GDKclrerr();
4069 0 : ret = 0;
4070 : }
4071 :
4072 814 : *out = ret;
4073 :
4074 814 : return MAL_SUCCEED;
4075 : }
4076 :
4077 : /* the function checks whether the geometry is closed. GEOS works only with
4078 : * linestring geometries but PostGIS returns true in any geometry that is not
4079 : * a linestring. I made it to be like PostGIS */
4080 : static str
4081 36 : geosIsClosed(bit *out, const GEOSGeometry *geosGeometry)
4082 : {
4083 36 : int geometryType = GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1;
4084 36 : int i = 0;
4085 36 : str err;
4086 36 : int geometriesNum;
4087 :
4088 36 : *out = bit_nil;
4089 :
4090 36 : switch (geometryType) {
4091 0 : case -1:
4092 0 : throw(MAL, "geom.IsClosed", SQLSTATE(38000) "Geos operation GEOSGeomTypeId failed");
4093 11 : case wkbPoint_mdb:
4094 : case wkbPolygon_mdb:
4095 : case wkbMultiPoint_mdb:
4096 : case wkbMultiPolygon_mdb:
4097 : //In all these case it is always true
4098 11 : *out = 1;
4099 11 : break;
4100 18 : case wkbLineString_mdb:
4101 : //check
4102 18 : if ((i = GEOSisClosed_r(geoshandle, geosGeometry)) == 2)
4103 0 : throw(MAL, "geom.IsClosed", SQLSTATE(38000) "Geos operation GEOSisClosed failed");
4104 18 : *out = i;
4105 18 : break;
4106 7 : case wkbMultiLineString_mdb:
4107 : case wkbGeometryCollection_mdb:
4108 : //check each one separately
4109 7 : geometriesNum = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
4110 7 : if (geometriesNum < 0)
4111 0 : throw(MAL, "geom.IsClosed", SQLSTATE(38000) "Geos operation GEOSGetNumGeometries failed");
4112 :
4113 15 : for (i = 0; i < geometriesNum; i++) {
4114 13 : const GEOSGeometry *gN = GEOSGetGeometryN_r(geoshandle, geosGeometry, i);
4115 13 : if (!gN)
4116 0 : throw(MAL, "geom.IsClosed", SQLSTATE(38000) "Geos operation GEOSGetGeometryN failed");
4117 :
4118 13 : if ((err = geosIsClosed(out, gN)) != MAL_SUCCEED) {
4119 0 : return err;
4120 : }
4121 :
4122 13 : if (!*out) //no reason to check further logical AND will always be 0
4123 : return MAL_SUCCEED;
4124 : }
4125 :
4126 : break;
4127 0 : default:
4128 0 : throw(MAL, "geom.IsClosed", SQLSTATE(38000) "Geos geometry type unknown");
4129 : }
4130 :
4131 : return MAL_SUCCEED;
4132 : }
4133 :
4134 : str
4135 24 : wkbIsClosed(bit *out, wkb **geomWKB)
4136 : {
4137 24 : str err;
4138 24 : GEOSGeom geosGeometry;
4139 :
4140 24 : if (is_wkb_nil(*geomWKB)) {
4141 0 : *out = bit_nil;
4142 0 : return MAL_SUCCEED;
4143 : }
4144 :
4145 : //if empty geometry return false
4146 24 : if ((err = wkbIsEmpty(out, geomWKB)) != MAL_SUCCEED) {
4147 : return err;
4148 : }
4149 24 : if (*out) {
4150 1 : *out = 0;
4151 1 : return MAL_SUCCEED;
4152 : }
4153 :
4154 23 : geosGeometry = wkb2geos(*geomWKB);
4155 23 : if (geosGeometry == NULL)
4156 0 : throw(MAL, "geom.IsClosed", SQLSTATE(38000) "Geos operation wkb2geos failed");
4157 :
4158 23 : err = geosIsClosed(out, geosGeometry);
4159 23 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4160 :
4161 23 : return err;
4162 : }
4163 :
4164 : str
4165 761 : wkbIsEmpty(bit *out, wkb **geomWKB)
4166 : {
4167 761 : return wkbBasicBoolean(out, geomWKB, GEOSisEmpty_r, "geom.IsEmpty");
4168 : }
4169 :
4170 : str
4171 16 : wkbIsRing(bit *out, wkb **geomWKB)
4172 : {
4173 16 : return wkbBasicBoolean(out, geomWKB, GEOSisRing_r, "geom.IsRing");
4174 : }
4175 :
4176 : str
4177 15 : wkbIsSimple(bit *out, wkb **geomWKB)
4178 : {
4179 15 : return wkbBasicBoolean(out, geomWKB, GEOSisSimple_r, "geom.IsSimple");
4180 : }
4181 :
4182 : /*geom prints a message saying the reason why the geometry is not valid but
4183 : * since there is also isValidReason I skip this here */
4184 : str
4185 18 : wkbIsValid(bit *out, wkb **geomWKB)
4186 : {
4187 18 : str err = wkbBasicBoolean(out, geomWKB, GEOSisValid_r, "geom.IsValid");
4188 : /* GOESisValid may cause GDKerror to be called: ignore it */
4189 18 : if (err == MAL_SUCCEED)
4190 18 : GDKclrerr();
4191 18 : return err;
4192 : }
4193 :
4194 : str
4195 0 : wkbIsValidReason(char **reason, wkb **geomWKB)
4196 : {
4197 0 : GEOSGeom geosGeometry;
4198 0 : char *GEOSReason = NULL;
4199 :
4200 0 : if (is_wkb_nil(*geomWKB)) {
4201 0 : if ((*reason = GDKstrdup(str_nil)) == NULL)
4202 0 : throw(MAL, "geom.IsValidReason", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4203 : return MAL_SUCCEED;
4204 : }
4205 :
4206 0 : geosGeometry = wkb2geos(*geomWKB);
4207 0 : if (geosGeometry == NULL)
4208 0 : throw(MAL, "geom.IsValidReason", SQLSTATE(38000) "Geos operation wkb2geom failed");
4209 :
4210 0 : GEOSReason = GEOSisValidReason_r(geoshandle, geosGeometry);
4211 :
4212 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4213 :
4214 0 : if (GEOSReason == NULL)
4215 0 : throw(MAL, "geom.IsValidReason", SQLSTATE(38000) "Geos operation GEOSisValidReason failed");
4216 :
4217 0 : *reason = GDKstrdup(GEOSReason);
4218 0 : GEOSFree_r(geoshandle, GEOSReason);
4219 0 : if (*reason == NULL)
4220 0 : throw(MAL, "geom.IsValidReason", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4221 :
4222 : return MAL_SUCCEED;
4223 : }
4224 :
4225 : /* I should check it since it does not work */
4226 : str
4227 0 : wkbIsValidDetail(char **out, wkb **geom)
4228 : {
4229 0 : int res = -1;
4230 0 : char *GEOSreason = NULL;
4231 0 : GEOSGeom GEOSlocation = NULL;
4232 0 : GEOSGeom geosGeometry;
4233 :
4234 0 : if (is_wkb_nil(*geom)) {
4235 0 : if ((*out = GDKstrdup(str_nil)) == NULL)
4236 0 : throw(MAL, "geom.IsValidReason", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4237 : return MAL_SUCCEED;
4238 : }
4239 :
4240 0 : if ((geosGeometry = wkb2geos(*geom)) == NULL) {
4241 0 : *out = NULL;
4242 0 : throw(MAL, "geom.IsValidDetail", SQLSTATE(38000) "Geos operation wkb2geos failed");
4243 : }
4244 :
4245 0 : res = GEOSisValidDetail_r(geoshandle, geosGeometry, 1, &GEOSreason, &GEOSlocation);
4246 :
4247 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4248 :
4249 0 : if (res == 2) {
4250 0 : throw(MAL, "geom.IsValidDetail", SQLSTATE(38000) "Geos operation GEOSisValidDetail failed");
4251 : }
4252 :
4253 0 : *out = GDKstrdup(GEOSreason);
4254 :
4255 0 : GEOSFree_r(geoshandle, GEOSreason);
4256 0 : GEOSGeom_destroy_r(geoshandle, GEOSlocation);
4257 :
4258 0 : if (*out == NULL)
4259 0 : throw(MAL, "geom.IsValidReason", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4260 :
4261 : return MAL_SUCCEED;
4262 : }
4263 :
4264 : /* returns the area of the geometry */
4265 : str
4266 2 : wkbArea(dbl *out, wkb **geomWKB)
4267 : {
4268 2 : GEOSGeom geosGeometry;
4269 :
4270 2 : if (is_wkb_nil(*geomWKB)) {
4271 0 : *out = dbl_nil;
4272 0 : return MAL_SUCCEED;
4273 : }
4274 :
4275 2 : geosGeometry = wkb2geos(*geomWKB);
4276 2 : if (geosGeometry == NULL) {
4277 0 : *out = dbl_nil;
4278 0 : throw(MAL, "geom.Area", SQLSTATE(38000) "Geos operation wkb2geos failed");
4279 : }
4280 :
4281 2 : if (!GEOSArea_r(geoshandle, geosGeometry, out)) {
4282 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4283 0 : *out = dbl_nil;
4284 0 : throw(MAL, "geom.Area", SQLSTATE(38000) "Geos operation GEOSArea failed");
4285 : }
4286 :
4287 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4288 :
4289 2 : return MAL_SUCCEED;
4290 : }
4291 :
4292 : /* returns the centroid of the geometry */
4293 : str
4294 2 : wkbCentroid(wkb **out, wkb **geom)
4295 : {
4296 2 : GEOSGeom geosGeometry;
4297 2 : GEOSGeom outGeometry;
4298 :
4299 2 : if (is_wkb_nil(*geom)) {
4300 0 : if ((*out = wkbNULLcopy()) == NULL)
4301 0 : throw(MAL, "geom.Centroid", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4302 : return MAL_SUCCEED;
4303 : }
4304 2 : geosGeometry = wkb2geos(*geom);
4305 2 : if (geosGeometry == NULL)
4306 0 : throw(MAL, "geom.Centroid", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4307 :
4308 2 : outGeometry = GEOSGetCentroid_r(geoshandle, geosGeometry);
4309 2 : GEOSSetSRID_r(geoshandle, outGeometry, GEOSGetSRID_r(geoshandle, geosGeometry)); //the centroid has the same SRID with the the input geometry
4310 2 : *out = geos2wkb(outGeometry);
4311 :
4312 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4313 2 : GEOSGeom_destroy_r(geoshandle, outGeometry);
4314 :
4315 2 : return MAL_SUCCEED;
4316 :
4317 : }
4318 :
4319 : /* Returns the 2-dimensional Cartesian minimum distance (based on spatial ref) between two geometries in projected units */
4320 : str
4321 64 : wkbDistance(dbl *out, wkb **a, wkb **b)
4322 : {
4323 64 : GEOSGeom ga, gb;
4324 64 : str err = MAL_SUCCEED;
4325 :
4326 64 : if (is_wkb_nil(*a) || is_wkb_nil(*b)) {
4327 0 : *out = dbl_nil;
4328 0 : return MAL_SUCCEED;
4329 : }
4330 :
4331 65 : ga = wkb2geos(*a);
4332 65 : gb = wkb2geos(*b);
4333 64 : if (ga == NULL || gb == NULL) {
4334 0 : if (ga)
4335 0 : GEOSGeom_destroy_r(geoshandle, ga);
4336 0 : if (gb)
4337 0 : GEOSGeom_destroy_r(geoshandle, gb);
4338 0 : *out = dbl_nil;
4339 0 : throw(MAL, "geom.Distance", SQLSTATE(38000) "Geos operation wkb2geos failed");
4340 : }
4341 :
4342 64 : if (GEOSGetSRID_r(geoshandle, ga) != GEOSGetSRID_r(geoshandle, gb)) {
4343 0 : err = createException(MAL, "geom.Distance", SQLSTATE(38000) "Geometries of different SRID");
4344 64 : } else if (!GEOSDistance_r(geoshandle, ga, gb, out)) {
4345 0 : err = createException(MAL, "geom.Distance", SQLSTATE(38000) "Geos operation GEOSDistance failed");
4346 : }
4347 :
4348 65 : GEOSGeom_destroy_r(geoshandle, ga);
4349 65 : GEOSGeom_destroy_r(geoshandle, gb);
4350 :
4351 65 : return err;
4352 : }
4353 :
4354 : /* Returns the 2d length of the geometry if it is a linestring or multilinestring */
4355 : str
4356 2 : wkbLength(dbl *out, wkb **a)
4357 : {
4358 2 : GEOSGeom geosGeometry;
4359 2 : str err = MAL_SUCCEED;
4360 :
4361 2 : if (is_wkb_nil(*a)) {
4362 0 : *out = dbl_nil;
4363 0 : return MAL_SUCCEED;
4364 : }
4365 :
4366 2 : geosGeometry = wkb2geos(*a);
4367 2 : if (geosGeometry == NULL) {
4368 0 : throw(MAL, "geom.Length", SQLSTATE(38000) "Geos operation wkb2geos failed");
4369 : }
4370 :
4371 2 : if (!GEOSLength_r(geoshandle, geosGeometry, out))
4372 0 : err = createException(MAL, "geom.Length", SQLSTATE(38000) "Geos operation GEOSLength failed");
4373 :
4374 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4375 :
4376 2 : return err;
4377 : }
4378 :
4379 : /* Returns a geometry that represents the convex hull of this geometry.
4380 : * The convex hull of a geometry represents the minimum convex geometry
4381 : * that encloses all geometries within the set. */
4382 : str
4383 1 : wkbConvexHull(wkb **out, wkb **geom)
4384 : {
4385 1 : str ret = MAL_SUCCEED;
4386 1 : GEOSGeom geosGeometry;
4387 1 : GEOSGeom convexHullGeometry = NULL;
4388 :
4389 1 : if (is_wkb_nil(*geom)) {
4390 0 : if ((*out = wkbNULLcopy()) == NULL)
4391 0 : throw(MAL, "geom.ConvexHull", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4392 : return MAL_SUCCEED;
4393 : }
4394 1 : if ((geosGeometry = wkb2geos(*geom)) == NULL)
4395 0 : throw(MAL, "geom.ConvexHull", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4396 :
4397 1 : if ((convexHullGeometry = GEOSConvexHull_r(geoshandle, geosGeometry)) == NULL) {
4398 0 : ret = createException(MAL, "geom.ConvexHull", SQLSTATE(38000) "Geos operation GEOSConvexHull failed");
4399 : } else {
4400 1 : GEOSSetSRID_r(geoshandle, convexHullGeometry, (*geom)->srid);
4401 1 : *out = geos2wkb(convexHullGeometry);
4402 1 : GEOSGeom_destroy_r(geoshandle, convexHullGeometry);
4403 1 : if (*out == NULL)
4404 0 : ret = createException(MAL, "geom.ConvexHull", SQLSTATE(38000) "Geos operation geos2wkb failed");
4405 : }
4406 1 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4407 :
4408 1 : return ret;
4409 :
4410 : }
4411 :
4412 : /* Gets two geometries and returns a new geometry */
4413 : static str
4414 5 : wkbanalysis(wkb **out, wkb **geom1WKB, wkb **geom2WKB, GEOSGeometry *(*func) (GEOSContextHandle_t handle, const GEOSGeometry *, const GEOSGeometry *), const char *name)
4415 : {
4416 5 : GEOSGeom outGeometry, geom1Geometry, geom2Geometry;
4417 5 : str err = MAL_SUCCEED;
4418 :
4419 5 : if (is_wkb_nil(*geom1WKB) || is_wkb_nil(*geom2WKB)) {
4420 0 : if ((*out = wkbNULLcopy()) == NULL)
4421 0 : throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
4422 : return MAL_SUCCEED;
4423 : }
4424 :
4425 5 : geom1Geometry = wkb2geos(*geom1WKB);
4426 5 : geom2Geometry = wkb2geos(*geom2WKB);
4427 5 : if (geom1Geometry == NULL || geom2Geometry == NULL) {
4428 0 : *out = NULL;
4429 0 : if (geom1Geometry)
4430 0 : GEOSGeom_destroy_r(geoshandle, geom1Geometry);
4431 0 : if (geom2Geometry)
4432 0 : GEOSGeom_destroy_r(geoshandle, geom2Geometry);
4433 0 : throw(MAL, name, SQLSTATE(38000) "Geos operation wkb2geos failed");
4434 : }
4435 :
4436 : //make sure the geometries are of the same srid
4437 5 : if (GEOSGetSRID_r(geoshandle, geom1Geometry) != GEOSGetSRID_r(geoshandle, geom2Geometry)) {
4438 0 : err = createException(MAL, name, SQLSTATE(38000) "Geometries of different SRID");
4439 5 : } else if ((outGeometry = (*func) (geoshandle, geom1Geometry, geom2Geometry)) == NULL) {
4440 0 : err = createException(MAL, name, SQLSTATE(38000) "Geos operation GEOS%s failed", name + 5);
4441 : } else {
4442 5 : GEOSSetSRID_r(geoshandle, outGeometry, GEOSGetSRID_r(geoshandle, geom1Geometry));
4443 5 : *out = geos2wkb(outGeometry);
4444 5 : GEOSGeom_destroy_r(geoshandle, outGeometry);
4445 : }
4446 5 : GEOSGeom_destroy_r(geoshandle, geom1Geometry);
4447 5 : GEOSGeom_destroy_r(geoshandle, geom2Geometry);
4448 :
4449 5 : return err;
4450 : }
4451 :
4452 : str
4453 1 : wkbIntersection(wkb **out, wkb **a, wkb **b)
4454 : {
4455 1 : return wkbanalysis(out, a, b, GEOSIntersection_r, "geom.Intersection");
4456 : }
4457 :
4458 : str
4459 2 : wkbUnion(wkb **out, wkb **a, wkb **b)
4460 : {
4461 2 : return wkbanalysis(out, a, b, GEOSUnion_r, "geom.Union");
4462 : }
4463 :
4464 : //Gets a BAT with geometries and returns a single LineString
4465 : str
4466 0 : wkbUnionAggr(wkb **outWKB, bat *inBAT_id)
4467 : {
4468 0 : BAT *inBAT = NULL;
4469 0 : BATiter inBAT_iter;
4470 0 : BUN i;
4471 0 : str err;
4472 0 : wkb *aWKB, *bWKB;
4473 :
4474 : //get the BATs
4475 0 : if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
4476 0 : throw(MAL, "geom.Union", SQLSTATE(38000) "Geos problem retrieving columns");
4477 : }
4478 :
4479 0 : if (BATcount(inBAT) == 0) {
4480 0 : BBPunfix(inBAT->batCacheid);
4481 0 : if ((*outWKB = wkbNULLcopy()) == NULL)
4482 0 : throw(MAL, "geom.Union", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4483 : return MAL_SUCCEED;
4484 : }
4485 :
4486 : //iterator over the BATs
4487 0 : inBAT_iter = bat_iterator(inBAT);
4488 :
4489 0 : aWKB = (wkb *) BUNtvar(inBAT_iter, 0);
4490 0 : if (BATcount(inBAT) == 1) {
4491 0 : bat_iterator_end(&inBAT_iter);
4492 0 : err = wkbFromWKB(outWKB, &aWKB);
4493 0 : BBPunfix(inBAT->batCacheid);
4494 0 : if (err) {
4495 0 : freeException(err);
4496 0 : throw(MAL, "geom.Union", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4497 : }
4498 : return MAL_SUCCEED;
4499 : }
4500 0 : bWKB = (wkb *) BUNtvar(inBAT_iter, 1);
4501 : //create the first union using the first two geometries
4502 0 : err = wkbUnion(outWKB, &aWKB, &bWKB);
4503 0 : for (i = 2; err == MAL_SUCCEED && i < BATcount(inBAT); i++) {
4504 0 : aWKB = *outWKB;
4505 0 : bWKB = (wkb *) BUNtvar(inBAT_iter, i);
4506 0 : *outWKB = NULL;
4507 :
4508 0 : err = wkbUnion(outWKB, &aWKB, &bWKB);
4509 0 : GDKfree(aWKB);
4510 : }
4511 :
4512 0 : bat_iterator_end(&inBAT_iter);
4513 0 : BBPunfix(inBAT->batCacheid);
4514 :
4515 0 : return err;
4516 :
4517 : }
4518 :
4519 : str
4520 1 : wkbDifference(wkb **out, wkb **a, wkb **b)
4521 : {
4522 1 : return wkbanalysis(out, a, b, GEOSDifference_r, "geom.Difference");
4523 : }
4524 :
4525 : str
4526 1 : wkbSymDifference(wkb **out, wkb **a, wkb **b)
4527 : {
4528 1 : return wkbanalysis(out, a, b, GEOSSymDifference_r, "geom.SymDifference");
4529 : }
4530 :
4531 : /* Returns a geometry that represents all points whose distance from this Geometry is less than or equal to distance. */
4532 : str
4533 11 : wkbBuffer(wkb **out, wkb **geom, dbl *distance)
4534 : {
4535 11 : GEOSGeom geosGeometry;
4536 11 : GEOSGeom new;
4537 :
4538 11 : if (is_wkb_nil(*geom) || is_dbl_nil(*distance)) {
4539 0 : if ((*out = wkbNULLcopy()) == NULL)
4540 0 : throw(MAL, "geom.Buffer", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4541 : return MAL_SUCCEED;
4542 : }
4543 :
4544 11 : geosGeometry = wkb2geos(*geom);
4545 11 : if (geosGeometry == NULL) {
4546 0 : throw(MAL, "geom.Buffer", SQLSTATE(38000) "Geos operation wkb2geos failed");
4547 : }
4548 :
4549 11 : if ((new = GEOSBuffer_r(geoshandle, geosGeometry, *distance, 18)) == NULL) {
4550 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4551 0 : throw(MAL, "geom.Buffer", SQLSTATE(38000) "Geos operation GEOSBuffer failed");
4552 : }
4553 11 : *out = geos2wkb(new);
4554 11 : GEOSGeom_destroy_r(geoshandle, new);
4555 11 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4556 :
4557 11 : if (*out == NULL)
4558 0 : throw(MAL, "geom.Buffer", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4559 :
4560 11 : (*out)->srid = (*geom)->srid;
4561 :
4562 11 : return MAL_SUCCEED;
4563 : }
4564 :
4565 : /* Gets two geometries and returns a Boolean by comparing them */
4566 : static str
4567 130 : wkbspatial(bit *out, wkb **geomWKB_a, wkb **geomWKB_b, char (*func) (GEOSContextHandle_t handle, const GEOSGeometry *, const GEOSGeometry *), const char *name)
4568 : {
4569 130 : int res;
4570 130 : GEOSGeom geosGeometry_a, geosGeometry_b;
4571 :
4572 130 : if (is_wkb_nil(*geomWKB_a) || is_wkb_nil(*geomWKB_b)) {
4573 0 : *out = bit_nil;
4574 0 : return MAL_SUCCEED;
4575 : }
4576 :
4577 130 : geosGeometry_a = wkb2geos(*geomWKB_a);
4578 130 : geosGeometry_b = wkb2geos(*geomWKB_b);
4579 130 : if (geosGeometry_a == NULL || geosGeometry_b == NULL) {
4580 0 : if (geosGeometry_a)
4581 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_a);
4582 0 : if (geosGeometry_b)
4583 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_b);
4584 0 : throw(MAL, name, SQLSTATE(38000) "Geos operation wkb2geos failed");
4585 : }
4586 :
4587 130 : if (GEOSGetSRID_r(geoshandle, geosGeometry_a) != GEOSGetSRID_r(geoshandle, geosGeometry_b)) {
4588 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_a);
4589 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_b);
4590 0 : throw(MAL, name, SQLSTATE(38000) "Geometries of different SRID");
4591 : }
4592 :
4593 129 : res = (*func) (geoshandle, geosGeometry_a, geosGeometry_b);
4594 :
4595 130 : GEOSGeom_destroy_r(geoshandle, geosGeometry_a);
4596 131 : GEOSGeom_destroy_r(geoshandle, geosGeometry_b);
4597 :
4598 131 : if (res == 2)
4599 0 : throw(MAL, name, SQLSTATE(38000) "Geos operation GEOS%s failed", name + 5);
4600 :
4601 131 : *out = res;
4602 :
4603 131 : return MAL_SUCCEED;
4604 : }
4605 :
4606 : str
4607 30 : wkbContains(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4608 : {
4609 30 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSContains_r, "geom.Contains");
4610 : }
4611 :
4612 : str
4613 2 : wkbCrosses(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4614 : {
4615 2 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSCrosses_r, "geom.Crosses");
4616 : }
4617 :
4618 : str
4619 2 : wkbDisjoint(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4620 : {
4621 2 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSDisjoint_r, "geom.Disjoint");
4622 : }
4623 :
4624 : str
4625 10 : wkbEquals(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4626 : {
4627 10 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSEquals_r, "geom.Equals");
4628 : }
4629 :
4630 : str
4631 58 : wkbIntersects(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4632 : {
4633 58 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSIntersects_r, "geom.Intersects");
4634 : }
4635 :
4636 : str
4637 6 : wkbOverlaps(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4638 : {
4639 6 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSOverlaps_r, "geom.Overlaps");
4640 : }
4641 :
4642 : str
4643 1 : wkbRelate(bit *out, wkb **geomWKB_a, wkb **geomWKB_b, str *pattern)
4644 : {
4645 1 : int res;
4646 1 : GEOSGeom geosGeometry_a, geosGeometry_b;
4647 :
4648 1 : if (is_wkb_nil(*geomWKB_a) || is_wkb_nil(*geomWKB_b) || strNil(*pattern)) {
4649 0 : *out = bit_nil;
4650 0 : return MAL_SUCCEED;
4651 : }
4652 :
4653 1 : geosGeometry_a = wkb2geos(*geomWKB_a);
4654 1 : geosGeometry_b = wkb2geos(*geomWKB_b);
4655 1 : if (geosGeometry_a == NULL || geosGeometry_b == NULL) {
4656 0 : if (geosGeometry_a)
4657 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_a);
4658 0 : if (geosGeometry_b)
4659 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_b);
4660 0 : throw(MAL, "geom.RelatePattern", SQLSTATE(38000) "Geos operation wkb2geos failed");
4661 : }
4662 :
4663 1 : if (GEOSGetSRID_r(geoshandle, geosGeometry_a) != GEOSGetSRID_r(geoshandle, geosGeometry_b)) {
4664 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_a);
4665 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_b);
4666 0 : throw(MAL, "geom.RelatePattern", SQLSTATE(38000) "Geometries of different SRID");
4667 : }
4668 :
4669 1 : res = GEOSRelatePattern_r(geoshandle, geosGeometry_a, geosGeometry_b, *pattern);
4670 :
4671 1 : GEOSGeom_destroy_r(geoshandle, geosGeometry_a);
4672 1 : GEOSGeom_destroy_r(geoshandle, geosGeometry_b);
4673 :
4674 1 : if (res == 2)
4675 0 : throw(MAL, "geom.RelatePattern", SQLSTATE(38000) "Geos operation GEOSRelatePattern failed");
4676 :
4677 1 : *out = res;
4678 :
4679 1 : return MAL_SUCCEED;
4680 : }
4681 :
4682 : str
4683 2 : wkbTouches(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4684 : {
4685 2 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSTouches_r, "geom.Touches");
4686 : }
4687 :
4688 : str
4689 2 : wkbWithin(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4690 : {
4691 2 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSWithin_r, "geom.Within");
4692 : }
4693 :
4694 : str
4695 9 : wkbCovers(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4696 : {
4697 9 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSCovers_r, "geom.Covers");
4698 : }
4699 :
4700 : str
4701 9 : wkbCoveredBy(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4702 : {
4703 9 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSCoveredBy_r, "geom.CoveredBy");
4704 : }
4705 :
4706 : str
4707 55 : wkbDWithin(bit *out, wkb **geomWKB_a, wkb **geomWKB_b, dbl *distance)
4708 : {
4709 55 : double distanceComputed;
4710 55 : str err;
4711 :
4712 55 : if (is_wkb_nil(*geomWKB_a) || is_wkb_nil(*geomWKB_b) || is_dbl_nil(*distance)) {
4713 0 : *out = bit_nil;
4714 0 : return MAL_SUCCEED;
4715 : }
4716 56 : if ((err = wkbDistance(&distanceComputed, geomWKB_a, geomWKB_b)) != MAL_SUCCEED) {
4717 : return err;
4718 : }
4719 :
4720 56 : *out = (distanceComputed <= *distance);
4721 :
4722 56 : return MAL_SUCCEED;
4723 : }
4724 :
4725 : str
4726 10 : wkbDWithinMbr(bit *out, wkb **a, wkb **b, mbr **mbr_a, mbr **mbr_b, dbl *distance)
4727 : {
4728 10 : double actualDistance, bboxDistance;
4729 10 : double halfd_a, halfd_b; // halfed diagonals of the a and b bounding boxes
4730 10 : double ambiguous_zone_min, ambiguous_zone_max; // see comments
4731 10 : str err;
4732 :
4733 10 : if (is_wkb_nil(*a) || is_wkb_nil(*b) || is_dbl_nil(*distance)) {
4734 0 : *out = bit_nil;
4735 0 : return MAL_SUCCEED;
4736 : }
4737 :
4738 : // if there are no mbr(s) fallback to wkbDWithin
4739 10 : if (is_mbr_nil(*mbr_a) || is_mbr_nil(*mbr_b))
4740 0 : return wkbDWithin(out, a, b, distance);
4741 :
4742 : // first calculate the distance of the bounding boxes (mbrs)
4743 10 : if ((err = mbrDistance(&bboxDistance, mbr_a, mbr_b)) != MAL_SUCCEED)
4744 : return err;
4745 :
4746 10 : if ((err = mbrDiagonal(&halfd_a, mbr_a)) != MAL_SUCCEED)
4747 : return err;
4748 10 : halfd_a *= .5;
4749 :
4750 10 : if ((err = mbrDiagonal(&halfd_b, mbr_b)) != MAL_SUCCEED)
4751 : return err;
4752 10 : halfd_b *= .5;
4753 :
4754 : // Every bounding box can be inscribed in a circle. When calculating the distance
4755 : // between two mbrs we do so by their centroids which are actually the origins of
4756 : // their circumscribed circles. Then, independently of the bounded geometry, we can
4757 : // find two rough distance limits which are giving us a zone outside of which the
4758 : // questions 'distance within' can be answered only by the bounding box geometry.
4759 : // If the 'distance within' check is done over distance value in this zone then we
4760 : // actually need to perform the underlying geometry distance calculation.
4761 10 : ambiguous_zone_max = bboxDistance;
4762 10 : ambiguous_zone_min = bboxDistance - halfd_a - halfd_b;
4763 :
4764 10 : if (*distance < ambiguous_zone_min) {
4765 3 : *out = false;
4766 7 : } else if (*distance > ambiguous_zone_max) {
4767 3 : *out = true;
4768 : } else {
4769 : // if we are not sure still calculate the actual distance of the geometries
4770 4 : if ((err = wkbDistance(&actualDistance, a, b)) != MAL_SUCCEED)
4771 : return err;
4772 4 : *out = (actualDistance <= *distance);
4773 : }
4774 :
4775 : return MAL_SUCCEED;
4776 : }
4777 :
4778 : /*returns the n-th geometry in a multi-geometry */
4779 : str
4780 13 : wkbGeometryN(wkb **out, wkb **geom, const int *geometryNum)
4781 : {
4782 13 : int geometriesNum = -1;
4783 13 : GEOSGeom geosGeometry = NULL;
4784 :
4785 : //no geometry at this position
4786 13 : if (is_wkb_nil(*geom) || is_int_nil(*geometryNum) || *geometryNum <= 0) {
4787 1 : if ((*out = wkbNULLcopy()) == NULL)
4788 0 : throw(MAL, "geom.GeometryN", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4789 : return MAL_SUCCEED;
4790 : }
4791 :
4792 12 : geosGeometry = wkb2geos(*geom);
4793 :
4794 12 : if (geosGeometry == NULL) {
4795 0 : *out = NULL;
4796 0 : throw(MAL, "geom.GeometryN", SQLSTATE(38000) "Geos operation wkb2geos failed");
4797 : }
4798 :
4799 12 : geometriesNum = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
4800 12 : if (geometriesNum < 0) {
4801 0 : *out = NULL;
4802 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4803 0 : throw(MAL, "geom.GeometryN", SQLSTATE(38000) "Geos operation GEOSGetNumGeometries failed");
4804 : }
4805 12 : if (geometriesNum == 1 || //geometry is not a multi geometry
4806 11 : geometriesNum < *geometryNum) { //no geometry at this position
4807 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4808 2 : if ((*out = wkbNULLcopy()) == NULL)
4809 0 : throw(MAL, "geom.GeometryN", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4810 : return MAL_SUCCEED;
4811 : }
4812 :
4813 10 : *out = geos2wkb(GEOSGetGeometryN_r(geoshandle, geosGeometry, *geometryNum - 1));
4814 10 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4815 10 : if (*out == NULL)
4816 0 : throw(MAL, "geom.GeometryN", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4817 :
4818 : return MAL_SUCCEED;
4819 : }
4820 :
4821 : /* returns the number of geometries */
4822 : str
4823 10 : wkbNumGeometries(int *out, wkb **geom)
4824 : {
4825 10 : GEOSGeom geosGeometry;
4826 :
4827 10 : if (is_wkb_nil(*geom)) {
4828 0 : *out = int_nil;
4829 0 : return MAL_SUCCEED;
4830 : }
4831 :
4832 10 : geosGeometry = wkb2geos(*geom);
4833 10 : if (geosGeometry == NULL) {
4834 0 : *out = int_nil;
4835 0 : throw(MAL, "geom.NumGeometries", SQLSTATE(38000) "Geos operation wkb2geos failed");
4836 : }
4837 :
4838 10 : *out = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
4839 10 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4840 10 : if (*out < 0) {
4841 0 : *out = int_nil;
4842 0 : throw(MAL, "geom.GeometryN", SQLSTATE(38000) "Geos operation GEOSGetNumGeometries failed");
4843 : }
4844 :
4845 : return MAL_SUCCEED;
4846 : }
4847 :
4848 :
4849 : /* TODO: Analyze these functions below (what's the dif from normal contain, is it unfinished?) */
4850 :
4851 : geom_export str wkbContains_point_bat(bat *out, wkb **a, bat *point_x, bat *point_y);
4852 : geom_export str wkbContains_point(bit *out, wkb **a, dbl *point_x, dbl *point_y);
4853 :
4854 : static inline double
4855 0 : isLeft(double P0x, double P0y, double P1x, double P1y, double P2x, double P2y)
4856 : {
4857 0 : return ((P1x - P0x) * (P2y - P0y)
4858 0 : - (P2x - P0x) * (P1y - P0y));
4859 : }
4860 :
4861 : static str
4862 0 : pnpoly(int *out, int nvert, dbl *vx, dbl *vy, bat *point_x, bat *point_y)
4863 : {
4864 0 : BAT *bo = NULL, *bpx = NULL, *bpy;
4865 0 : dbl *px = NULL, *py = NULL;
4866 0 : BUN i = 0, cnt;
4867 0 : int j = 0, nv;
4868 0 : bit *cs = NULL;
4869 :
4870 : /*Get the BATs */
4871 0 : if ((bpx = BATdescriptor(*point_x)) == NULL) {
4872 0 : throw(MAL, "geom.point", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
4873 : }
4874 :
4875 0 : if ((bpy = BATdescriptor(*point_y)) == NULL) {
4876 0 : BBPunfix(bpx->batCacheid);
4877 0 : throw(MAL, "geom.point", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
4878 : }
4879 :
4880 : /*Check BATs alignment */
4881 0 : if (bpx->hseqbase != bpy->hseqbase || BATcount(bpx) != BATcount(bpy)) {
4882 0 : BBPunfix(bpx->batCacheid);
4883 0 : BBPunfix(bpy->batCacheid);
4884 0 : throw(MAL, "geom.point", SQLSTATE(38000) "both point bats must have dense and aligned heads");
4885 : }
4886 :
4887 : /*Create output BAT */
4888 0 : if ((bo = COLnew(bpx->hseqbase, TYPE_bit, BATcount(bpx), TRANSIENT)) == NULL) {
4889 0 : BBPunfix(bpx->batCacheid);
4890 0 : BBPunfix(bpy->batCacheid);
4891 0 : throw(MAL, "geom.point", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4892 : }
4893 :
4894 : /*Iterate over the Point BATs and determine if they are in Polygon represented by vertex BATs */
4895 0 : BATiter bpxi = bat_iterator(bpx);
4896 0 : BATiter bpyi = bat_iterator(bpy);
4897 0 : px = (dbl *) bpxi.base;
4898 0 : py = (dbl *) bpyi.base;
4899 :
4900 0 : nv = nvert - 1;
4901 0 : cnt = BATcount(bpx);
4902 0 : cs = (bit *) Tloc(bo, 0);
4903 0 : for (i = 0; i < cnt; i++) {
4904 : int wn = 0;
4905 0 : for (j = 0; j < nv; j++) {
4906 0 : if (vy[j] <= py[i]) {
4907 0 : if (vy[j + 1] > py[i])
4908 0 : if (isLeft(vx[j], vy[j], vx[j + 1], vy[j + 1], px[i], py[i]) > 0)
4909 0 : ++wn;
4910 : } else {
4911 0 : if (vy[j + 1] <= py[i])
4912 0 : if (isLeft(vx[j], vy[j], vx[j + 1], vy[j + 1], px[i], py[i]) < 0)
4913 0 : --wn;
4914 : }
4915 : }
4916 0 : *cs++ = wn & 1;
4917 : }
4918 0 : bat_iterator_end(&bpxi);
4919 0 : bat_iterator_end(&bpyi);
4920 0 : BATsetcount(bo, cnt);
4921 0 : bo->tsorted = bo->trevsorted = false;
4922 0 : bo->tkey = false;
4923 0 : BBPunfix(bpx->batCacheid);
4924 0 : BBPunfix(bpy->batCacheid);
4925 0 : *out = bo->batCacheid;
4926 0 : BBPkeepref(bo);
4927 0 : return MAL_SUCCEED;
4928 : }
4929 :
4930 : static str
4931 0 : pnpolyWithHoles(bat *out, int nvert, dbl *vx, dbl *vy, int nholes, dbl **hx, dbl **hy, int *hn, bat *point_x, bat *point_y)
4932 : {
4933 0 : BAT *bo = NULL, *bpx = NULL, *bpy;
4934 0 : dbl *px = NULL, *py = NULL;
4935 0 : BUN i = 0, cnt = 0;
4936 0 : int j = 0, h = 0;
4937 0 : bit *cs = NULL;
4938 :
4939 : /*Get the BATs */
4940 0 : if ((bpx = BATdescriptor(*point_x)) == NULL) {
4941 0 : throw(MAL, "geom.point", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
4942 : }
4943 0 : if ((bpy = BATdescriptor(*point_y)) == NULL) {
4944 0 : BBPunfix(bpx->batCacheid);
4945 0 : throw(MAL, "geom.point", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
4946 : }
4947 :
4948 : /*Check BATs alignment */
4949 0 : if (bpx->hseqbase != bpy->hseqbase || BATcount(bpx) != BATcount(bpy)) {
4950 0 : BBPunfix(bpx->batCacheid);
4951 0 : BBPunfix(bpy->batCacheid);
4952 0 : throw(MAL, "geom.point", SQLSTATE(38000) "Geos both point bats must have dense and aligned heads");
4953 : }
4954 :
4955 : /*Create output BAT */
4956 0 : if ((bo = COLnew(bpx->hseqbase, TYPE_bit, BATcount(bpx), TRANSIENT)) == NULL) {
4957 0 : BBPunfix(bpx->batCacheid);
4958 0 : BBPunfix(bpy->batCacheid);
4959 0 : throw(MAL, "geom.point", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4960 : }
4961 :
4962 : /*Iterate over the Point BATs and determine if they are in Polygon represented by vertex BATs */
4963 0 : BATiter bpxi = bat_iterator(bpx);
4964 0 : BATiter bpyi = bat_iterator(bpy);
4965 0 : px = (dbl *) bpxi.base;
4966 0 : py = (dbl *) bpyi.base;
4967 0 : cnt = BATcount(bpx);
4968 0 : cs = (bit *) Tloc(bo, 0);
4969 0 : for (i = 0; i < cnt; i++) {
4970 : int wn = 0;
4971 :
4972 : /*First check the holes */
4973 0 : for (h = 0; h < nholes; h++) {
4974 0 : int nv = hn[h] - 1;
4975 0 : wn = 0;
4976 0 : for (j = 0; j < nv; j++) {
4977 0 : if (hy[h][j] <= py[i]) {
4978 0 : if (hy[h][j + 1] > py[i])
4979 0 : if (isLeft(hx[h][j], hy[h][j], hx[h][j + 1], hy[h][j + 1], px[i], py[i]) > 0)
4980 0 : ++wn;
4981 : } else {
4982 0 : if (hy[h][j + 1] <= py[i])
4983 0 : if (isLeft(hx[h][j], hy[h][j], hx[h][j + 1], hy[h][j + 1], px[i], py[i]) < 0)
4984 0 : --wn;
4985 : }
4986 : }
4987 :
4988 : /*It is in one of the holes */
4989 0 : if (wn) {
4990 : break;
4991 : }
4992 : }
4993 :
4994 0 : if (wn)
4995 0 : continue;
4996 :
4997 : /*If not in any of the holes, check inside the Polygon */
4998 0 : for (j = 0; j < nvert - 1; j++) {
4999 0 : if (vy[j] <= py[i]) {
5000 0 : if (vy[j + 1] > py[i])
5001 0 : if (isLeft(vx[j], vy[j], vx[j + 1], vy[j + 1], px[i], py[i]) > 0)
5002 0 : ++wn;
5003 : } else {
5004 0 : if (vy[j + 1] <= py[i])
5005 0 : if (isLeft(vx[j], vy[j], vx[j + 1], vy[j + 1], px[i], py[i]) < 0)
5006 0 : --wn;
5007 : }
5008 : }
5009 0 : *cs++ = wn & 1;
5010 : }
5011 0 : bat_iterator_end(&bpxi);
5012 0 : bat_iterator_end(&bpyi);
5013 0 : BATsetcount(bo, cnt);
5014 0 : bo->tsorted = bo->trevsorted = false;
5015 0 : bo->tkey = false;
5016 0 : BBPunfix(bpx->batCacheid);
5017 0 : BBPunfix(bpy->batCacheid);
5018 0 : *out = bo->batCacheid;
5019 0 : BBPkeepref(bo);
5020 0 : return MAL_SUCCEED;
5021 : }
5022 :
5023 : #define POLY_NUM_VERT 120
5024 : #define POLY_NUM_HOLE 10
5025 :
5026 : str
5027 0 : wkbContains_point_bat(bat *out, wkb **a, bat *point_x, bat *point_y)
5028 : {
5029 0 : double *vert_x, *vert_y, **holes_x = NULL, **holes_y = NULL;
5030 0 : int *holes_n = NULL, j;
5031 0 : wkb *geom = NULL;
5032 0 : str err = MAL_SUCCEED;
5033 0 : str geom_str = NULL;
5034 0 : char *str2, *token, *subtoken;
5035 0 : char *saveptr1 = NULL, *saveptr2 = NULL;
5036 0 : int nvert = 0, nholes = 0;
5037 :
5038 0 : geom = (wkb *) *a;
5039 :
5040 0 : if ((err = wkbAsText(&geom_str, &geom, NULL)) != MAL_SUCCEED) {
5041 : return err;
5042 : }
5043 0 : token = strchr(geom_str, '(');
5044 0 : token += 2;
5045 :
5046 : /*Lets get the polygon */
5047 0 : token = strtok_r(token, ")", &saveptr1);
5048 0 : vert_x = GDKmalloc(POLY_NUM_VERT * sizeof(double));
5049 0 : vert_y = GDKmalloc(POLY_NUM_VERT * sizeof(double));
5050 0 : if (vert_x == NULL || vert_y == NULL) {
5051 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5052 0 : goto bailout;
5053 : }
5054 :
5055 : for (str2 = token;; str2 = NULL) {
5056 0 : subtoken = strtok_r(str2, ",", &saveptr2);
5057 0 : if (subtoken == NULL)
5058 : break;
5059 0 : sscanf(subtoken, "%lf %lf", &vert_x[nvert], &vert_y[nvert]);
5060 0 : nvert++;
5061 0 : if ((nvert % POLY_NUM_VERT) == 0) {
5062 0 : double *tmp;
5063 0 : tmp = GDKrealloc(vert_x, nvert * 2 * sizeof(double));
5064 0 : if (tmp == NULL) {
5065 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5066 0 : goto bailout;
5067 : }
5068 0 : vert_x = tmp;
5069 0 : tmp = GDKrealloc(vert_y, nvert * 2 * sizeof(double));
5070 0 : if (tmp == NULL) {
5071 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5072 0 : goto bailout;
5073 : }
5074 : vert_y = tmp;
5075 : }
5076 : }
5077 :
5078 0 : token = strtok_r(NULL, ")", &saveptr1);
5079 0 : if (token) {
5080 0 : holes_x = GDKzalloc(POLY_NUM_HOLE * sizeof(double *));
5081 0 : holes_y = GDKzalloc(POLY_NUM_HOLE * sizeof(double *));
5082 0 : holes_n = GDKzalloc(POLY_NUM_HOLE * sizeof(int));
5083 0 : if (holes_x == NULL || holes_y == NULL || holes_n == NULL) {
5084 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5085 0 : goto bailout;
5086 : }
5087 : }
5088 : /*Lets get all the holes */
5089 0 : while (token) {
5090 0 : int nhole = 0;
5091 0 : token = strchr(token, '(');
5092 0 : if (!token)
5093 : break;
5094 0 : token++;
5095 :
5096 0 : if (holes_x[nholes] == NULL &&
5097 0 : (holes_x[nholes] = GDKzalloc(POLY_NUM_VERT * sizeof(double))) == NULL) {
5098 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5099 0 : goto bailout;
5100 : }
5101 0 : if (holes_y[nholes] == NULL &&
5102 0 : (holes_y[nholes] = GDKzalloc(POLY_NUM_VERT * sizeof(double))) == NULL) {
5103 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5104 0 : goto bailout;
5105 : }
5106 :
5107 : for (str2 = token;; str2 = NULL) {
5108 0 : subtoken = strtok_r(str2, ",", &saveptr2);
5109 0 : if (subtoken == NULL)
5110 : break;
5111 0 : sscanf(subtoken, "%lf %lf", &holes_x[nholes][nhole], &holes_y[nholes][nhole]);
5112 0 : nhole++;
5113 0 : if ((nhole % POLY_NUM_VERT) == 0) {
5114 0 : double *tmp;
5115 0 : tmp = GDKrealloc(holes_x[nholes], nhole * 2 * sizeof(double));
5116 0 : if (tmp == NULL) {
5117 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5118 0 : goto bailout;
5119 : }
5120 0 : holes_x[nholes] = tmp;
5121 0 : tmp = GDKrealloc(holes_y[nholes], nhole * 2 * sizeof(double));
5122 0 : if (tmp == NULL) {
5123 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5124 0 : goto bailout;
5125 : }
5126 0 : holes_y[nholes] = tmp;
5127 : }
5128 : }
5129 :
5130 0 : holes_n[nholes] = nhole;
5131 0 : nholes++;
5132 0 : if ((nholes % POLY_NUM_HOLE) == 0) {
5133 0 : double **tmp;
5134 0 : int *itmp;
5135 0 : tmp = GDKrealloc(holes_x, nholes * 2 * sizeof(double *));
5136 0 : if (tmp == NULL) {
5137 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5138 0 : goto bailout;
5139 : }
5140 0 : holes_x = tmp;
5141 0 : tmp = GDKrealloc(holes_y, nholes * 2 * sizeof(double *));
5142 0 : if (tmp == NULL) {
5143 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5144 0 : goto bailout;
5145 : }
5146 0 : holes_y = tmp;
5147 0 : itmp = GDKrealloc(holes_n, nholes * 2 * sizeof(int));
5148 0 : if (itmp == NULL) {
5149 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5150 0 : goto bailout;
5151 : }
5152 : holes_n = itmp;
5153 : }
5154 0 : token = strtok_r(NULL, ")", &saveptr1);
5155 : }
5156 :
5157 0 : if (nholes)
5158 0 : err = pnpolyWithHoles(out, nvert, vert_x, vert_y, nholes, holes_x, holes_y, holes_n, point_x, point_y);
5159 : else {
5160 0 : err = pnpoly(out, nvert, vert_x, vert_y, point_x, point_y);
5161 : }
5162 :
5163 0 : bailout:
5164 0 : GDKfree(geom_str);
5165 0 : GDKfree(vert_x);
5166 0 : GDKfree(vert_y);
5167 0 : if (holes_x && holes_y && holes_n) {
5168 0 : for (j = 0; j < nholes; j++) {
5169 0 : GDKfree(holes_x[j]);
5170 0 : GDKfree(holes_y[j]);
5171 : }
5172 : }
5173 0 : GDKfree(holes_x);
5174 0 : GDKfree(holes_y);
5175 0 : GDKfree(holes_n);
5176 :
5177 0 : return err;
5178 : }
5179 :
5180 : str
5181 0 : wkbContains_point(bit *out, wkb **a, dbl *point_x, dbl *point_y)
5182 : {
5183 0 : (void) a;
5184 0 : (void) point_x;
5185 0 : (void) point_y;
5186 0 : *out = TRUE;
5187 0 : return MAL_SUCCEED;
5188 : }
5189 :
5190 : static str
5191 37 : geom_AsText_wkb(char **ret, wkb **w)
5192 : {
5193 37 : return wkbAsText(ret, w, &(int){0});
5194 : }
5195 : static str
5196 29 : geom_AsEWKT_wkb(char **ret, wkb **w)
5197 : {
5198 29 : return wkbAsText(ret, w, &(int){1});
5199 : }
5200 : static str
5201 71 : geom_GeomFromText_str_int(wkb **ret, char **wkt, int *srid)
5202 : {
5203 71 : return wkbFromText(ret, wkt, srid, &(int){0});
5204 : }
5205 : static str
5206 13 : geom_PointFromText_str_int(wkb **ret, char **wkt, int *srid)
5207 : {
5208 13 : return wkbFromText(ret, wkt, srid, &(int){1});
5209 : }
5210 : static str
5211 31 : geom_LineFromText_str_int(wkb **ret, char **wkt, int *srid)
5212 : {
5213 31 : return wkbFromText(ret, wkt, srid, &(int){2});
5214 : }
5215 : static str
5216 18 : geom_PolygonFromText_str_int(wkb **ret, char **wkt, int *srid)
5217 : {
5218 18 : return wkbFromText(ret, wkt, srid, &(int){4});
5219 : }
5220 : static str
5221 16 : geom_MPointFromText_str_int(wkb **ret, char **wkt, int *srid)
5222 : {
5223 16 : return wkbFromText(ret, wkt, srid, &(int){5});
5224 : }
5225 : static str
5226 15 : geom_MLineFromText_str_int(wkb **ret, char **wkt, int *srid)
5227 : {
5228 15 : return wkbFromText(ret, wkt, srid, &(int){6});
5229 : }
5230 : static str
5231 12 : geom_MPolyFromText_str_int(wkb **ret, char **wkt, int *srid)
5232 : {
5233 12 : return wkbFromText(ret, wkt, srid, &(int){7});
5234 : }
5235 : static str
5236 0 : geom_GeomCollFromText_str_int(wkb **ret, char **wkt, int *srid)
5237 : {
5238 0 : return wkbFromText(ret, wkt, srid, &(int){8});
5239 : }
5240 : static str
5241 228 : geom_GeomFromText_str(wkb **ret, char **wkt)
5242 : {
5243 228 : return wkbFromText(ret, wkt, &(int){0}, &(int){0});
5244 : }
5245 : static str
5246 18 : geom_PointFromText_str(wkb **ret, char **wkt)
5247 : {
5248 18 : return wkbFromText(ret, wkt, &(int){0}, &(int){1});
5249 : }
5250 : static str
5251 29 : geom_LineFromText_str(wkb **ret, char **wkt)
5252 : {
5253 29 : return wkbFromText(ret, wkt, &(int){0}, &(int){2});
5254 : }
5255 : static str
5256 16 : geom_PolygonFromText_str(wkb **ret, char **wkt)
5257 : {
5258 16 : return wkbFromText(ret, wkt, &(int){0}, &(int){4});
5259 : }
5260 : static str
5261 12 : geom_MPointFromText_str(wkb **ret, char **wkt)
5262 : {
5263 12 : return wkbFromText(ret, wkt, &(int){0}, &(int){5});
5264 : }
5265 : static str
5266 9 : geom_MLineFromText_str(wkb **ret, char **wkt)
5267 : {
5268 9 : return wkbFromText(ret, wkt, &(int){0}, &(int){6});
5269 : }
5270 : static str
5271 10 : geom_MPolyFromText_str(wkb **ret, char **wkt)
5272 : {
5273 10 : return wkbFromText(ret, wkt, &(int){0}, &(int){7});
5274 : }
5275 : static str
5276 3 : geom_GeomCollFromText_str(wkb **ret, char **wkt)
5277 : {
5278 3 : return wkbFromText(ret, wkt, &(int){0}, &(int){8});
5279 : }
5280 : static str
5281 3 : geom_NumInteriorRings_wkb(int *ret, wkb **w)
5282 : {
5283 3 : return wkbNumRings(ret, w, &(int){0});
5284 : }
5285 : static str
5286 3 : geom_NRings_wkb(int *ret, wkb **w)
5287 : {
5288 3 : return wkbNumRings(ret, w, &(int){1});
5289 : }
5290 : static str
5291 0 : geom_BdPolyFromText_str_int(wkb **ret, char **wkt, int *srid)
5292 : {
5293 0 : return wkbMLineStringToPolygon(ret, wkt, srid, &(int){0});
5294 : }
5295 : static str
5296 0 : geom_BdMPolyFromText_str_int(wkb **ret, char **wkt, int *srid)
5297 : {
5298 0 : return wkbMLineStringToPolygon(ret, wkt, srid, &(int){1});
5299 : }
5300 : static str
5301 49 : geom_MakePoint_dbl_dbl(wkb **ret, dbl *x, dbl *y)
5302 : {
5303 49 : return wkbMakePoint(ret, x, y, &(dbl){0}, &(dbl){0}, &(int){0});
5304 : }
5305 : static str
5306 6 : geom_MakePoint_dbl_dbl_dbl(wkb **ret, dbl *x, dbl *y, dbl *z)
5307 : {
5308 6 : return wkbMakePoint(ret, x, y, z, &(dbl){0}, &(int){10});
5309 : }
5310 : static str
5311 0 : geom_MakePointM_dbl_dbl_dbl(wkb **ret, dbl *x, dbl *y, dbl *m)
5312 : {
5313 0 : return wkbMakePoint(ret, x, y, &(dbl){0}, m, &(int){1});
5314 : }
5315 : static str
5316 0 : geom_MakePoint_dbl_dbl_dbl_dbl(wkb **ret, dbl *x, dbl *y, dbl *z, dbl *m)
5317 : {
5318 0 : return wkbMakePoint(ret, x, y, z, m, &(int){11});
5319 : }
5320 : static str
5321 13 : geom_GeometryType1_wkb(char **ret, wkb **w)
5322 : {
5323 13 : return wkbGeometryType(ret, w, &(int){0});
5324 : }
5325 : static str
5326 13 : geom_GeometryType2_wkb(char **ret, wkb **w)
5327 : {
5328 13 : return wkbGeometryType(ret, w, &(int){1});
5329 : }
5330 : static str
5331 0 : geom_X_wkb(dbl *ret, wkb **w)
5332 : {
5333 0 : return wkbGetCoordinate(ret, w, &(int){0});
5334 : }
5335 : static str
5336 0 : geom_Y_wkb(dbl *ret, wkb **w)
5337 : {
5338 0 : return wkbGetCoordinate(ret, w, &(int){1});
5339 : }
5340 : static str
5341 0 : geom_Z_wkb(dbl *ret, wkb **w)
5342 : {
5343 0 : return wkbGetCoordinate(ret, w, &(int){2});
5344 : }
5345 : static str
5346 0 : geom_Force2D_wkb(wkb **ret, wkb **g)
5347 : {
5348 0 : return wkbForceDim(ret, g, &(int){2});
5349 : }
5350 : static str
5351 0 : geom_Force3D_wkb(wkb **ret, wkb **g)
5352 : {
5353 0 : return wkbForceDim(ret, g, &(int){3});
5354 : }
5355 : static str
5356 0 : geom_Translate_wkb_dbl_dbl(wkb **ret, wkb **g, dbl *dx, dbl *dy)
5357 : {
5358 0 : return wkbTranslate(ret, g, dx, dy, &(dbl){0});
5359 : }
5360 : static str
5361 0 : geom_Translate_wkb_dbl_dbl_dbl(wkb **ret, wkb **g, dbl *dx, dbl *dy, dbl *dz)
5362 : {
5363 0 : return wkbTranslate(ret, g, dx, dy, dz);
5364 : }
5365 : static str
5366 3 : geom_NumPoints_wkb(int *ret, wkb **w)
5367 : {
5368 3 : return wkbNumPoints(ret, w, &(int){1});
5369 : }
5370 : static str
5371 3 : geom_NPoints_wkb(int *ret, wkb **w)
5372 : {
5373 3 : return wkbNumPoints(ret, w, &(int){0});
5374 : }
5375 : static str
5376 0 : geom_MakeEnvelope_dbl_dbl_dbl_dbl_int(wkb **ret, dbl *xmin, dbl *ymin, dbl *xmax, dbl *ymax, int *srid)
5377 : {
5378 0 : return wkbEnvelopeFromCoordinates(ret, xmin, ymin, xmax, ymax, srid);
5379 : }
5380 : static str
5381 0 : geom_MakeEnvelope_dbl_dbl_dbl_dbl(wkb **ret, dbl *xmin, dbl *ymin, dbl *xmax, dbl *ymax)
5382 : {
5383 0 : return wkbEnvelopeFromCoordinates(ret, xmin, ymin, xmax, ymax, &(int){0});
5384 : }
5385 : static str
5386 0 : geom_MakePolygon_wkb(wkb **ret, wkb **external)
5387 : {
5388 0 : return wkbMakePolygon(ret, external, &(bat){bat_nil}, &(int){0});
5389 : }
5390 : static str
5391 0 : geom_MakePolygon_wkb_int(wkb **ret, wkb **external, int *srid)
5392 : {
5393 0 : return wkbMakePolygon(ret, external, &(bat){bat_nil}, srid);
5394 : }
5395 : static str
5396 0 : geom_XMinFromWKB_wkb(dbl *ret, wkb **g)
5397 : {
5398 0 : return wkbCoordinateFromWKB(ret, g, &(int){1});
5399 : }
5400 : static str
5401 0 : geom_YMinFromWKB_wkb(dbl *ret, wkb **g)
5402 : {
5403 0 : return wkbCoordinateFromWKB(ret, g, &(int){2});
5404 : }
5405 : static str
5406 0 : geom_XMaxFromWKB_wkb(dbl *ret, wkb **g)
5407 : {
5408 0 : return wkbCoordinateFromWKB(ret, g, &(int){3});
5409 : }
5410 : static str
5411 0 : geom_YMaxFromWKB_wkb(dbl *ret, wkb **g)
5412 : {
5413 0 : return wkbCoordinateFromWKB(ret, g, &(int){4});
5414 : }
5415 : static str
5416 0 : geom_XMinFromMBR_mbr(dbl *ret, mbr **b)
5417 : {
5418 0 : return wkbCoordinateFromMBR(ret, b, &(int){1});
5419 : }
5420 : static str
5421 0 : geom_YMinFromMBR_mbr(dbl *ret, mbr **b)
5422 : {
5423 0 : return wkbCoordinateFromMBR(ret, b, &(int){2});
5424 : }
5425 : static str
5426 0 : geom_XMaxFromMBR_mbr(dbl *ret, mbr **b)
5427 : {
5428 0 : return wkbCoordinateFromMBR(ret, b, &(int){3});
5429 : }
5430 : static str
5431 0 : geom_YMaxFromMBR_mbr(dbl *ret, mbr **b)
5432 : {
5433 0 : return wkbCoordinateFromMBR(ret, b, &(int){4});
5434 : }
5435 : static str
5436 454 : calc_wkb_str_int_int(wkb **ret, str *wkt, int *srid, int *type)
5437 : {
5438 454 : (void) srid;
5439 454 : (void) type;
5440 454 : return wkbFromText(ret, wkt, &(int){0}, &(int){0});
5441 : }
5442 :
5443 : static str
5444 0 : batgeom_GeomFromText_str_int(bat *ret, bat *wkt, int *srid)
5445 : {
5446 0 : return wkbFromText_bat(ret, wkt, srid, &(int){0});
5447 : }
5448 : static str
5449 0 : batgeom_PointFromText_str_int(bat *ret, bat *wkt, int *srid)
5450 : {
5451 0 : return wkbFromText_bat(ret, wkt, srid, &(int){1});
5452 : }
5453 : static str
5454 0 : batgeom_LineFromText_str_int(bat *ret, bat *wkt, int *srid)
5455 : {
5456 0 : return wkbFromText_bat(ret, wkt, srid, &(int){2});
5457 : }
5458 : static str
5459 0 : batgeom_PolygonFromText_str_int(bat *ret, bat *wkt, int *srid)
5460 : {
5461 0 : return wkbFromText_bat(ret, wkt, srid, &(int){4});
5462 : }
5463 : static str
5464 0 : batgeom_MPointFromText_str_int(bat *ret, bat *wkt, int *srid)
5465 : {
5466 0 : return wkbFromText_bat(ret, wkt, srid, &(int){5});
5467 : }
5468 : static str
5469 0 : batgeom_MLineFromText_str_int(bat *ret, bat *wkt, int *srid)
5470 : {
5471 0 : return wkbFromText_bat(ret, wkt, srid, &(int){6});
5472 : }
5473 : static str
5474 0 : batgeom_MPolyFromText_str_int(bat *ret, bat *wkt, int *srid)
5475 : {
5476 0 : return wkbFromText_bat(ret, wkt, srid, &(int){7});
5477 : }
5478 : static str
5479 0 : batgeom_GeomCollFromText_str_int(bat *ret, bat *wkt, int *srid)
5480 : {
5481 0 : return wkbFromText_bat(ret, wkt, srid, &(int){8});
5482 : }
5483 : static str
5484 1 : batgeom_GeomFromText_str(bat *ret, bat *wkt)
5485 : {
5486 1 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){0});
5487 : }
5488 : static str
5489 8 : batgeom_PointFromText_str(bat *ret, bat *wkt)
5490 : {
5491 8 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){1});
5492 : }
5493 : static str
5494 8 : batgeom_LineFromText_str(bat *ret, bat *wkt)
5495 : {
5496 8 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){2});
5497 : }
5498 : static str
5499 8 : batgeom_PolygonFromText_str(bat *ret, bat *wkt)
5500 : {
5501 8 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){4});
5502 : }
5503 : static str
5504 8 : batgeom_MPointFromText_str(bat *ret, bat *wkt)
5505 : {
5506 8 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){5});
5507 : }
5508 : static str
5509 8 : batgeom_MLineFromText_str(bat *ret, bat *wkt)
5510 : {
5511 8 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){6});
5512 : }
5513 : static str
5514 8 : batgeom_MPolyFromText_str(bat *ret, bat *wkt)
5515 : {
5516 8 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){7});
5517 : }
5518 : static str
5519 0 : batgeom_GeomCollFromText_str(bat *ret, bat *wkt)
5520 : {
5521 0 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){8});
5522 : }
5523 : static str
5524 26 : batgeom_AsText_wkb(bat *ret, bat *w)
5525 : {
5526 26 : return wkbAsText_bat(ret, w, &(int){0});
5527 : }
5528 : static str
5529 6 : batgeom_AsEWKT_wkb(bat *ret, bat *w)
5530 : {
5531 6 : return wkbAsText_bat(ret, w, &(int){1});
5532 : }
5533 : static str
5534 9 : batgeom_GeometryType1_wkb(bat *ret, bat *w)
5535 : {
5536 9 : return wkbGeometryType_bat(ret, w, &(int){0});
5537 : }
5538 : static str
5539 15 : batgeom_GeometryType2_wkb(bat *ret, bat *w)
5540 : {
5541 15 : return wkbGeometryType_bat(ret, w, &(int){1});
5542 : }
5543 : static str
5544 3 : batgeom_MakePoint_dbl_dbl(bat *ret, bat *x, bat *y)
5545 : {
5546 3 : return wkbMakePoint_bat(ret, x, y, &(bat){bat_nil}, &(bat){bat_nil}, &(int){0});
5547 : }
5548 : static str
5549 1 : batgeom_MakePoint_dbl_dbl_dbl(bat *ret, bat *x, bat *y, bat *z)
5550 : {
5551 1 : return wkbMakePoint_bat(ret, x, y, z, &(bat){bat_nil}, &(int){10});
5552 : }
5553 : static str
5554 1 : batgeom_MakePointM_dbl_dbl_dbl(bat *ret, bat *x, bat *y, bat *m)
5555 : {
5556 1 : return wkbMakePoint_bat(ret, x, y, &(bat){bat_nil}, m, &(int){1});
5557 : }
5558 : static str
5559 1 : batgeom_MakePoint_dbl_dbl_dbl_dbl(bat *ret, bat *x, bat *y, bat *z, bat *m)
5560 : {
5561 1 : return wkbMakePoint_bat(ret, x, y, z, m, &(int){11});
5562 : }
5563 : static str
5564 9 : batgeom_NumPoints_wkb(bat *ret, bat *w)
5565 : {
5566 9 : return wkbNumPoints_bat(ret, w, &(int){1});
5567 : }
5568 : static str
5569 8 : batgeom_NPoints_wkb(bat *ret, bat *w)
5570 : {
5571 8 : return wkbNumPoints_bat(ret, w, &(int){0});
5572 : }
5573 : static str
5574 5 : batgeom_X_wkb(bat *ret, bat *w)
5575 : {
5576 5 : return wkbGetCoordinate_bat(ret, w, &(int){0});
5577 : }
5578 : static str
5579 4 : batgeom_Y_wkb(bat *ret, bat *w)
5580 : {
5581 4 : return wkbGetCoordinate_bat(ret, w, &(int){1});
5582 : }
5583 : static str
5584 3 : batgeom_Z_wkb(bat *ret, bat *w)
5585 : {
5586 3 : return wkbGetCoordinate_bat(ret, w, &(int){2});
5587 : }
5588 : static str
5589 9 : batgeom_NumInteriorRings_wkb(bat *ret, bat *w)
5590 : {
5591 9 : return wkbNumRings_bat(ret, w, &(int){0});
5592 : }
5593 : static str
5594 8 : batgeom_NRings_wkb(bat *ret, bat *w)
5595 : {
5596 8 : return wkbNumRings_bat(ret, w, &(int){1});
5597 : }
5598 : static str
5599 1 : batgeom_XMinFromWKB_wkb(bat *ret, bat *g)
5600 : {
5601 1 : return wkbCoordinateFromWKB_bat(ret, g, &(int){1});
5602 : }
5603 : static str
5604 1 : batgeom_YMinFromWKB_wkb(bat *ret, bat *g)
5605 : {
5606 1 : return wkbCoordinateFromWKB_bat(ret, g, &(int){2});
5607 : }
5608 : static str
5609 1 : batgeom_XMaxFromWKB_wkb(bat *ret, bat *g)
5610 : {
5611 1 : return wkbCoordinateFromWKB_bat(ret, g, &(int){3});
5612 : }
5613 : static str
5614 1 : batgeom_YMaxFromWKB_wkb(bat *ret, bat *g)
5615 : {
5616 1 : return wkbCoordinateFromWKB_bat(ret, g, &(int){4});
5617 : }
5618 : static str
5619 1 : batgeom_XMinFromMBR_mbr(bat *ret, bat *b)
5620 : {
5621 1 : return wkbCoordinateFromMBR_bat(ret, b, &(int){1});
5622 : }
5623 : static str
5624 1 : batgeom_YMinFromMBR_mbr(bat *ret, bat *b)
5625 : {
5626 1 : return wkbCoordinateFromMBR_bat(ret, b, &(int){2});
5627 : }
5628 : static str
5629 1 : batgeom_XMaxFromMBR_mbr(bat *ret, bat *b)
5630 : {
5631 1 : return wkbCoordinateFromMBR_bat(ret, b, &(int){3});
5632 : }
5633 : static str
5634 1 : batgeom_YMaxFromMBR_mbr(bat *ret, bat *b)
5635 : {
5636 1 : return wkbCoordinateFromMBR_bat(ret, b, &(int){4});
5637 : }
5638 :
5639 : #include "mel.h"
5640 : static mel_atom geom_init_atoms[] = {
5641 : { .name="mbr", .basetype="lng", .size=sizeof(mbr), .tostr=mbrTOSTR, .fromstr=mbrFROMSTR, .hash=mbrHASH, .null=mbrNULL, .cmp=mbrCOMP, .read=mbrREAD, .write=mbrWRITE, },
5642 : { .name="wkb", .tostr=wkbTOSTR, .fromstr=wkbFROMSTR, .hash=wkbHASH, .null=wkbNULL, .cmp=wkbCOMP, .read=wkbREAD, .write=wkbWRITE, .put=wkbPUT, .del=wkbDEL, .length=wkbLENGTH, .heap=wkbHEAP, },
5643 : { .cmp=NULL }
5644 : };
5645 : static mel_func geom_init_funcs[] = {
5646 : //TODO Fill in descriptions
5647 : command("geom", "CoversGeographic", wkbCoversGeographic, false, "TODO", args(1, 3, arg("", bit), arg("a", wkb), arg("b", wkb))),
5648 :
5649 : command("geom", "DistanceGeographic", wkbDistanceGeographic, false, "TODO", args(1, 3, arg("", dbl), arg("a", wkb), arg("b", wkb))),
5650 : command("batgeom", "DistanceGeographic", wkbDistanceGeographic_bat, false, "TODO", args(1, 3, batarg("", dbl), batarg("a", wkb), batarg("b", wkb))),
5651 : command("batgeom", "DistanceGeographic", wkbDistanceGeographic_bat_cand, false, "TODO", args(1, 5, batarg("", dbl), batarg("a", wkb), batarg("b", wkb), batarg("s1", oid), batarg("s2", oid))),
5652 :
5653 : //Filter functions
5654 : command("geom", "DWithinGeographic", wkbDWithinGeographic, false, "TODO", args(1, 4, arg("", bit), arg("a", wkb), arg("b", wkb), arg("d", dbl))),
5655 : command("geom", "DWithinGeographicselect", wkbDWithinGeographicSelect, false, "TODO", args(1, 6, batarg("", oid), batarg("b", wkb), batarg("s", oid), arg("c", wkb), arg("d", dbl),arg("anti",bit))),
5656 : command("geom", "DWithinGeographicjoin", wkbDWithinGeographicJoin, false, "TODO", args(2, 10, batarg("lr",oid),batarg("rr",oid), batarg("a", wkb), batarg("b", wkb), batarg("d", dbl), batarg("sl",oid),batarg("sr",oid),arg("nil_matches",bit),arg("estimate",lng),arg("anti",bit))),
5657 : command("geom", "IntersectsGeographic", wkbIntersectsGeographic, false, "Returns true if the geographic Geometries intersect in any point", args(1, 3, arg("", bit), arg("a", wkb), arg("b", wkb))),
5658 : command("geom", "IntersectsGeographicselect", wkbIntersectsGeographicSelect, false, "TODO", args(1, 5, batarg("", oid), batarg("b", wkb), batarg("s", oid), arg("c", wkb), arg("anti",bit))),
5659 : command("geom", "IntersectsGeographicjoin", wkbIntersectsGeographicJoin, false, "TODO", args(2, 9, batarg("lr",oid),batarg("rr",oid), batarg("a", wkb), batarg("b", wkb), batarg("sl",oid),batarg("sr",oid),arg("nil_matches",bit),arg("estimate",lng),arg("anti",bit))),
5660 :
5661 : command("rtree", "Intersects", wkbIntersects, false, "Returns true if these Geometries 'spatially intersect in 2D'", args(1,3, arg("",bit),arg("a",wkb),arg("b",wkb))),
5662 : command("rtree", "Intersectsselect", wkbIntersectsSelectRTree, false, "TODO", args(1, 5, batarg("", oid), batarg("b", wkb), batarg("s", oid), arg("c", wkb), arg("anti",bit))),
5663 : command("rtree", "Intersectsjoin", wkbIntersectsJoinRTree, false, "TODO", args(2, 9, batarg("lr",oid),batarg("rr",oid), batarg("a", wkb), batarg("b", wkb), batarg("sl",oid),batarg("sr",oid),arg("nil_matches",bit),arg("estimate",lng),arg("anti",bit))),
5664 :
5665 : command("rtree", "DWithin", wkbDWithin, false, "Returns true if these Geometries 'spatially intersect in 2D'", args(1,4, arg("",bit),arg("a",wkb),arg("b",wkb),arg("dst",dbl))),
5666 : command("rtree", "DWithinselect", wkbDWithinSelectRTree, false, "TODO", args(1, 6, batarg("", oid), batarg("b", wkb), batarg("s", oid), arg("c", wkb), arg("dst",dbl), arg("anti",bit))),
5667 : command("rtree", "DWithinjoin", wkbDWithinJoinRTree, false, "TODO", args(2, 10, batarg("lr",oid),batarg("rr",oid), batarg("a", wkb), batarg("b", wkb), batarg("sl",oid),batarg("sr",oid), arg("dst",dbl),arg("nil_matches",bit),arg("estimate",lng),arg("anti",bit))),
5668 :
5669 : command("geom", "Intersects_noindex", wkbIntersects, false, "Returns true if these Geometries 'spatially intersect in 2D'", args(1,3, arg("",bit),arg("a",wkb),arg("b",wkb))),
5670 : command("geom", "Intersects_noindexselect", wkbIntersectsSelectNoIndex, false, "TODO", args(1, 5, batarg("", oid), batarg("b", wkb), batarg("s", oid), arg("c", wkb), arg("anti",bit))),
5671 : command("geom", "Intersects_noindexjoin", wkbIntersectsJoinNoIndex, false, "TODO", args(2, 9, batarg("lr",oid),batarg("rr",oid), batarg("a", wkb), batarg("b", wkb), batarg("sl",oid),batarg("sr",oid),arg("nil_matches",bit),arg("estimate",lng),arg("anti",bit))),
5672 :
5673 : command("geom", "DWithin_noindex", wkbDWithin, false, "Returns true if the two geometries are within the specifies distance from each other", args(1,4, arg("",bit),arg("a",wkb),arg("b",wkb),arg("dst",dbl))),
5674 : command("geom", "DWithinselect_noindex", wkbDWithinSelectRTree, false, "TODO", args(1, 6, batarg("", oid), batarg("b", wkb), batarg("s", oid), arg("c", wkb), arg("dst",dbl), arg("anti",bit))),
5675 : command("geom", "DWithinjoin_noindex", wkbDWithinJoinRTree, false, "TODO", args(2, 10, batarg("lr",oid),batarg("rr",oid), batarg("a", wkb), batarg("b", wkb), batarg("sl",oid),batarg("sr",oid), arg("dst",dbl),arg("nil_matches",bit),arg("estimate",lng),arg("anti",bit))),
5676 :
5677 : command("geom", "IntersectsMBR", mbrIntersects, false, "TODO", args(1,3, arg("",bit),arg("a",mbr),arg("b",mbr))),
5678 :
5679 : command("geom", "Collect", wkbCollect, false, "TODO", args(1,3, arg("",wkb),arg("a",wkb),arg("b",wkb))),
5680 :
5681 : command("aggr", "Collect", wkbCollectAggr, false, "TODO", args(1, 2, arg("", wkb), batarg("val", wkb))),
5682 : command("aggr", "subCollect", wkbCollectAggrSubGrouped, false, "TODO", args(1, 5, batarg("", wkb), batarg("val", wkb), batarg("g", oid), batarg("e", oid), arg("skip_nils", bit))),
5683 : command("aggr", "subCollect", wkbCollectAggrSubGroupedCand, false, "TODO", args(1, 6, batarg("", wkb), batarg("val", wkb), batarg("g", oid), batargany("e", 1), batarg("g", oid), arg("skip_nils", bit))),
5684 :
5685 : command("geom", "hasZ", geoHasZ, false, "returns 1 if the geometry has z coordinate", args(1,2, arg("",int),arg("flags",int))),
5686 : command("geom", "hasM", geoHasM, false, "returns 1 if the geometry has m coordinate", args(1,2, arg("",int),arg("flags",int))),
5687 : command("geom", "getType", geoGetType, false, "returns the str representation of the geometry type", args(1,3, arg("",str),arg("flags",int),arg("format",int))),
5688 :
5689 : command("geom", "MLineStringToPolygon", wkbMLineStringToPolygon, false, "Creates polygons using the MultiLineString provided as WKT. Depending on the flag creates one (flag=0) or multiple (flag=1) polygons", args(1,4, arg("",wkb),arg("wkt",str),arg("srid",int),arg("flag",int))),
5690 : command("geom", "AsBinary", wkbAsBinary, false, "Returns the wkb representation into HEX format", args(1,2, arg("",str),arg("w",wkb))),
5691 : command("geom", "FromBinary", wkbFromBinary, false, "Creates a wkb using the HEX representation", args(1,2, arg("",wkb),arg("w",str))),
5692 : command("geom", "ToText", wkbAsText, false, "", args(1,3, arg("",str),arg("w",wkb),arg("withSRID",int))),
5693 : command("geom", "FromText", wkbFromText, false, "", args(1,4, arg("",wkb),arg("wkt",str),arg("srid",int),arg("type",int))),
5694 : command("geom", "NumRings", wkbNumRings, false, "Returns the number of interior rings+exterior on the first polygon of the geometry", args(1,3, arg("",int),arg("w",wkb),arg("exterior",int))),
5695 : command("geom", "MakePointXYZM", wkbMakePoint, false, "creates a point using the coordinates", args(1,6, arg("",wkb),arg("x",dbl),arg("y",dbl),arg("z",dbl),arg("m",dbl),arg("zmFlag",int))),
5696 : command("geom", "GeometryType", wkbGeometryType, false, "", args(1,3, arg("",str),arg("w",wkb),arg("flag",int))),
5697 : command("geom", "GetCoordinate", wkbGetCoordinate, false, "Returns the coordinate at position idx of a point, or NULL if not available. idx=0 -> X, idx=1 -> Y, idx=2 -> Z. Input must be point", args(1,3, arg("",dbl),arg("w",wkb),arg("idx",int))),
5698 : command("geom", "Boundary", wkbBoundary, false, "Returns the closure of the combinatorial boundary of the Geometry.", args(1,2, arg("",wkb),arg("w",wkb))),
5699 : command("geom", "CoordDim", wkbCoordDim, false, "Return the coordinate dimension of the geometry", args(1,2, arg("",int),arg("w",wkb))),
5700 : command("geom", "Dimension", wkbDimension, false, "The inherent dimension of this Geometry object, which must be less than or equal to the coordinate dimension.", args(1,2, arg("",int),arg("w",wkb))),
5701 : command("geom", "getSRID", wkbGetSRID, false, "Returns the Spatial Reference System ID for this Geometry.", args(1,2, arg("",int),arg("w",wkb))),
5702 : command("geom", "setSRID", wkbSetSRID, false, "Sets the Reference System ID for this Geometry.", args(1,3, arg("",wkb),arg("w",wkb),arg("srid",int))),
5703 : command("geom", "StartPoint", wkbStartPoint, false, "Returns the first point of a LINESTRING geometry as a POINT or NULL if the input parameter is not a LINESTRING", args(1,2, arg("",wkb),arg("w",wkb))),
5704 : command("geom", "EndPoint", wkbEndPoint, false, "Returns the last point of a LINESTRING geometry as a POINT or NULL if the input parameter is not a LINESTRING.", args(1,2, arg("",wkb),arg("w",wkb))),
5705 : command("geom", "PointN", wkbPointN, false, "Returns the n-th point of the Geometry. Argument w should be Linestring.", args(1,3, arg("",wkb),arg("w",wkb),arg("n",int))),
5706 : command("geom", "Envelope", wkbEnvelope, false, "The minimum bounding box for this Geometry, returned as a Geometry. The polygon is defined by the corner points of the bounding box ((MINX,MINY),(MAXX,MINY),(MAXX,MAXY),(MINX,MAXY)).", args(1,2, arg("",wkb),arg("w",wkb))),
5707 : command("geom", "EnvelopeFromCoordinates", wkbEnvelopeFromCoordinates, false, "A polygon created by the provided coordinates", args(1,6, arg("",wkb),arg("",dbl),arg("",dbl),arg("",dbl),arg("",dbl),arg("",int))),
5708 : command("geom", "Polygon", wkbMakePolygon, false, "Returns a Polygon created from the provided LineStrings", args(1,4, arg("",wkb),arg("",wkb),batarg("",wkb),arg("",int))),
5709 : command("geom", "ExteriorRing", wkbExteriorRing, false, "Returns a line string representing the exterior ring of the POLYGON geometry. Return NULL if the geometry is not a polygon.", args(1,2, arg("",wkb),arg("w",wkb))),
5710 : command("geom", "InteriorRingN", wkbInteriorRingN, false, "Return the Nth interior linestring ring of the polygon geometry. Return NULL if the geometry is not a polygon or the given N is out of range.", args(1,3, arg("",wkb),arg("w",wkb),arg("n",int))),
5711 : command("geom", "IsClosed", wkbIsClosed, false, "Returns TRUE if the LINESTRING's start and end points are coincident.", args(1,2, arg("",bit),arg("w",wkb))),
5712 : command("geom", "IsEmpty", wkbIsEmpty, false, "Returns true if this Geometry is an empty geometry.", args(1,2, arg("",bit),arg("w",wkb))),
5713 : command("geom", "IsRing", wkbIsRing, false, "Returns TRUE if this LINESTRING is both closed and simple.", args(1,2, arg("",bit),arg("w",wkb))),
5714 : command("geom", "IsSimple", wkbIsSimple, false, "Returns (TRUE) if this Geometry has no anomalous geometric points, such as self intersection or self tangency.", args(1,2, arg("",bit),arg("w",wkb))),
5715 : command("geom", "IsValid", wkbIsValid, false, "Returns true if the ST_Geometry is well formed.", args(1,2, arg("",bit),arg("w",wkb))),
5716 : command("geom", "IsValidReason", wkbIsValidReason, false, "Returns text stating if a geometry is valid or not and if not valid, a reason why.", args(1,2, arg("",str),arg("w",wkb))),
5717 : command("geom", "IsValidDetail", wkbIsValidDetail, false, "Returns a valid_detail (valid,reason,location) row stating if a geometry is valid or not and if not valid, a reason why and a location where.", args(1,2, arg("",str),arg("w",wkb))),
5718 : command("geom", "Area", wkbArea, false, "Returns the area of the surface if it is a polygon or multi-polygon", args(1,2, arg("",dbl),arg("w",wkb))),
5719 : command("geom", "Centroid", wkbCentroid, false, "Computes the geometric center of a geometry, or equivalently, the center of mass of the geometry as a POINT.", args(1,2, arg("",wkb),arg("w",wkb))),
5720 : command("geom", "Distance", wkbDistance, false, "Returns the 2-dimensional minimum cartesian distance between the two geometries in projected units (spatial ref units.", args(1,3, arg("",dbl),arg("a",wkb),arg("b",wkb))),
5721 : command("geom", "Length", wkbLength, false, "Returns the cartesian 2D length of the geometry if it is a linestring or multilinestring", args(1,2, arg("",dbl),arg("w",wkb))),
5722 : command("geom", "ConvexHull", wkbConvexHull, false, "Returns a geometry that represents the convex hull of this geometry. The convex hull of a geometry represents the minimum convex geometry that encloses all geometries within the set.", args(1,2, arg("",wkb),arg("w",wkb))),
5723 : command("geom", "Intersection", wkbIntersection, false, "Returns a geometry that represents the point set intersection of the Geometries a, b", args(1,3, arg("",wkb),arg("a",wkb),arg("b",wkb))),
5724 : command("geom", "Union", wkbUnion, false, "Returns a geometry that represents the point set union of the Geometries a, b", args(1,3, arg("",wkb),arg("a",wkb),arg("b",wkb))),
5725 : command("geom", "Union", wkbUnionAggr, false, "Gets a BAT with geometries and returns their union", args(1,2, arg("",wkb),batarg("a",wkb))),
5726 : command("geom", "Difference", wkbDifference, false, "Returns a geometry that represents that part of geometry A that does not intersect with geometry B", args(1,3, arg("",wkb),arg("a",wkb),arg("b",wkb))),
5727 : command("geom", "SymDifference", wkbSymDifference, false, "Returns a geometry that represents the portions of A and B that do not intersect", args(1,3, arg("",wkb),arg("a",wkb),arg("b",wkb))),
5728 : command("geom", "Buffer", wkbBuffer, false, "Returns a geometry that represents all points whose distance from this geometry is less than or equal to distance. Calculations are in the Spatial Reference System of this Geometry.", args(1,3, arg("",wkb),arg("a",wkb),arg("distance",dbl))),
5729 : command("geom", "Contains", wkbContains, false, "Returns true if and only if no points of B lie in the exterior of A, and at least one point of the interior of B lies in the interior of A.", args(1,3, arg("",bit),arg("a",wkb),arg("b",wkb))),
5730 : command("geom", "Crosses", wkbCrosses, false, "Returns TRUE if the supplied geometries have some, but not all, interior points in common.", args(1,3, arg("",bit),arg("a",wkb),arg("b",wkb))),
5731 : command("geom", "Disjoint", wkbDisjoint, false, "Returns true if these Geometries are 'spatially disjoint'", args(1,3, arg("",bit),arg("a",wkb),arg("b",wkb))),
5732 : command("geom", "Equals", wkbEquals, false, "Returns true if the given geometries represent the same geometry. Directionality is ignored.", args(1,3, arg("",bit),arg("a",wkb),arg("b",wkb))),
5733 : command("geom", "Overlaps", wkbOverlaps, false, "Returns TRUE if the Geometries intersect but are not completely contained by each other.", args(1,3, arg("",bit),arg("a",wkb),arg("b",wkb))),
5734 : command("geom", "Relate", wkbRelate, false, "Returns true if the Geometry a 'spatially related' to Geometry b, by testing for intersection between the Interior, Boundary and Exterior of the two geometries as specified by the values in the intersectionPatternMatrix.", args(1,4, arg("",bit),arg("a",wkb),arg("b",wkb),arg("intersection_matrix_pattern",str))),
5735 : command("geom", "Touches", wkbTouches, false, "Returns TRUE if the geometries have at least one point in common, but their interiors do not intersect.", args(1,3, arg("",bit),arg("a",wkb),arg("b",wkb))),
5736 : command("geom", "Within", wkbWithin, false, "Returns TRUE if the geometry A is completely inside geometry B", args(1,3, arg("",bit),arg("a",wkb),arg("b",wkb))),
5737 : command("geom", "Covers", wkbCovers, false, "Returns TRUE if no point of geometry B is outside geometry A", args(1,3, arg("",bit),arg("a",wkb),arg("b",wkb))),
5738 : command("geom", "CoveredBy", wkbCoveredBy, false, "Returns TRUE if no point of geometry A is outside geometry B", args(1,3, arg("",bit),arg("a",wkb),arg("b",wkb))),
5739 : command("geom", "DWithin2", wkbDWithinMbr, false, "" /* <<< desc TODO */, args(1,6, arg("",bit),arg("a",wkb),arg("b",wkb),arg("a_mbr",mbr),arg("b_mbr",mbr),arg("dst",dbl))),
5740 : command("geom", "GeometryN", wkbGeometryN, false, "Returns the 1-based Nth geometry if the geometry is a GEOMETRYCOLLECTION, (MULTI)POINT, (MULTI)LINESTRING, MULTICURVE or (MULTI)POLYGON. Otherwise, return NULL", args(1,3, arg("",wkb),arg("g",wkb),arg("n",int))),
5741 : command("geom", "NumGeometries", wkbNumGeometries, false, "Returns the number of geometries", args(1,2, arg("",int),arg("g",wkb))),
5742 : command("geom", "Transform", wkbTransform, false, "Transforms a geometry from one srid to another", args(1,6, arg("",wkb),arg("g",wkb),arg("srid_src",int),arg("srid_dst",int),arg("proj_src",str),arg("proj_dest",str))),
5743 : command("geom", "DelaunayTriangles", wkbDelaunayTriangles, false, "Returns a Delaunay triangulation, flag=0 => collection of polygons, flag=1 => multilinestring", args(1,4, arg("",wkb),arg("a",wkb),arg("tolerance",dbl),arg("flag",int))),
5744 : command("geom", "Dump", wkbDump, false, "Gets a MultiPolygon and returns the Polygons in it", args(2,3, batarg("id",str),batarg("geom",wkb),arg("a",wkb))),
5745 : command("geom", "DumpPoints", wkbDumpPoints, false, "Gets a Geometry and returns the Points in it", args(2,3, batarg("id",str),batarg("geom",wkb),arg("a",wkb))),
5746 : command("geom", "Segmentize", wkbSegmentize, false, "It creates a new geometry with all segments on it smaller or equal to sz", args(1,3, arg("",wkb),arg("g",wkb),arg("sz",dbl))),
5747 : command("geom", "ForceDimensions", wkbForceDim, false, "Removes or Adds additional coordinates in the geometry to make it d dimensions", args(1,3, arg("",wkb),arg("g",wkb),arg("d",int))),
5748 : command("geom", "Contains", wkbContains_point, false, "Returns true if the Geometry a 'spatially contains' Geometry b", args(1,4, arg("",bit),arg("a",wkb),arg("x",dbl),arg("y",dbl))),
5749 : command("geom", "Translate3D", wkbTranslate, false, "Moves all points of the geometry by dx, dy, dz", args(1,5, arg("",wkb),arg("g",wkb),arg("dx",dbl),arg("dy",dbl),arg("dz",dbl))),
5750 : command("geom", "Contains", wkbContains_point_bat, false, "Returns true if the Geometry-BAT a 'spatially contains' Geometry-B b", args(1,4, batarg("",bit),arg("a",wkb),batarg("px",dbl),batarg("py",dbl))),
5751 : command("geom", "PointsNum", wkbNumPoints, false, "The number of points in the Geometry. If check=1, the geometry should be a linestring", args(1,3, arg("",int),arg("w",wkb),arg("check",int))),
5752 : command("geom", "MakeLine", wkbMakeLine, false, "Gets two point or linestring geometries and returns a linestring geometry", args(1,3, arg("",wkb),arg("a",wkb),arg("b",wkb))),
5753 : command("aggr", "MakeLine", wkbMakeLineAggr, false, "Gets a BAT with point or linestring geometries and returns a single linestring geometry", args(1,2, arg("",wkb),batarg("a",wkb))),
5754 : command("aggr", "subMakeLine", wkbMakeLineAggrSubGrouped, false, "TODO", args(1, 5, batarg("", wkb), batarg("val", wkb), batarg("g", oid), batarg("e", oid), arg("skip_nils", bit))),
5755 : command("aggr", "subMakeLine", wkbMakeLineAggrSubGroupedCand, false, "TODO", args(1, 6, batarg("", wkb), batarg("val", wkb), batarg("g", oid), batargany("e", 1), batarg("g", oid), arg("skip_nils", bit))),
5756 : command("geom", "PointOnSurface", wkbPointOnSurface, false, "Returns a point guaranteed to lie on the surface. Similar to postGIS it works for points and lines in addition to surfaces and for 3d geometries.", args(1,2, arg("",wkb),arg("w",wkb))),
5757 : command("geom", "mbr", wkbMBR, false, "Creates the mbr for the given wkb.", args(1,2, arg("",mbr),arg("",wkb))),
5758 : command("geom", "MakeBox2D", wkbBox2D, false, "Creates an mbr from the two 2D points", args(1,3, arg("",mbr),arg("",wkb),arg("",wkb))),
5759 : command("geom", "mbrOverlaps", mbrOverlaps_wkb, false, "Returns true if the mbr of geom1 overlaps the mbr of geom2", args(1,3, arg("",bit),arg("geom1",wkb),arg("geom2",wkb))),
5760 : command("geom", "mbrOverlaps", mbrOverlaps, false, "Returns true if box1 overlaps box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5761 : command("geom", "mbrOverlapOrLeft", mbrOverlapOrLeft_wkb, false, "Returns true if the mbr of geom1 overlaps or is to the left of thr mbr of geom2", args(1,3, arg("",bit),arg("geom1",wkb),arg("geom2",wkb))),
5762 : command("geom", "mbrOverlapOrLeft", mbrOverlapOrLeft, false, "Returns true if box1 overlaps or is to the left of box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5763 : command("geom", "mbrOverlapOrBelow", mbrOverlapOrBelow_wkb, false, "Returns true if the mbr of geom1 overlaps or is below the mbr of geom2", args(1,3, arg("",bit),arg("geom1",wkb),arg("geom2",wkb))),
5764 : command("geom", "mbrOverlapOrBelow", mbrOverlapOrBelow, false, "Returns true if box1 overlaps or is below box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5765 : command("geom", "mbrOverlapOrRight", mbrOverlapOrRight_wkb, false, "Returns true if the mbr of geom1 overlalps or is right of the mbr of geom2", args(1,3, arg("",bit),arg("geom1",wkb),arg("geom2",wkb))),
5766 : command("geom", "mbrOverlapOrRight", mbrOverlapOrRight, false, "Returns true if box1 overlalps or is right of box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5767 : command("geom", "mbrLeft", mbrLeft_wkb, false, "Returns true if the mbr of geom1 is left of the mbr of geom2", args(1,3, arg("",bit),arg("geom1",wkb),arg("geom2",wkb))),
5768 : command("geom", "mbrLeft", mbrLeft, false, "Returns true if box1 is left of box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5769 : command("geom", "mbrBelow", mbrBelow_wkb, false, "Returns true if the mbr of geom1 is below the mbr of geom2", args(1,3, arg("",bit),arg("geom1",wkb),arg("geom2",wkb))),
5770 : command("geom", "mbrBelow", mbrBelow, false, "Returns true if box1 is below box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5771 : command("geom", "mbrEqual", mbrEqual_wkb, false, "Returns true if the mbr of geom1 is the same as the mbr of geom2", args(1,3, arg("",bit),arg("geom1",wkb),arg("geom2",wkb))),
5772 : command("geom", "mbrEqual", mbrEqual, false, "Returns true if box1 is the same as box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5773 : command("geom", "mbrRight", mbrRight_wkb, false, "Returns true if the mbr of geom1 is right of the mbr of geom2", args(1,3, arg("",bit),arg("geom1",wkb),arg("geom2",wkb))),
5774 : command("geom", "mbrRight", mbrRight, false, "Returns true if box1 is right of box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5775 : command("geom", "mbrContained", mbrContained_wkb, false, "Returns true if the mbr of geom1 is contained by the mbr of geom2", args(1,3, arg("",bit),arg("geom1",wkb),arg("geom2",wkb))),
5776 : command("geom", "mbrContained", mbrContained, false, "Returns true if box1 is contained by box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5777 : command("geom", "mbrOverlapOrAbove", mbrOverlapOrAbove_wkb, false, "Returns true if the mbr of geom1 overlaps or is above the mbr of geom2", args(1,3, arg("",bit),arg("geom1",wkb),arg("geom2",wkb))),
5778 : command("geom", "mbrOverlapOrAbove", mbrOverlapOrAbove, false, "Returns true if box1 overlaps or is above box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5779 : command("geom", "mbrAbove", mbrAbove_wkb, false, "Returns true if the mbr of geom1 is above the mbr of geom2", args(1,3, arg("",bit),arg("geom1",wkb),arg("geom2",wkb))),
5780 : command("geom", "mbrAbove", mbrAbove, false, "Returns true if box1 is above box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5781 : command("geom", "mbrContains", mbrContains_wkb, false, "Returns true if the mbr of geom1 contains the mbr of geom2", args(1,3, arg("",bit),arg("geom1",wkb),arg("geom2",wkb))),
5782 : command("geom", "mbrContains", mbrContains, false, "Returns true if box1 contains box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5783 : command("geom", "mbrDistance", mbrDistance_wkb, false, "Returns the distance of the centroids of the mbrs of the two geometries", args(1,3, arg("",dbl),arg("geom1",wkb),arg("geom2",wkb))),
5784 : command("geom", "mbrDistance", mbrDistance, false, "Returns the distance of the centroids of the two boxes", args(1,3, arg("",dbl),arg("box1",mbr),arg("box2",mbr))),
5785 : command("geom", "coordinateFromWKB", wkbCoordinateFromWKB, false, "returns xmin (=1), ymin (=2), xmax (=3) or ymax(=4) of the provided geometry", args(1,3, arg("",dbl),arg("",wkb),arg("",int))),
5786 : command("geom", "coordinateFromMBR", wkbCoordinateFromMBR, false, "returns xmin (=1), ymin (=2), xmax (=3) or ymax(=4) of the provided mbr", args(1,3, arg("",dbl),arg("",mbr),arg("",int))),
5787 : command("geom", "epilogue", geom_epilogue, false, "", args(1,1, arg("",void))),
5788 : command("batgeom", "FromText", wkbFromText_bat, false, "", args(1,4, batarg("",wkb),batarg("wkt",str),arg("srid",int),arg("type",int))),
5789 : command("batgeom", "ToText", wkbAsText_bat, false, "", args(1,3, batarg("",str),batarg("w",wkb),arg("withSRID",int))),
5790 : command("batgeom", "GeometryType", wkbGeometryType_bat, false, "", args(1,3, batarg("",str),batarg("w",wkb),arg("flag",int))),
5791 : command("batgeom", "MakePointXYZM", wkbMakePoint_bat, false, "creates a point using the coordinates", args(1,6, batarg("",wkb),batarg("x",dbl),batarg("y",dbl),batarg("z",dbl),batarg("m",dbl),arg("zmFlag",int))),
5792 : command("batgeom", "PointsNum", wkbNumPoints_bat, false, "The number of points in the Geometry. If check=1, the geometry should be a linestring", args(1,3, batarg("",int),batarg("w",wkb),arg("check",int))),
5793 : command("batgeom", "GetCoordinate", wkbGetCoordinate_bat, false, "Returns the coordinate at position idx of a point, or NULL if not available. idx=0 -> X, idx=1 -> Y, idx=2 -> Z. Input must be point", args(1,3, batarg("",dbl),batarg("w",wkb),arg("idx",int))),
5794 : command("batgeom", "GeometryN", wkbGeometryN_bat, false, "Returns the 1-based Nth geometry if the geometry is a GEOMETRYCOLLECTION, (MULTI)POINT, (MULTI)LINESTRING, MULTICURVE or (MULTI)POLYGON. Otherwise, return NULL", args(1,3, batarg("",wkb),batarg("w",wkb),arg("n",int))),
5795 : command("batgeom", "NumGeometries", wkbNumGeometries_bat, false, "Returns the number of geometries", args(1,2, batarg("",int),batarg("w",wkb))),
5796 : command("batgeom", "NumRings", wkbNumRings_bat, false, "Returns the number of interior rings+exterior on the first polygon of the geometry", args(1,3, batarg("",int),batarg("w",wkb),arg("exterior",int))),
5797 : command("batgeom", "Boundary", wkbBoundary_bat, false, "", args(1,2, batarg("",wkb),batarg("w",wkb))),
5798 : command("batgeom", "IsClosed", wkbIsClosed_bat, false, "", args(1,2, batarg("",bit),batarg("w",wkb))),
5799 : command("batgeom", "IsEmpty", wkbIsEmpty_bat, false, "", args(1,2, batarg("",bit),batarg("w",wkb))),
5800 : command("batgeom", "IsSimple", wkbIsSimple_bat, false, "", args(1,2, batarg("",bit),batarg("w",wkb))),
5801 : command("batgeom", "IsRing", wkbIsRing_bat, false, "", args(1,2, batarg("",bit),batarg("w",wkb))),
5802 : command("batgeom", "IsValid", wkbIsValid_bat, false, "", args(1,2, batarg("",bit),batarg("w",wkb))),
5803 : command("batgeom", "MakeBox2D", wkbBox2D_bat, false, "", args(1,3, batarg("",mbr),batarg("p1",wkb),batarg("p2",wkb))),
5804 : command("batgeom", "Dimension", wkbDimension_bat, false, "", args(1,2, batarg("",int),batarg("w",wkb))),
5805 : command("batgeom", "Distance", wkbDistance_bat, false, "", args(1,3, batarg("",dbl),batarg("a",wkb),batarg("b",wkb))),
5806 : command("batgeom", "Distance", wkbDistance_geom_bat, false, "", args(1,3, batarg("",dbl),arg("a",wkb),batarg("b",wkb))),
5807 : command("batgeom", "Distance", wkbDistance_bat_geom, false, "", args(1,3, batarg("",dbl),batarg("a",wkb),arg("b",wkb))),
5808 : command("batgeom", "Contains", wkbContains_bat, false, "", args(1,3, batarg("",bit),batarg("a",wkb),batarg("b",wkb))),
5809 : command("batgeom", "Contains", wkbContains_geom_bat, false, "", args(1,3, batarg("",bit),arg("a",wkb),batarg("b",wkb))),
5810 : command("batgeom", "Contains", wkbContains_bat_geom, false, "", args(1,3, batarg("",bit),batarg("a",wkb),arg("b",wkb))),
5811 : command("batgeom", "Filter", wkbFilter_geom_bat, false, "Filters the points in the bats according to the MBR of the other bat.", args(1,3, batarg("",wkb),arg("a",wkb),batarg("b",wkb))),
5812 : command("batgeom", "Filter", wkbFilter_bat_geom, false, "", args(1,3, batarg("",wkb),batarg("a",wkb),arg("b",wkb))),
5813 : command("batgeom", "setSRID", wkbSetSRID_bat, false, "Sets the Reference System ID for this Geometry.", args(1,3, batarg("",wkb),batarg("w",wkb),arg("srid",int))),
5814 : command("batgeom", "MakeLine", wkbMakeLine_bat, false, "Gets two BATS of point or linestring geometries and returns a bat with linestring geometries", args(1,3, batarg("",wkb),batarg("a",wkb),batarg("b",wkb))),
5815 : command("batgeom", "Union", wkbUnion_bat, false, "Gets two BATS of geometries and returns the pairwise unions", args(1,3, batarg("",wkb),batarg("a",wkb),batarg("b",wkb))),
5816 : command("batgeom", "mbr", wkbMBR_bat, false, "Creates the mbr for the given wkb.", args(1,2, batarg("",mbr),batarg("",wkb))),
5817 : command("batgeom", "coordinateFromWKB", wkbCoordinateFromWKB_bat, false, "returns xmin (=1), ymin (=2), xmax (=3) or ymax(=4) of the provided geometry", args(1,3, batarg("",dbl),batarg("",wkb),arg("",int))),
5818 : command("batgeom", "coordinateFromMBR", wkbCoordinateFromMBR_bat, false, "returns xmin (=1), ymin (=2), xmax (=3) or ymax(=4) of the provided mbr", args(1,3, batarg("",dbl),batarg("",mbr),arg("",int))),
5819 : command("batgeom", "Transform", wkbTransform_bat, false, "Transforms a bat of geometries from one srid to another", args(1,6, batarg("",wkb),batarg("g",wkb),arg("srid_src",int),arg("srid_dst",int),arg("proj_src",str),arg("proj_dest",str))),
5820 : command("calc", "mbr", mbrFromString, false, "", args(1,2, arg("",mbr),arg("v",str))),
5821 : command("calc", "mbr", mbrFromMBR, false, "", args(1,2, arg("",mbr),arg("v",mbr))),
5822 : command("calc", "wkb", wkbFromWKB, false, "It is called when adding a new geometry column to an existing table", args(1,2, arg("",wkb),arg("v",wkb))),
5823 : command("calc", "wkb", geom_2_geom, false, "Called when inserting values to a table in order to check if the inserted geometries are of the same type and srid required by the column definition", args(1,4, arg("",wkb),arg("geo",wkb),arg("columnType",int),arg("columnSRID",int))),
5824 : command("batcalc", "wkb", geom_2_geom_bat, false, "Called when inserting values to a table in order to check if the inserted geometries are of the same type and srid required by the column definition", args(1,5, batarg("",wkb),batarg("geo",wkb),batarg("s",oid),arg("columnType",int),arg("columnSRID",int))),
5825 : command("batcalc", "wkb", wkbFromText_bat_cand, false, "", args(1,5, batarg("",wkb),batarg("wkt",str),batarg("s",oid),arg("srid",int),arg("type",int))),
5826 : command("geom", "AsText", geom_AsText_wkb, false, "", args(1,2, arg("",str),arg("w",wkb))),
5827 : command("geom", "AsEWKT", geom_AsEWKT_wkb, false, "", args(1,2, arg("",str),arg("w",wkb))),
5828 : command("geom", "GeomFromText", geom_GeomFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5829 : command("geom", "PointFromText", geom_PointFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5830 : command("geom", "LineFromText", geom_LineFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5831 : command("geom", "PolygonFromText", geom_PolygonFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5832 : command("geom", "MPointFromText", geom_MPointFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5833 : command("geom", "MLineFromText", geom_MLineFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5834 : command("geom", "MPolyFromText", geom_MPolyFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5835 : command("geom", "GeomCollFromText", geom_GeomCollFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5836 : command("geom", "GeomFromText", geom_GeomFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5837 : command("geom", "PointFromText", geom_PointFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5838 : command("geom", "LineFromText", geom_LineFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5839 : command("geom", "PolygonFromText", geom_PolygonFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5840 : command("geom", "MPointFromText", geom_MPointFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5841 : command("geom", "MLineFromText", geom_MLineFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5842 : command("geom", "MPolyFromText", geom_MPolyFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5843 : command("geom", "GeomCollFromText", geom_GeomCollFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5844 : command("geom", "NumInteriorRings", geom_NumInteriorRings_wkb, false, "", args(1,2, arg("",int),arg("w",wkb))),
5845 : command("geom", "NRings", geom_NRings_wkb, false, "", args(1,2, arg("",int),arg("w",wkb))),
5846 : command("geom", "BdPolyFromText", geom_BdPolyFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5847 : command("geom", "BdMPolyFromText", geom_BdMPolyFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5848 : command("geom", "MakePoint", geom_MakePoint_dbl_dbl, false, "", args(1,3, arg("",wkb),arg("x",dbl),arg("y",dbl))),
5849 : command("geom", "MakePoint", geom_MakePoint_dbl_dbl_dbl, false, "", args(1,4, arg("",wkb),arg("x",dbl),arg("y",dbl),arg("z",dbl))),
5850 : command("geom", "MakePointM", geom_MakePointM_dbl_dbl_dbl, false, "", args(1,4, arg("",wkb),arg("x",dbl),arg("y",dbl),arg("m",dbl))),
5851 : command("geom", "MakePoint", geom_MakePoint_dbl_dbl_dbl_dbl, false, "", args(1,5, arg("",wkb),arg("x",dbl),arg("y",dbl),arg("z",dbl),arg("m",dbl))),
5852 : command("geom", "GeometryType1", geom_GeometryType1_wkb, false, "", args(1,2, arg("",str),arg("w",wkb))),
5853 : command("geom", "GeometryType2", geom_GeometryType2_wkb, false, "", args(1,2, arg("",str),arg("w",wkb))),
5854 : command("geom", "X", geom_X_wkb, false, "", args(1,2, arg("",dbl),arg("w",wkb))),
5855 : command("geom", "Y", geom_Y_wkb, false, "", args(1,2, arg("",dbl),arg("w",wkb))),
5856 : command("geom", "Z", geom_Z_wkb, false, "", args(1,2, arg("",dbl),arg("w",wkb))),
5857 : command("geom", "Force2D", geom_Force2D_wkb, false, "", args(1,2, arg("",wkb),arg("g",wkb))),
5858 : command("geom", "Force3D", geom_Force3D_wkb, false, "", args(1,2, arg("",wkb),arg("g",wkb))),
5859 : command("geom", "Translate", geom_Translate_wkb_dbl_dbl, false, "", args(1,4, arg("",wkb),arg("g",wkb),arg("dx",dbl),arg("dy",dbl))),
5860 : command("geom", "Translate", geom_Translate_wkb_dbl_dbl_dbl, false, "", args(1,5, arg("",wkb),arg("g",wkb),arg("dx",dbl),arg("dy",dbl),arg("dz",dbl))),
5861 : command("geom", "NumPoints", geom_NumPoints_wkb, false, "", args(1,2, arg("",int),arg("w",wkb))),
5862 : command("geom", "NPoints", geom_NPoints_wkb, false, "", args(1,2, arg("",int),arg("w",wkb))),
5863 : command("geom", "MakeEnvelope", geom_MakeEnvelope_dbl_dbl_dbl_dbl_int, false, "", args(1,6, arg("",wkb),arg("xmin",dbl),arg("ymin",dbl),arg("xmax",dbl),arg("ymax",dbl),arg("srid",int))),
5864 : command("geom", "MakeEnvelope", geom_MakeEnvelope_dbl_dbl_dbl_dbl, false, "", args(1,5, arg("",wkb),arg("xmin",dbl),arg("ymin",dbl),arg("xmax",dbl),arg("ymax",dbl))),
5865 : command("geom", "MakePolygon", geom_MakePolygon_wkb, false, "", args(1,2, arg("",wkb),arg("external",wkb))),
5866 : command("geom", "MakePolygon", geom_MakePolygon_wkb_int, false, "", args(1,3, arg("",wkb),arg("external",wkb),arg("srid",int))),
5867 : command("geom", "XMinFromWKB", geom_XMinFromWKB_wkb, false, "", args(1,2, arg("",dbl),arg("g",wkb))),
5868 : command("geom", "YMinFromWKB", geom_YMinFromWKB_wkb, false, "", args(1,2, arg("",dbl),arg("g",wkb))),
5869 : command("geom", "XMaxFromWKB", geom_XMaxFromWKB_wkb, false, "", args(1,2, arg("",dbl),arg("g",wkb))),
5870 : command("geom", "YMaxFromWKB", geom_YMaxFromWKB_wkb, false, "", args(1,2, arg("",dbl),arg("g",wkb))),
5871 : command("geom", "XMinFromMBR", geom_XMinFromMBR_mbr, false, "", args(1,2, arg("",dbl),arg("b",mbr))),
5872 : command("geom", "YMinFromMBR", geom_YMinFromMBR_mbr, false, "", args(1,2, arg("",dbl),arg("b",mbr))),
5873 : command("geom", "XMaxFromMBR", geom_XMaxFromMBR_mbr, false, "", args(1,2, arg("",dbl),arg("b",mbr))),
5874 : command("geom", "YMaxFromMBR", geom_YMaxFromMBR_mbr, false, "", args(1,2, arg("",dbl),arg("b",mbr))),
5875 : command("calc", "wkb", calc_wkb_str_int_int, false, "", args(1,4, arg("",wkb),arg("wkt",str),arg("srid",int),arg("type",int))),
5876 : command("batgeom", "GeomFromText", batgeom_GeomFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5877 : command("batgeom", "PointFromText", batgeom_PointFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5878 : command("batgeom", "LineFromText", batgeom_LineFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5879 : command("batgeom", "PolygonFromText", batgeom_PolygonFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5880 : command("batgeom", "MPointFromText", batgeom_MPointFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5881 : command("batgeom", "MLineFromText", batgeom_MLineFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5882 : command("batgeom", "MPolyFromText", batgeom_MPolyFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5883 : command("batgeom", "GeomCollFromText", batgeom_GeomCollFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5884 : command("batgeom", "GeomFromText", batgeom_GeomFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5885 : command("batgeom", "PointFromText", batgeom_PointFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5886 : command("batgeom", "LineFromText", batgeom_LineFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5887 : command("batgeom", "PolygonFromText", batgeom_PolygonFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5888 : command("batgeom", "MPointFromText", batgeom_MPointFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5889 : command("batgeom", "MLineFromText", batgeom_MLineFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5890 : command("batgeom", "MPolyFromText", batgeom_MPolyFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5891 : command("batgeom", "GeomCollFromText", batgeom_GeomCollFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5892 : command("batgeom", "AsText", batgeom_AsText_wkb, false, "", args(1,2, batarg("",str),batarg("w",wkb))),
5893 : command("batgeom", "AsEWKT", batgeom_AsEWKT_wkb, false, "", args(1,2, batarg("",str),batarg("w",wkb))),
5894 : command("batgeom", "GeometryType1", batgeom_GeometryType1_wkb, false, "", args(1,2, batarg("",str),batarg("w",wkb))),
5895 : command("batgeom", "GeometryType2", batgeom_GeometryType2_wkb, false, "", args(1,2, batarg("",str),batarg("w",wkb))),
5896 : command("batgeom", "MakePoint", batgeom_MakePoint_dbl_dbl, false, "", args(1,3, batarg("",wkb),batarg("x",dbl),batarg("y",dbl))),
5897 : command("batgeom", "MakePoint", batgeom_MakePoint_dbl_dbl_dbl, false, "", args(1,4, batarg("",wkb),batarg("x",dbl),batarg("y",dbl),batarg("z",dbl))),
5898 : command("batgeom", "MakePointM", batgeom_MakePointM_dbl_dbl_dbl, false, "", args(1,4, batarg("",wkb),batarg("x",dbl),batarg("y",dbl),batarg("m",dbl))),
5899 : command("batgeom", "MakePoint", batgeom_MakePoint_dbl_dbl_dbl_dbl, false, "", args(1,5, batarg("",wkb),batarg("x",dbl),batarg("y",dbl),batarg("z",dbl),batarg("m",dbl))),
5900 : command("batgeom", "NumPoints", batgeom_NumPoints_wkb, false, "", args(1,2, batarg("",int),batarg("w",wkb))),
5901 : command("batgeom", "NPoints", batgeom_NPoints_wkb, false, "", args(1,2, batarg("",int),batarg("w",wkb))),
5902 : command("batgeom", "X", batgeom_X_wkb, false, "", args(1,2, batarg("",dbl),batarg("w",wkb))),
5903 : command("batgeom", "Y", batgeom_Y_wkb, false, "", args(1,2, batarg("",dbl),batarg("w",wkb))),
5904 : command("batgeom", "Z", batgeom_Z_wkb, false, "", args(1,2, batarg("",dbl),batarg("w",wkb))),
5905 : command("batgeom", "NumInteriorRings", batgeom_NumInteriorRings_wkb, false, "", args(1,2, batarg("",int),batarg("w",wkb))),
5906 : command("batgeom", "NRings", batgeom_NRings_wkb, false, "", args(1,2, batarg("",int),batarg("w",wkb))),
5907 : command("batgeom", "XMinFromWKB", batgeom_XMinFromWKB_wkb, false, "", args(1,2, batarg("",dbl),batarg("g",wkb))),
5908 : command("batgeom", "YMinFromWKB", batgeom_YMinFromWKB_wkb, false, "", args(1,2, batarg("",dbl),batarg("g",wkb))),
5909 : command("batgeom", "XMaxFromWKB", batgeom_XMaxFromWKB_wkb, false, "", args(1,2, batarg("",dbl),batarg("g",wkb))),
5910 : command("batgeom", "YMaxFromWKB", batgeom_YMaxFromWKB_wkb, false, "", args(1,2, batarg("",dbl),batarg("g",wkb))),
5911 : command("batgeom", "XMinFromMBR", batgeom_XMinFromMBR_mbr, false, "", args(1,2, batarg("",dbl),batarg("b",mbr))),
5912 : command("batgeom", "YMinFromMBR", batgeom_YMinFromMBR_mbr, false, "", args(1,2, batarg("",dbl),batarg("b",mbr))),
5913 : command("batgeom", "XMaxFromMBR", batgeom_XMaxFromMBR_mbr, false, "", args(1,2, batarg("",dbl),batarg("b",mbr))),
5914 : command("batgeom", "YMaxFromMBR", batgeom_YMaxFromMBR_mbr, false, "", args(1,2, batarg("",dbl),batarg("b",mbr))),
5915 : { .imp=NULL }
5916 : };
5917 : #include "mal_import.h"
5918 : #ifdef _MSC_VER
5919 : #undef read
5920 : #pragma section(".CRT$XCU",read)
5921 : #endif
5922 340 : LIB_STARTUP_FUNC(init_geom_mal)
5923 340 : { mal_module2("geom", geom_init_atoms, geom_init_funcs, geom_prelude, NULL); }
|