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