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", 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 lenght 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", 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 transfered 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 0 : throw(MAL,"geom.Collect", "%s", 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 : 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 : 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 248 : 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 248 : geoCoordinatesNum = GEOSGeom_getCoordinateDimension_r(geoshandle, geosGeometry);
2276 : /* get the type of the geometry */
2277 248 : valueType = (GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1) << 2;
2278 :
2279 248 : if (geoCoordinatesNum > 2)
2280 94 : valueType += (1 << 1);
2281 94 : if (geoCoordinatesNum > 3)
2282 0 : valueType += 1;
2283 :
2284 248 : 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 135 : *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 76 : geoGetType(char **res, int *info, int *flag)
2330 : {
2331 76 : 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 76 : 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 329 : geom_prelude(void)
2345 : {
2346 329 : mbrNIL.xmin = flt_nil;
2347 329 : mbrNIL.xmax = flt_nil;
2348 329 : mbrNIL.ymin = flt_nil;
2349 329 : mbrNIL.ymax = flt_nil;
2350 329 : if (libgeom_init() != GDK_SUCCEED)
2351 0 : throw(MAL, "geom.prelude", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2352 329 : TYPE_mbr = malAtomSize(sizeof(mbr), "mbr");
2353 329 : return MAL_SUCCEED;
2354 : }
2355 :
2356 : static str
2357 328 : geom_epilogue(void *ret)
2358 : {
2359 328 : (void) ret;
2360 328 : 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 1112 : geos2wkb(const GEOSGeometry *geosGeometry)
2369 : {
2370 1112 : size_t wkbLen = 0;
2371 1112 : unsigned char *w = NULL;
2372 1112 : wkb *geomWKB;
2373 :
2374 : // if the geosGeometry is NULL create a NULL WKB
2375 1112 : if (geosGeometry == NULL) {
2376 0 : return wkbNULLcopy();
2377 : }
2378 :
2379 1112 : GEOS_setWKBOutputDims_r(geoshandle, GEOSGeom_getCoordinateDimension_r(geoshandle, geosGeometry));
2380 1119 : w = GEOSGeomToWKB_buf_r(geoshandle, geosGeometry, &wkbLen);
2381 :
2382 1114 : if (w == NULL)
2383 : return NULL;
2384 :
2385 1114 : assert(wkbLen <= GDK_int_max);
2386 :
2387 1114 : geomWKB = GDKmalloc(wkb_size(wkbLen));
2388 : //If malloc failed create a NULL wkb
2389 1123 : if (geomWKB == NULL) {
2390 0 : GEOSFree_r(geoshandle, w);
2391 0 : return NULL;
2392 : }
2393 :
2394 1123 : geomWKB->len = (int) wkbLen;
2395 1123 : geomWKB->srid = GEOSGetSRID_r(geoshandle, geosGeometry);
2396 1122 : memcpy(&geomWKB->data, w, wkbLen);
2397 1122 : GEOSFree_r(geoshandle, w);
2398 :
2399 1119 : return geomWKB;
2400 : }
2401 :
2402 : /* gets the mbr from the geometry */
2403 : mbr *
2404 667 : mbrFromGeos(const GEOSGeom geosGeometry)
2405 : {
2406 667 : GEOSGeom envelope;
2407 667 : mbr *geomMBR;
2408 667 : double xmin = 0, ymin = 0, xmax = 0, ymax = 0;
2409 :
2410 667 : geomMBR = GDKmalloc(sizeof(mbr));
2411 680 : 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 680 : if (!geosGeometry || (envelope = GEOSEnvelope_r(geoshandle, geosGeometry)) == NULL) {
2416 0 : *geomMBR = mbrNIL;
2417 0 : return geomMBR;
2418 : }
2419 :
2420 678 : if ((GEOSGeomTypeId_r(geoshandle, envelope) + 1) == wkbPoint_mdb) {
2421 : #if GEOS_CAPI_VERSION_MAJOR >= 1 && GEOS_CAPI_VERSION_MINOR >= 3
2422 412 : const GEOSCoordSequence *coords = GEOSGeom_getCoordSeq_r(geoshandle, envelope);
2423 : #else
2424 : const GEOSCoordSeq coords = GEOSGeom_getCoordSeq_r(geoshandle, envelope);
2425 : #endif
2426 417 : GEOSCoordSeq_getX_r(geoshandle, coords, 0, &xmin);
2427 413 : GEOSCoordSeq_getY_r(geoshandle, coords, 0, &ymin);
2428 415 : assert(GDK_flt_min <= xmin && xmin <= GDK_flt_max);
2429 415 : assert(GDK_flt_min <= ymin && ymin <= GDK_flt_max);
2430 415 : geomMBR->xmin = (float) xmin;
2431 415 : geomMBR->ymin = (float) ymin;
2432 415 : geomMBR->xmax = (float) xmin;
2433 415 : 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 252 : const GEOSGeometry *ring = GEOSGetExteriorRing_r(geoshandle, envelope);
2437 : #else
2438 : const GEOSGeom ring = GEOSGetExteriorRing_r(geoshandle, envelope);
2439 : #endif
2440 251 : if (ring) {
2441 : #if GEOS_CAPI_VERSION_MAJOR >= 1 && GEOS_CAPI_VERSION_MINOR >= 3
2442 251 : 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 256 : GEOSCoordSeq_getX_r(geoshandle, coords, 2, &xmax); //right-upper corner
2449 254 : GEOSCoordSeq_getY_r(geoshandle, coords, 2, &ymax);
2450 252 : assert(GDK_flt_min <= xmin && xmin <= GDK_flt_max);
2451 252 : assert(GDK_flt_min <= ymin && ymin <= GDK_flt_max);
2452 252 : assert(GDK_flt_min <= xmax && xmax <= GDK_flt_max);
2453 252 : assert(GDK_flt_min <= ymax && ymax <= GDK_flt_max);
2454 252 : geomMBR->xmin = (float) xmin;
2455 252 : geomMBR->ymin = (float) ymin;
2456 252 : geomMBR->xmax = (float) xmax;
2457 252 : geomMBR->ymax = (float) ymax;
2458 : }
2459 : }
2460 667 : GEOSGeom_destroy_r(geoshandle, envelope);
2461 659 : 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 1028 : wkbFromText(wkb **geomWKB, str *geomWKT, int *srid, int *tpe)
2614 : {
2615 1028 : size_t len = 0;
2616 1028 : int te = 0;
2617 1028 : str err;
2618 1028 : size_t parsedBytes;
2619 :
2620 1028 : *geomWKB = NULL;
2621 2056 : 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 1029 : err = wkbFROMSTR_withSRID(*geomWKT, &len, geomWKB, *srid, &parsedBytes);
2627 1023 : if (err != MAL_SUCCEED)
2628 : return err;
2629 :
2630 969 : 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 56 : 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 68 : if (seq == NULL)
2907 0 : throw(MAL, "geom.MakePoint", SQLSTATE(38000) "Geos operation GEOSCoordSeq_create failed");
2908 :
2909 136 : if (!GEOSCoordSeq_setOrdinate_r(geoshandle, seq, 0, 0, *x) ||
2910 68 : !GEOSCoordSeq_setOrdinate_r(geoshandle, seq, 0, 1, *y) ||
2911 68 : (*zmFlag == 1 && !GEOSCoordSeq_setOrdinate_r(geoshandle, seq, 0, 2, *m)) ||
2912 68 : (*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 68 : if ((geosGeometry = GEOSGeom_createPoint_r(geoshandle, seq)) == NULL) {
2918 0 : GEOSCoordSeq_destroy_r(geoshandle, seq);
2919 0 : throw(MAL, "geom.MakePoint", SQLSTATE(38000) "Geos opertion GEOSGeometry failed");
2920 : }
2921 :
2922 67 : *out = geos2wkb(geosGeometry);
2923 68 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
2924 :
2925 68 : 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 162 : wkbBasicInt(int *out, wkb *geom, int (*func) (GEOSContextHandle_t handle, const GEOSGeometry *), const char *name)
2937 : {
2938 162 : GEOSGeom geosGeometry;
2939 162 : str ret = MAL_SUCCEED;
2940 :
2941 162 : if (is_wkb_nil(geom)) {
2942 0 : *out = int_nil;
2943 0 : return MAL_SUCCEED;
2944 : }
2945 :
2946 163 : 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 162 : 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 32 : 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 0 : freeException(msg);
3458 0 : throw(MAL, "aggr.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3459 : }
3460 : return MAL_SUCCEED;
3461 : }
3462 2 : bWKB = inWKB_array[1];
3463 : //create the first line using the first two geometries
3464 2 : outCoordSeq = GEOSCoordSeq_create_r(geoshandle, size, 2);
3465 :
3466 2 : msg = wkbExtractPointToCoordSeq(&outCoordSeq, aWKB, 0);
3467 2 : msg = wkbExtractPointToCoordSeq(&outCoordSeq, bWKB, 1);
3468 :
3469 : // add one more segment for each following row
3470 4 : for (i = 2; msg == MAL_SUCCEED && i < size; i++) {
3471 0 : msg = wkbExtractPointToCoordSeq(&outCoordSeq, inWKB_array[i], i);
3472 : }
3473 2 : if ((outGeometry = GEOSGeom_createLineString_r(geoshandle, outCoordSeq)) == NULL) {
3474 0 : msg = createException(MAL, "geom.MakeLine", SQLSTATE(38000) "Geos operation GEOSGeom_createLineString failed");
3475 : }
3476 2 : *outWKB = geos2wkb(outGeometry);
3477 2 : GEOSGeom_destroy_r(geoshandle, outGeometry);
3478 : /* no need to clean outCoordSeq. it is destroyed via outGeometry */
3479 2 : return msg;
3480 : }
3481 :
3482 : //TODO Check SRID
3483 : //TODO Check if the input geometries are points
3484 : str
3485 1 : wkbMakeLineAggrSubGroupedCand(bat *outid, const bat *bid, const bat *gid, const bat *eid, const bat *sid, const bit *skip_nils)
3486 : {
3487 1 : BAT *b = NULL, *g = NULL, *s = NULL, *out = NULL;
3488 1 : BAT *sortedgroups, *sortedorder;
3489 1 : BATiter bi;
3490 1 : const oid *gids = NULL;
3491 1 : str msg = MAL_SUCCEED;
3492 :
3493 1 : oid min, max;
3494 1 : BUN ngrp;
3495 1 : struct canditer ci;
3496 :
3497 1 : oid lastGrp = -1;
3498 1 : wkb **lines = NULL, **lineGroup = NULL;
3499 1 : int position = 0;
3500 :
3501 : //Not using these variables
3502 1 : (void) skip_nils;
3503 1 : (void) eid;
3504 :
3505 : //Get the BAT descriptors for the value, group and candidate bats
3506 1 : if ((b = BATdescriptor(*bid)) == NULL ||
3507 1 : (gid && !is_bat_nil(*gid) && (g = BATdescriptor(*gid)) == NULL) ||
3508 0 : (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL)) {
3509 0 : msg = createException(MAL, "aggr.MakeLine", RUNTIME_OBJECT_MISSING);
3510 0 : goto free;
3511 : }
3512 :
3513 1 : if ((BATsort(&sortedgroups, &sortedorder, NULL, g, NULL, NULL, false, false, true)) != GDK_SUCCEED) {
3514 0 : msg = createException(MAL, "aggr.MakeLine", "BAT sort failed.");
3515 0 : goto free;
3516 : }
3517 :
3518 : //Project new order onto input bat IF the sortedorder isn't dense (in which case, the original input order is correct)
3519 1 : if (!BATtdense(sortedorder)) {
3520 1 : BAT *sortedinput = BATproject(sortedorder, b);
3521 1 : BBPreclaim(sortedorder);
3522 1 : if (sortedinput == NULL) {
3523 0 : BBPreclaim(sortedgroups);
3524 0 : msg = createException(MAL, "aggr.MakeLine", GDK_EXCEPTION);
3525 0 : goto free;
3526 : }
3527 1 : BBPunfix(b->batCacheid);
3528 1 : BBPunfix(g->batCacheid);
3529 1 : b = sortedinput;
3530 1 : g = sortedgroups;
3531 : }
3532 : else {
3533 0 : BBPunfix(sortedgroups->batCacheid);
3534 0 : BBPunfix(sortedorder->batCacheid);
3535 : }
3536 :
3537 : //Fill in the values of the group aggregate operation
3538 1 : if ((msg = (str) BATgroupaggrinit(b, g, NULL, s, &min, &max, &ngrp, &ci)) != NULL) {
3539 0 : msg = createException(MAL, "aggr.MakeLine", "%s", msg);
3540 0 : goto free;
3541 : }
3542 :
3543 : //Create a new BAT column of wkb type, with lenght equal to the number of groups
3544 1 : if ((out = COLnew(min, ATOMindex("wkb"), ngrp, TRANSIENT)) == NULL) {
3545 0 : msg = createException(MAL, "aggr.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3546 0 : goto free;
3547 : }
3548 :
3549 : //Create an array of WKB to hold the results of the MakeLine
3550 1 : if ((lines = GDKzalloc(sizeof(wkb *) * ngrp)) == NULL) {
3551 0 : msg = createException(MAL, "aggr.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3552 0 : BBPreclaim(out);
3553 0 : goto free;
3554 : }
3555 :
3556 : //Create an array of WKB to hold the points to be made into a line (for one group at a time)
3557 1 : if ((lineGroup = GDKzalloc(sizeof(wkb*) * ci.ncand)) == NULL) {
3558 0 : msg = createException(MAL, "aggr.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3559 0 : BBPreclaim(out);
3560 0 : goto free;
3561 : }
3562 :
3563 1 : if (g && !BATtdense(g))
3564 1 : gids = (const oid *)Tloc(g, 0);
3565 1 : bi = bat_iterator(b);
3566 :
3567 6 : for (BUN i = 0; i < ci.ncand; i++) {
3568 5 : oid o = canditer_next(&ci);
3569 5 : BUN p = o - b->hseqbase;
3570 5 : oid grp = gids ? gids[p] : g ? min + (oid)p : 0;
3571 5 : wkb *inWKB = (wkb *)BUNtvar(bi, p);
3572 :
3573 5 : if (grp != lastGrp) {
3574 3 : if (lastGrp != (oid)-1) {
3575 2 : msg = wkbMakeLineAggrArray(&lines[lastGrp], lineGroup, position);
3576 2 : position = 0;
3577 2 : if (msg != MAL_SUCCEED) {
3578 0 : GDKfree(lineGroup);
3579 0 : goto free;
3580 : }
3581 : }
3582 : lastGrp = grp;
3583 : }
3584 5 : lineGroup[position++] = inWKB;
3585 : }
3586 1 : msg = wkbMakeLineAggrArray(&lines[lastGrp], lineGroup, position);
3587 1 : GDKfree(lineGroup);
3588 1 : if (msg != MAL_SUCCEED)
3589 0 : goto free;
3590 :
3591 1 : if (BUNappendmulti(out, lines, ngrp, false) != GDK_SUCCEED) {
3592 0 : msg = createException(MAL, "geom.Union", SQLSTATE(38000) "BUNappend operation failed");
3593 0 : for (BUN i = 0; i < ngrp; i++)
3594 0 : GDKfree(lines[i]);
3595 0 : GDKfree(lines);
3596 0 : bat_iterator_end(&bi);
3597 0 : goto free;
3598 : }
3599 :
3600 4 : for (BUN i = 0; i < ngrp; i++)
3601 3 : GDKfree(lines[i]);
3602 1 : GDKfree(lines);
3603 1 : bat_iterator_end(&bi);
3604 :
3605 1 : *outid = out->batCacheid;
3606 1 : BBPkeepref(out);
3607 1 : BBPunfix(b->batCacheid);
3608 1 : if (g)
3609 1 : BBPunfix(g->batCacheid);
3610 1 : if (s)
3611 0 : BBPunfix(s->batCacheid);
3612 : return MAL_SUCCEED;
3613 0 : free:
3614 0 : if (b)
3615 0 : BBPunfix(b->batCacheid);
3616 0 : if (g)
3617 0 : BBPunfix(g->batCacheid);
3618 0 : if (s)
3619 0 : BBPunfix(s->batCacheid);
3620 0 : BBPreclaim(out);
3621 : return msg;
3622 : }
3623 :
3624 : str
3625 1 : wkbMakeLineAggrSubGrouped (bat *out, const bat *bid, const bat *gid, const bat *eid, const bit *skip_nils) {
3626 1 : return wkbMakeLineAggrSubGroupedCand(out,bid,gid,eid,NULL,skip_nils);
3627 : }
3628 :
3629 : /* Returns the first or last point of a linestring */
3630 : static str
3631 2 : wkbBorderPoint(wkb **out, wkb **geom, GEOSGeometry *(*func) (GEOSContextHandle_t handle, const GEOSGeometry *), const char *name)
3632 : {
3633 2 : GEOSGeom geosGeometry;
3634 2 : GEOSGeom new;
3635 2 : str err = MAL_SUCCEED;
3636 :
3637 2 : if (is_wkb_nil(*geom)) {
3638 0 : if ((*out = wkbNULLcopy()) == NULL)
3639 0 : throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
3640 : return MAL_SUCCEED;
3641 : }
3642 :
3643 2 : *out = NULL;
3644 2 : geosGeometry = wkb2geos(*geom);
3645 2 : if (geosGeometry == NULL) {
3646 0 : throw(MAL, name, SQLSTATE(38000) "Geos operation wkb2geos failed");
3647 : }
3648 :
3649 2 : if (GEOSGeomTypeId_r(geoshandle, geosGeometry) != GEOS_LINESTRING) {
3650 0 : err = createException(MAL, name, SQLSTATE(38000) "Geometry not a LineString");
3651 : } else {
3652 2 : new = (*func) (geoshandle, geosGeometry);
3653 2 : if (new == NULL) {
3654 0 : err = createException(MAL, name, SQLSTATE(38000) "Geos operation GEOSGeomGet%s failed", name + 5);
3655 : } else {
3656 2 : *out = geos2wkb(new);
3657 2 : GEOSGeom_destroy_r(geoshandle, new);
3658 : }
3659 : }
3660 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3661 :
3662 2 : return err;
3663 : }
3664 :
3665 : /* Returns the first point in a linestring */
3666 : str
3667 1 : wkbStartPoint(wkb **out, wkb **geom)
3668 : {
3669 1 : return wkbBorderPoint(out, geom, GEOSGeomGetStartPoint_r, "geom.StartPoint");
3670 : }
3671 :
3672 : /* Returns the last point in a linestring */
3673 : str
3674 1 : wkbEndPoint(wkb **out, wkb **geom)
3675 : {
3676 1 : return wkbBorderPoint(out, geom, GEOSGeomGetEndPoint_r, "geom.EndPoint");
3677 : }
3678 :
3679 : static str
3680 58 : numPointsLineString(unsigned int *out, const GEOSGeometry *geosGeometry)
3681 : {
3682 : /* get the coordinates of the points comprising the geometry */
3683 58 : const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r(geoshandle, geosGeometry);
3684 :
3685 58 : if (coordSeq == NULL)
3686 0 : throw(MAL, "geom.NumPoints", SQLSTATE(38000) "Geos operation GEOSGeom_getCoordSeq failed");
3687 :
3688 : /* get the number of points in the geometry */
3689 58 : if (!GEOSCoordSeq_getSize_r(geoshandle, coordSeq, out)) {
3690 0 : *out = int_nil;
3691 0 : throw(MAL, "geom.NumPoints", SQLSTATE(38000) "Geos operation GEOSGeomGetNumPoints failed");
3692 : }
3693 :
3694 : return MAL_SUCCEED;
3695 : }
3696 :
3697 : static str
3698 11 : numPointsPolygon(unsigned int *out, const GEOSGeometry *geosGeometry)
3699 : {
3700 11 : const GEOSGeometry *exteriorRingGeometry;
3701 11 : int numInteriorRings = 0, i = 0;
3702 11 : str err;
3703 11 : unsigned int pointsN = 0;
3704 :
3705 : /* get the exterior ring of the polygon */
3706 11 : exteriorRingGeometry = GEOSGetExteriorRing_r(geoshandle, geosGeometry);
3707 11 : if (!exteriorRingGeometry) {
3708 0 : *out = int_nil;
3709 0 : throw(MAL, "geom.NumPoints", SQLSTATE(38000) "Geos operation GEOSGetExteriorRing failed");
3710 : }
3711 : //get the points in the exterior ring
3712 11 : if ((err = numPointsLineString(out, exteriorRingGeometry)) != MAL_SUCCEED) {
3713 0 : *out = int_nil;
3714 0 : return err;
3715 : }
3716 11 : pointsN = *out;
3717 :
3718 : //check the interior rings
3719 11 : numInteriorRings = GEOSGetNumInteriorRings_r(geoshandle, geosGeometry);
3720 11 : if (numInteriorRings == -1) {
3721 0 : *out = int_nil;
3722 0 : throw(MAL, "geom.NumPoints", SQLSTATE(38000) "Geos operation GEOSGetNumInteriorRings failed");
3723 : }
3724 : // iterate over the interiorRing and transform each one of them
3725 16 : for (i = 0; i < numInteriorRings; i++) {
3726 5 : if ((err = numPointsLineString(out, GEOSGetInteriorRingN_r(geoshandle, geosGeometry, i))) != MAL_SUCCEED) {
3727 0 : *out = int_nil;
3728 0 : return err;
3729 : }
3730 5 : pointsN += *out;
3731 : }
3732 :
3733 11 : *out = pointsN;
3734 11 : return MAL_SUCCEED;
3735 : }
3736 :
3737 : static str numPointsGeometry(unsigned int *out, const GEOSGeometry *geosGeometry);
3738 : static str
3739 9 : numPointsMultiGeometry(unsigned int *out, const GEOSGeometry *geosGeometry)
3740 : {
3741 9 : int geometriesNum, i;
3742 9 : const GEOSGeometry *multiGeometry = NULL;
3743 9 : str err;
3744 9 : unsigned int pointsN = 0;
3745 :
3746 9 : geometriesNum = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
3747 :
3748 40 : for (i = 0; i < geometriesNum; i++) {
3749 22 : multiGeometry = GEOSGetGeometryN_r(geoshandle, geosGeometry, i);
3750 22 : if ((err = numPointsGeometry(out, multiGeometry)) != MAL_SUCCEED) {
3751 0 : *out = int_nil;
3752 0 : return err;
3753 : }
3754 22 : pointsN += *out;
3755 : }
3756 :
3757 9 : *out = pointsN;
3758 9 : return MAL_SUCCEED;
3759 : }
3760 :
3761 : static str
3762 62 : numPointsGeometry(unsigned int *out, const GEOSGeometry *geosGeometry)
3763 : {
3764 62 : int geometryType = GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1;
3765 :
3766 : //check the type of the geometry
3767 62 : switch (geometryType) {
3768 42 : case wkbPoint_mdb:
3769 : case wkbLineString_mdb:
3770 : case wkbLinearRing_mdb:
3771 42 : return numPointsLineString(out, geosGeometry);
3772 11 : case wkbPolygon_mdb:
3773 11 : return numPointsPolygon(out, geosGeometry);
3774 9 : case wkbMultiPoint_mdb:
3775 : case wkbMultiLineString_mdb:
3776 : case wkbMultiPolygon_mdb:
3777 : case wkbGeometryCollection_mdb:
3778 9 : return numPointsMultiGeometry(out, geosGeometry);
3779 0 : default:
3780 0 : throw(MAL, "geom.NumPoints", SQLSTATE(38000) "Geos geometry type %s unknown", geom_type2str(geometryType, 0));
3781 : }
3782 : }
3783 :
3784 : /* Returns the number of points in a geometry */
3785 : str
3786 42 : wkbNumPoints(int *out, wkb **geom, int *check)
3787 : {
3788 42 : GEOSGeom geosGeometry;
3789 42 : int geometryType = 0;
3790 42 : str err = MAL_SUCCEED;
3791 42 : char *geomSTR = NULL;
3792 42 : unsigned int pointsNum;
3793 :
3794 42 : if (is_wkb_nil(*geom) || is_int_nil(*check)) {
3795 0 : *out = int_nil;
3796 0 : return MAL_SUCCEED;
3797 : }
3798 :
3799 42 : geosGeometry = wkb2geos(*geom);
3800 42 : if (geosGeometry == NULL) {
3801 0 : *out = int_nil;
3802 0 : throw(MAL, "geom.NumPoints", SQLSTATE(38000) "Geos operation wkb2geos failed");
3803 : }
3804 :
3805 42 : geometryType = GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1;
3806 :
3807 42 : if (*check && geometryType != wkbLineString_mdb) {
3808 2 : *out = int_nil;
3809 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3810 :
3811 2 : if ((err = wkbAsText(&geomSTR, geom, NULL)) == MAL_SUCCEED) {
3812 2 : err = createException(MAL, "geom.NumPoints", SQLSTATE(38000) "Geometry \"%s\" not a LineString", geomSTR);
3813 2 : GDKfree(geomSTR);
3814 : }
3815 2 : return err;
3816 : }
3817 :
3818 40 : if ((err = numPointsGeometry(&pointsNum, geosGeometry)) != MAL_SUCCEED) {
3819 0 : *out = int_nil;
3820 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3821 0 : return err;
3822 : }
3823 :
3824 40 : if (pointsNum > INT_MAX) {
3825 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3826 0 : *out = int_nil;
3827 0 : throw(MAL, "geom.NumPoints", SQLSTATE(38000) "Geos operation Overflow");
3828 : }
3829 :
3830 40 : *out = pointsNum;
3831 40 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3832 :
3833 40 : return MAL_SUCCEED;
3834 : }
3835 :
3836 : /* Returns the n-th point of the geometry */
3837 : str
3838 1 : wkbPointN(wkb **out, wkb **geom, int *n)
3839 : {
3840 1 : int rN = -1;
3841 1 : GEOSGeom geosGeometry;
3842 1 : GEOSGeom new;
3843 1 : str err = MAL_SUCCEED;
3844 :
3845 1 : if (is_wkb_nil(*geom) || is_int_nil(*n)) {
3846 0 : if ((*out = wkbNULLcopy()) == NULL)
3847 0 : throw(MAL, "geom.PointN", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3848 : return MAL_SUCCEED;
3849 : }
3850 :
3851 1 : geosGeometry = wkb2geos(*geom);
3852 1 : if (geosGeometry == NULL) {
3853 0 : *out = NULL;
3854 0 : throw(MAL, "geom.PointN", SQLSTATE(38000) "Geos operation wkb2geos failed");
3855 : }
3856 :
3857 1 : if (GEOSGeomTypeId_r(geoshandle, geosGeometry) != GEOS_LINESTRING) {
3858 0 : *out = NULL;
3859 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3860 0 : throw(MAL, "geom.PointN", SQLSTATE(38000) "Geometry not a LineString");
3861 : }
3862 : //check number of points
3863 1 : rN = GEOSGeomGetNumPoints_r(geoshandle, geosGeometry);
3864 1 : if (rN == -1) {
3865 0 : *out = NULL;
3866 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3867 0 : throw(MAL, "geom.PointN", SQLSTATE(38000) "Geos operation GEOSGeomGetNumPoints failed");
3868 : }
3869 :
3870 1 : if (rN <= *n || *n < 0) {
3871 0 : *out = NULL;
3872 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3873 0 : throw(MAL, "geom.PointN", SQLSTATE(38000) "Geos unable to retrieve point %d (not enough points)", *n);
3874 : }
3875 :
3876 1 : if ((new = GEOSGeomGetPointN_r(geoshandle, geosGeometry, *n)) == NULL) {
3877 0 : err = createException(MAL, "geom.PointN", SQLSTATE(38000) "Geos operation GEOSGeomGetPointN failed");
3878 : } else {
3879 1 : if ((*out = geos2wkb(new)) == NULL)
3880 0 : err = createException(MAL, "geom.PointN", SQLSTATE(38000) "Geos operation GEOSGeomGetPointN failed");
3881 1 : GEOSGeom_destroy_r(geoshandle, new);
3882 : }
3883 1 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3884 :
3885 1 : return err;
3886 : }
3887 :
3888 : /* Returns the exterior ring of the polygon*/
3889 : str
3890 2 : wkbExteriorRing(wkb **exteriorRingWKB, wkb **geom)
3891 : {
3892 2 : GEOSGeom geosGeometry;
3893 2 : const GEOSGeometry *exteriorRingGeometry;
3894 2 : str err = MAL_SUCCEED;
3895 :
3896 2 : if (is_wkb_nil(*geom)) {
3897 0 : if ((*exteriorRingWKB = wkbNULLcopy()) == NULL)
3898 0 : throw(MAL, "geom.ExteriorRing", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3899 : return MAL_SUCCEED;
3900 : }
3901 :
3902 2 : geosGeometry = wkb2geos(*geom);
3903 2 : if (geosGeometry == NULL) {
3904 0 : *exteriorRingWKB = NULL;
3905 0 : throw(MAL, "geom.ExteriorRing", SQLSTATE(38000) "Geos operation wkb2geos failed");
3906 : }
3907 :
3908 2 : if (GEOSGeomTypeId_r(geoshandle, geosGeometry) != GEOS_POLYGON) {
3909 0 : *exteriorRingWKB = NULL;
3910 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3911 0 : throw(MAL, "geom.ExteriorRing", SQLSTATE(38000) "Geometry not a Polygon");
3912 :
3913 : }
3914 : /* get the exterior ring of the geometry */
3915 2 : if ((exteriorRingGeometry = GEOSGetExteriorRing_r(geoshandle, geosGeometry)) == NULL)
3916 0 : err = createException(MAL, "geom.ExteriorRing", SQLSTATE(38000) "Geos operation GEOSGetExteriorRing failed");
3917 : else {
3918 : /* get the wkb representation of it */
3919 2 : if ((*exteriorRingWKB = geos2wkb(exteriorRingGeometry)) == NULL)
3920 0 : err = createException(MAL, "geom.ExteriorRing", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3921 : }
3922 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3923 :
3924 2 : return err;
3925 : }
3926 :
3927 : /* Returns the n-th interior ring of a polygon */
3928 : str
3929 1 : wkbInteriorRingN(wkb **interiorRingWKB, wkb **geom, int *ringNum)
3930 : {
3931 1 : GEOSGeom geosGeometry = NULL;
3932 1 : const GEOSGeometry *interiorRingGeometry;
3933 1 : int rN = -1;
3934 1 : str err = MAL_SUCCEED;
3935 :
3936 : //initialize to NULL
3937 1 : *interiorRingWKB = NULL;
3938 :
3939 1 : if (is_wkb_nil(*geom) || is_int_nil(*ringNum)) {
3940 0 : if ((*interiorRingWKB = wkbNULLcopy()) == NULL)
3941 0 : throw(MAL, "geom.InteriorRingN", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3942 : return MAL_SUCCEED;
3943 : }
3944 :
3945 1 : geosGeometry = wkb2geos(*geom);
3946 1 : if (geosGeometry == NULL) {
3947 0 : *interiorRingWKB = NULL;
3948 0 : throw(MAL, "geom.InteriorRingN", SQLSTATE(38000) "Geos operation wkb2geos failed");
3949 : }
3950 :
3951 1 : if ((GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1) != wkbPolygon_mdb) {
3952 0 : *interiorRingWKB = NULL;
3953 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3954 0 : throw(MAL, "geom.InteriorRingN", SQLSTATE(38000) "Geometry not a Polygon");
3955 :
3956 : }
3957 : //check number of internal rings
3958 1 : rN = GEOSGetNumInteriorRings_r(geoshandle, geosGeometry);
3959 1 : if (rN == -1) {
3960 0 : *interiorRingWKB = NULL;
3961 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3962 0 : throw(MAL, "geom.InteriorRingN", SQLSTATE(38000) "Geos operation GEOSGetInteriorRingN failed.");
3963 : }
3964 :
3965 1 : if (rN < *ringNum || *ringNum <= 0) {
3966 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3967 : //NOT AN ERROR throw(MAL, "geom.interiorRingN", SQLSTATE(38000) "Geos operation GEOSGetInteriorRingN failed. Not enough interior rings");
3968 0 : if ((*interiorRingWKB = wkbNULLcopy()) == NULL)
3969 0 : throw(MAL, "geom.InteriorRingN", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3970 : return MAL_SUCCEED;
3971 : }
3972 :
3973 : /* get the interior ring of the geometry */
3974 1 : if ((interiorRingGeometry = GEOSGetInteriorRingN_r(geoshandle, geosGeometry, *ringNum - 1)) == NULL) {
3975 0 : err = createException(MAL, "geom.InteriorRingN", SQLSTATE(38000) "Geos operation GEOSGetInteriorRingN failed");
3976 : } else {
3977 : /* get the wkb representation of it */
3978 1 : if ((*interiorRingWKB = geos2wkb(interiorRingGeometry)) == NULL)
3979 0 : err = createException(MAL, "geom.InteriorRingN", SQLSTATE(HY013) MAL_MALLOC_FAIL);
3980 : }
3981 1 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
3982 :
3983 1 : return err;
3984 : }
3985 :
3986 : /* Returns the number of interior rings in the first polygon of the provided geometry
3987 : * plus the exterior ring depending on the value of exteriorRing*/
3988 : str
3989 27 : wkbNumRings(int *out, wkb **geom, int *exteriorRing)
3990 : {
3991 27 : str ret = MAL_SUCCEED;
3992 27 : bit empty;
3993 27 : GEOSGeom geosGeometry;
3994 :
3995 27 : if (is_wkb_nil(*geom) || is_int_nil(*exteriorRing)) {
3996 0 : *out = int_nil;
3997 0 : return MAL_SUCCEED;
3998 : }
3999 :
4000 : //check if the geometry is empty
4001 27 : if ((ret = wkbIsEmpty(&empty, geom)) != MAL_SUCCEED) {
4002 : return ret;
4003 : }
4004 26 : if (empty) {
4005 : //the geometry is empty
4006 0 : *out = 0;
4007 0 : return MAL_SUCCEED;
4008 : }
4009 : //check the type of the geometry
4010 26 : geosGeometry = wkb2geos(*geom);
4011 :
4012 27 : if (geosGeometry == NULL)
4013 0 : throw(MAL, "geom.NumRings", SQLSTATE(38000) "Geos problem converting WKB to GEOS");
4014 :
4015 27 : if (GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1 == wkbMultiPolygon_mdb) {
4016 : //use the first polygon as done by PostGIS
4017 8 : wkb *new = geos2wkb(GEOSGetGeometryN_r(geoshandle, geosGeometry, 0));
4018 8 : if (new == NULL) {
4019 0 : ret = createException(MAL, "geom.NumRings", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4020 : } else {
4021 8 : ret = wkbBasicInt(out, new, GEOSGetNumInteriorRings_r, "geom.NumRings");
4022 8 : GDKfree(new);
4023 : }
4024 18 : } else if (GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1 == wkbPolygon_mdb) {
4025 9 : ret = wkbBasicInt(out, *geom, GEOSGetNumInteriorRings_r, "geom.NumRings");
4026 : } else {
4027 : //It is not a polygon so the number of rings is 0
4028 10 : *out = -*exteriorRing; /* compensate for += later */
4029 : }
4030 :
4031 27 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4032 :
4033 27 : if (ret != MAL_SUCCEED)
4034 : return ret;
4035 :
4036 27 : *out += *exteriorRing;
4037 :
4038 27 : return MAL_SUCCEED;
4039 : }
4040 :
4041 : /* it handles functions that take as input a single geometry and return Boolean */
4042 : static str
4043 802 : wkbBasicBoolean(bit *out, wkb **geom, char (*func) (GEOSContextHandle_t handle, const GEOSGeometry *), const char *name)
4044 : {
4045 802 : int ret;
4046 802 : GEOSGeom geosGeometry;
4047 :
4048 802 : if (is_wkb_nil(*geom)) {
4049 0 : *out = bit_nil;
4050 0 : return MAL_SUCCEED;
4051 : }
4052 :
4053 798 : geosGeometry = wkb2geos(*geom);
4054 803 : if (geosGeometry == NULL)
4055 0 : throw(MAL, name, SQLSTATE(38000) "Geos operation wkb2geom failed");
4056 :
4057 803 : ret = (*func) (geoshandle, geosGeometry); //it is supposed to return char but treating it as such gives wrong results
4058 798 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4059 :
4060 809 : if (ret == 2) {
4061 0 : GDKclrerr();
4062 0 : ret = 0;
4063 : }
4064 :
4065 809 : *out = ret;
4066 :
4067 809 : return MAL_SUCCEED;
4068 : }
4069 :
4070 : /* the function checks whether the geometry is closed. GEOS works only with
4071 : * linestring geometries but PostGIS returns true in any geometry that is not
4072 : * a linestring. I made it to be like PostGIS */
4073 : static str
4074 36 : geosIsClosed(bit *out, const GEOSGeometry *geosGeometry)
4075 : {
4076 36 : int geometryType = GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1;
4077 36 : int i = 0;
4078 36 : str err;
4079 36 : int geometriesNum;
4080 :
4081 36 : *out = bit_nil;
4082 :
4083 36 : switch (geometryType) {
4084 0 : case -1:
4085 0 : throw(MAL, "geom.IsClosed", SQLSTATE(38000) "Geos operation GEOSGeomTypeId failed");
4086 11 : case wkbPoint_mdb:
4087 : case wkbPolygon_mdb:
4088 : case wkbMultiPoint_mdb:
4089 : case wkbMultiPolygon_mdb:
4090 : //In all these case it is always true
4091 11 : *out = 1;
4092 11 : break;
4093 18 : case wkbLineString_mdb:
4094 : //check
4095 18 : if ((i = GEOSisClosed_r(geoshandle, geosGeometry)) == 2)
4096 0 : throw(MAL, "geom.IsClosed", SQLSTATE(38000) "Geos operation GEOSisClosed failed");
4097 18 : *out = i;
4098 18 : break;
4099 7 : case wkbMultiLineString_mdb:
4100 : case wkbGeometryCollection_mdb:
4101 : //check each one separately
4102 7 : geometriesNum = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
4103 7 : if (geometriesNum < 0)
4104 0 : throw(MAL, "geom.IsClosed", SQLSTATE(38000) "Geos operation GEOSGetNumGeometries failed");
4105 :
4106 15 : for (i = 0; i < geometriesNum; i++) {
4107 13 : const GEOSGeometry *gN = GEOSGetGeometryN_r(geoshandle, geosGeometry, i);
4108 13 : if (!gN)
4109 0 : throw(MAL, "geom.IsClosed", SQLSTATE(38000) "Geos operation GEOSGetGeometryN failed");
4110 :
4111 13 : if ((err = geosIsClosed(out, gN)) != MAL_SUCCEED) {
4112 0 : return err;
4113 : }
4114 :
4115 13 : if (!*out) //no reason to check further logical AND will always be 0
4116 : return MAL_SUCCEED;
4117 : }
4118 :
4119 : break;
4120 0 : default:
4121 0 : throw(MAL, "geom.IsClosed", SQLSTATE(38000) "Geos geometry type unknown");
4122 : }
4123 :
4124 : return MAL_SUCCEED;
4125 : }
4126 :
4127 : str
4128 24 : wkbIsClosed(bit *out, wkb **geomWKB)
4129 : {
4130 24 : str err;
4131 24 : GEOSGeom geosGeometry;
4132 :
4133 24 : if (is_wkb_nil(*geomWKB)) {
4134 0 : *out = bit_nil;
4135 0 : return MAL_SUCCEED;
4136 : }
4137 :
4138 : //if empty geometry return false
4139 24 : if ((err = wkbIsEmpty(out, geomWKB)) != MAL_SUCCEED) {
4140 : return err;
4141 : }
4142 24 : if (*out) {
4143 1 : *out = 0;
4144 1 : return MAL_SUCCEED;
4145 : }
4146 :
4147 23 : geosGeometry = wkb2geos(*geomWKB);
4148 23 : if (geosGeometry == NULL)
4149 0 : throw(MAL, "geom.IsClosed", SQLSTATE(38000) "Geos operation wkb2geos failed");
4150 :
4151 23 : err = geosIsClosed(out, geosGeometry);
4152 23 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4153 :
4154 23 : return err;
4155 : }
4156 :
4157 : str
4158 755 : wkbIsEmpty(bit *out, wkb **geomWKB)
4159 : {
4160 755 : return wkbBasicBoolean(out, geomWKB, GEOSisEmpty_r, "geom.IsEmpty");
4161 : }
4162 :
4163 : str
4164 16 : wkbIsRing(bit *out, wkb **geomWKB)
4165 : {
4166 16 : return wkbBasicBoolean(out, geomWKB, GEOSisRing_r, "geom.IsRing");
4167 : }
4168 :
4169 : str
4170 15 : wkbIsSimple(bit *out, wkb **geomWKB)
4171 : {
4172 15 : return wkbBasicBoolean(out, geomWKB, GEOSisSimple_r, "geom.IsSimple");
4173 : }
4174 :
4175 : /*geom prints a message saying the reason why the geometry is not valid but
4176 : * since there is also isValidReason I skip this here */
4177 : str
4178 18 : wkbIsValid(bit *out, wkb **geomWKB)
4179 : {
4180 18 : str err = wkbBasicBoolean(out, geomWKB, GEOSisValid_r, "geom.IsValid");
4181 : /* GOESisValid may cause GDKerror to be called: ignore it */
4182 18 : if (err == MAL_SUCCEED)
4183 18 : GDKclrerr();
4184 18 : return err;
4185 : }
4186 :
4187 : str
4188 0 : wkbIsValidReason(char **reason, wkb **geomWKB)
4189 : {
4190 0 : GEOSGeom geosGeometry;
4191 0 : char *GEOSReason = NULL;
4192 :
4193 0 : if (is_wkb_nil(*geomWKB)) {
4194 0 : if ((*reason = GDKstrdup(str_nil)) == NULL)
4195 0 : throw(MAL, "geom.IsValidReason", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4196 : return MAL_SUCCEED;
4197 : }
4198 :
4199 0 : geosGeometry = wkb2geos(*geomWKB);
4200 0 : if (geosGeometry == NULL)
4201 0 : throw(MAL, "geom.IsValidReason", SQLSTATE(38000) "Geos operation wkb2geom failed");
4202 :
4203 0 : GEOSReason = GEOSisValidReason_r(geoshandle, geosGeometry);
4204 :
4205 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4206 :
4207 0 : if (GEOSReason == NULL)
4208 0 : throw(MAL, "geom.IsValidReason", SQLSTATE(38000) "Geos operation GEOSisValidReason failed");
4209 :
4210 0 : *reason = GDKstrdup(GEOSReason);
4211 0 : GEOSFree_r(geoshandle, GEOSReason);
4212 0 : if (*reason == NULL)
4213 0 : throw(MAL, "geom.IsValidReason", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4214 :
4215 : return MAL_SUCCEED;
4216 : }
4217 :
4218 : /* I should check it since it does not work */
4219 : str
4220 0 : wkbIsValidDetail(char **out, wkb **geom)
4221 : {
4222 0 : int res = -1;
4223 0 : char *GEOSreason = NULL;
4224 0 : GEOSGeom GEOSlocation = NULL;
4225 0 : GEOSGeom geosGeometry;
4226 :
4227 0 : if (is_wkb_nil(*geom)) {
4228 0 : if ((*out = GDKstrdup(str_nil)) == NULL)
4229 0 : throw(MAL, "geom.IsValidReason", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4230 : return MAL_SUCCEED;
4231 : }
4232 :
4233 0 : if ((geosGeometry = wkb2geos(*geom)) == NULL) {
4234 0 : *out = NULL;
4235 0 : throw(MAL, "geom.IsValidDetail", SQLSTATE(38000) "Geos operation wkb2geos failed");
4236 : }
4237 :
4238 0 : res = GEOSisValidDetail_r(geoshandle, geosGeometry, 1, &GEOSreason, &GEOSlocation);
4239 :
4240 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4241 :
4242 0 : if (res == 2) {
4243 0 : throw(MAL, "geom.IsValidDetail", SQLSTATE(38000) "Geos operation GEOSisValidDetail failed");
4244 : }
4245 :
4246 0 : *out = GDKstrdup(GEOSreason);
4247 :
4248 0 : GEOSFree_r(geoshandle, GEOSreason);
4249 0 : GEOSGeom_destroy_r(geoshandle, GEOSlocation);
4250 :
4251 0 : if (*out == NULL)
4252 0 : throw(MAL, "geom.IsValidReason", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4253 :
4254 : return MAL_SUCCEED;
4255 : }
4256 :
4257 : /* returns the area of the geometry */
4258 : str
4259 2 : wkbArea(dbl *out, wkb **geomWKB)
4260 : {
4261 2 : GEOSGeom geosGeometry;
4262 :
4263 2 : if (is_wkb_nil(*geomWKB)) {
4264 0 : *out = dbl_nil;
4265 0 : return MAL_SUCCEED;
4266 : }
4267 :
4268 2 : geosGeometry = wkb2geos(*geomWKB);
4269 2 : if (geosGeometry == NULL) {
4270 0 : *out = dbl_nil;
4271 0 : throw(MAL, "geom.Area", SQLSTATE(38000) "Geos operation wkb2geos failed");
4272 : }
4273 :
4274 2 : if (!GEOSArea_r(geoshandle, geosGeometry, out)) {
4275 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4276 0 : *out = dbl_nil;
4277 0 : throw(MAL, "geom.Area", SQLSTATE(38000) "Geos operation GEOSArea failed");
4278 : }
4279 :
4280 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4281 :
4282 2 : return MAL_SUCCEED;
4283 : }
4284 :
4285 : /* returns the centroid of the geometry */
4286 : str
4287 2 : wkbCentroid(wkb **out, wkb **geom)
4288 : {
4289 2 : GEOSGeom geosGeometry;
4290 2 : GEOSGeom outGeometry;
4291 :
4292 2 : if (is_wkb_nil(*geom)) {
4293 0 : if ((*out = wkbNULLcopy()) == NULL)
4294 0 : throw(MAL, "geom.Centroid", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4295 : return MAL_SUCCEED;
4296 : }
4297 2 : geosGeometry = wkb2geos(*geom);
4298 2 : if (geosGeometry == NULL)
4299 0 : throw(MAL, "geom.Centroid", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4300 :
4301 2 : outGeometry = GEOSGetCentroid_r(geoshandle, geosGeometry);
4302 2 : GEOSSetSRID_r(geoshandle, outGeometry, GEOSGetSRID_r(geoshandle, geosGeometry)); //the centroid has the same SRID with the the input geometry
4303 2 : *out = geos2wkb(outGeometry);
4304 :
4305 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4306 2 : GEOSGeom_destroy_r(geoshandle, outGeometry);
4307 :
4308 2 : return MAL_SUCCEED;
4309 :
4310 : }
4311 :
4312 : /* Returns the 2-dimensional Cartesian minimum distance (based on spatial ref) between two geometries in projected units */
4313 : str
4314 65 : wkbDistance(dbl *out, wkb **a, wkb **b)
4315 : {
4316 65 : GEOSGeom ga, gb;
4317 65 : str err = MAL_SUCCEED;
4318 :
4319 65 : if (is_wkb_nil(*a) || is_wkb_nil(*b)) {
4320 0 : *out = dbl_nil;
4321 0 : return MAL_SUCCEED;
4322 : }
4323 :
4324 65 : ga = wkb2geos(*a);
4325 65 : gb = wkb2geos(*b);
4326 64 : if (ga == NULL || gb == NULL) {
4327 0 : if (ga)
4328 0 : GEOSGeom_destroy_r(geoshandle, ga);
4329 0 : if (gb)
4330 0 : GEOSGeom_destroy_r(geoshandle, gb);
4331 0 : *out = dbl_nil;
4332 0 : throw(MAL, "geom.Distance", SQLSTATE(38000) "Geos operation wkb2geos failed");
4333 : }
4334 :
4335 64 : if (GEOSGetSRID_r(geoshandle, ga) != GEOSGetSRID_r(geoshandle, gb)) {
4336 0 : err = createException(MAL, "geom.Distance", SQLSTATE(38000) "Geometries of different SRID");
4337 64 : } else if (!GEOSDistance_r(geoshandle, ga, gb, out)) {
4338 0 : err = createException(MAL, "geom.Distance", SQLSTATE(38000) "Geos operation GEOSDistance failed");
4339 : }
4340 :
4341 65 : GEOSGeom_destroy_r(geoshandle, ga);
4342 65 : GEOSGeom_destroy_r(geoshandle, gb);
4343 :
4344 65 : return err;
4345 : }
4346 :
4347 : /* Returns the 2d length of the geometry if it is a linestring or multilinestring */
4348 : str
4349 2 : wkbLength(dbl *out, wkb **a)
4350 : {
4351 2 : GEOSGeom geosGeometry;
4352 2 : str err = MAL_SUCCEED;
4353 :
4354 2 : if (is_wkb_nil(*a)) {
4355 0 : *out = dbl_nil;
4356 0 : return MAL_SUCCEED;
4357 : }
4358 :
4359 2 : geosGeometry = wkb2geos(*a);
4360 2 : if (geosGeometry == NULL) {
4361 0 : throw(MAL, "geom.Length", SQLSTATE(38000) "Geos operation wkb2geos failed");
4362 : }
4363 :
4364 2 : if (!GEOSLength_r(geoshandle, geosGeometry, out))
4365 0 : err = createException(MAL, "geom.Length", SQLSTATE(38000) "Geos operation GEOSLength failed");
4366 :
4367 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4368 :
4369 2 : return err;
4370 : }
4371 :
4372 : /* Returns a geometry that represents the convex hull of this geometry.
4373 : * The convex hull of a geometry represents the minimum convex geometry
4374 : * that encloses all geometries within the set. */
4375 : str
4376 1 : wkbConvexHull(wkb **out, wkb **geom)
4377 : {
4378 1 : str ret = MAL_SUCCEED;
4379 1 : GEOSGeom geosGeometry;
4380 1 : GEOSGeom convexHullGeometry = NULL;
4381 :
4382 1 : if (is_wkb_nil(*geom)) {
4383 0 : if ((*out = wkbNULLcopy()) == NULL)
4384 0 : throw(MAL, "geom.ConvexHull", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4385 : return MAL_SUCCEED;
4386 : }
4387 1 : if ((geosGeometry = wkb2geos(*geom)) == NULL)
4388 0 : throw(MAL, "geom.ConvexHull", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4389 :
4390 1 : if ((convexHullGeometry = GEOSConvexHull_r(geoshandle, geosGeometry)) == NULL) {
4391 0 : ret = createException(MAL, "geom.ConvexHull", SQLSTATE(38000) "Geos operation GEOSConvexHull failed");
4392 : } else {
4393 1 : GEOSSetSRID_r(geoshandle, convexHullGeometry, (*geom)->srid);
4394 1 : *out = geos2wkb(convexHullGeometry);
4395 1 : GEOSGeom_destroy_r(geoshandle, convexHullGeometry);
4396 1 : if (*out == NULL)
4397 0 : ret = createException(MAL, "geom.ConvexHull", SQLSTATE(38000) "Geos operation geos2wkb failed");
4398 : }
4399 1 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4400 :
4401 1 : return ret;
4402 :
4403 : }
4404 :
4405 : /* Gets two geometries and returns a new geometry */
4406 : static str
4407 5 : wkbanalysis(wkb **out, wkb **geom1WKB, wkb **geom2WKB, GEOSGeometry *(*func) (GEOSContextHandle_t handle, const GEOSGeometry *, const GEOSGeometry *), const char *name)
4408 : {
4409 5 : GEOSGeom outGeometry, geom1Geometry, geom2Geometry;
4410 5 : str err = MAL_SUCCEED;
4411 :
4412 5 : if (is_wkb_nil(*geom1WKB) || is_wkb_nil(*geom2WKB)) {
4413 0 : if ((*out = wkbNULLcopy()) == NULL)
4414 0 : throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
4415 : return MAL_SUCCEED;
4416 : }
4417 :
4418 5 : geom1Geometry = wkb2geos(*geom1WKB);
4419 5 : geom2Geometry = wkb2geos(*geom2WKB);
4420 5 : if (geom1Geometry == NULL || geom2Geometry == NULL) {
4421 0 : *out = NULL;
4422 0 : if (geom1Geometry)
4423 0 : GEOSGeom_destroy_r(geoshandle, geom1Geometry);
4424 0 : if (geom2Geometry)
4425 0 : GEOSGeom_destroy_r(geoshandle, geom2Geometry);
4426 0 : throw(MAL, name, SQLSTATE(38000) "Geos operation wkb2geos failed");
4427 : }
4428 :
4429 : //make sure the geometries are of the same srid
4430 5 : if (GEOSGetSRID_r(geoshandle, geom1Geometry) != GEOSGetSRID_r(geoshandle, geom2Geometry)) {
4431 0 : err = createException(MAL, name, SQLSTATE(38000) "Geometries of different SRID");
4432 5 : } else if ((outGeometry = (*func) (geoshandle, geom1Geometry, geom2Geometry)) == NULL) {
4433 0 : err = createException(MAL, name, SQLSTATE(38000) "Geos operation GEOS%s failed", name + 5);
4434 : } else {
4435 5 : GEOSSetSRID_r(geoshandle, outGeometry, GEOSGetSRID_r(geoshandle, geom1Geometry));
4436 5 : *out = geos2wkb(outGeometry);
4437 5 : GEOSGeom_destroy_r(geoshandle, outGeometry);
4438 : }
4439 5 : GEOSGeom_destroy_r(geoshandle, geom1Geometry);
4440 5 : GEOSGeom_destroy_r(geoshandle, geom2Geometry);
4441 :
4442 5 : return err;
4443 : }
4444 :
4445 : str
4446 1 : wkbIntersection(wkb **out, wkb **a, wkb **b)
4447 : {
4448 1 : return wkbanalysis(out, a, b, GEOSIntersection_r, "geom.Intersection");
4449 : }
4450 :
4451 : str
4452 2 : wkbUnion(wkb **out, wkb **a, wkb **b)
4453 : {
4454 2 : return wkbanalysis(out, a, b, GEOSUnion_r, "geom.Union");
4455 : }
4456 :
4457 : //Gets a BAT with geometries and returns a single LineString
4458 : str
4459 0 : wkbUnionAggr(wkb **outWKB, bat *inBAT_id)
4460 : {
4461 0 : BAT *inBAT = NULL;
4462 0 : BATiter inBAT_iter;
4463 0 : BUN i;
4464 0 : str err;
4465 0 : wkb *aWKB, *bWKB;
4466 :
4467 : //get the BATs
4468 0 : if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
4469 0 : throw(MAL, "geom.Union", SQLSTATE(38000) "Geos problem retrieving columns");
4470 : }
4471 :
4472 0 : if (BATcount(inBAT) == 0) {
4473 0 : BBPunfix(inBAT->batCacheid);
4474 0 : if ((*outWKB = wkbNULLcopy()) == NULL)
4475 0 : throw(MAL, "geom.Union", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4476 : return MAL_SUCCEED;
4477 : }
4478 :
4479 : //iterator over the BATs
4480 0 : inBAT_iter = bat_iterator(inBAT);
4481 :
4482 0 : aWKB = (wkb *) BUNtvar(inBAT_iter, 0);
4483 0 : if (BATcount(inBAT) == 1) {
4484 0 : bat_iterator_end(&inBAT_iter);
4485 0 : err = wkbFromWKB(outWKB, &aWKB);
4486 0 : BBPunfix(inBAT->batCacheid);
4487 0 : if (err) {
4488 0 : freeException(err);
4489 0 : throw(MAL, "geom.Union", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4490 : }
4491 : return MAL_SUCCEED;
4492 : }
4493 0 : bWKB = (wkb *) BUNtvar(inBAT_iter, 1);
4494 : //create the first union using the first two geometries
4495 0 : err = wkbUnion(outWKB, &aWKB, &bWKB);
4496 0 : for (i = 2; err == MAL_SUCCEED && i < BATcount(inBAT); i++) {
4497 0 : aWKB = *outWKB;
4498 0 : bWKB = (wkb *) BUNtvar(inBAT_iter, i);
4499 0 : *outWKB = NULL;
4500 :
4501 0 : err = wkbUnion(outWKB, &aWKB, &bWKB);
4502 0 : GDKfree(aWKB);
4503 : }
4504 :
4505 0 : bat_iterator_end(&inBAT_iter);
4506 0 : BBPunfix(inBAT->batCacheid);
4507 :
4508 0 : return err;
4509 :
4510 : }
4511 :
4512 : str
4513 1 : wkbDifference(wkb **out, wkb **a, wkb **b)
4514 : {
4515 1 : return wkbanalysis(out, a, b, GEOSDifference_r, "geom.Difference");
4516 : }
4517 :
4518 : str
4519 1 : wkbSymDifference(wkb **out, wkb **a, wkb **b)
4520 : {
4521 1 : return wkbanalysis(out, a, b, GEOSSymDifference_r, "geom.SymDifference");
4522 : }
4523 :
4524 : /* Returns a geometry that represents all points whose distance from this Geometry is less than or equal to distance. */
4525 : str
4526 11 : wkbBuffer(wkb **out, wkb **geom, dbl *distance)
4527 : {
4528 11 : GEOSGeom geosGeometry;
4529 11 : GEOSGeom new;
4530 :
4531 11 : if (is_wkb_nil(*geom) || is_dbl_nil(*distance)) {
4532 0 : if ((*out = wkbNULLcopy()) == NULL)
4533 0 : throw(MAL, "geom.Buffer", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4534 : return MAL_SUCCEED;
4535 : }
4536 :
4537 11 : geosGeometry = wkb2geos(*geom);
4538 11 : if (geosGeometry == NULL) {
4539 0 : throw(MAL, "geom.Buffer", SQLSTATE(38000) "Geos operation wkb2geos failed");
4540 : }
4541 :
4542 11 : if ((new = GEOSBuffer_r(geoshandle, geosGeometry, *distance, 18)) == NULL) {
4543 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4544 0 : throw(MAL, "geom.Buffer", SQLSTATE(38000) "Geos operation GEOSBuffer failed");
4545 : }
4546 11 : *out = geos2wkb(new);
4547 11 : GEOSGeom_destroy_r(geoshandle, new);
4548 11 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4549 :
4550 11 : if (*out == NULL)
4551 0 : throw(MAL, "geom.Buffer", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4552 :
4553 11 : (*out)->srid = (*geom)->srid;
4554 :
4555 11 : return MAL_SUCCEED;
4556 : }
4557 :
4558 : /* Gets two geometries and returns a Boolean by comparing them */
4559 : static str
4560 129 : wkbspatial(bit *out, wkb **geomWKB_a, wkb **geomWKB_b, char (*func) (GEOSContextHandle_t handle, const GEOSGeometry *, const GEOSGeometry *), const char *name)
4561 : {
4562 129 : int res;
4563 129 : GEOSGeom geosGeometry_a, geosGeometry_b;
4564 :
4565 129 : if (is_wkb_nil(*geomWKB_a) || is_wkb_nil(*geomWKB_b)) {
4566 0 : *out = bit_nil;
4567 0 : return MAL_SUCCEED;
4568 : }
4569 :
4570 130 : geosGeometry_a = wkb2geos(*geomWKB_a);
4571 126 : geosGeometry_b = wkb2geos(*geomWKB_b);
4572 130 : if (geosGeometry_a == NULL || geosGeometry_b == NULL) {
4573 0 : if (geosGeometry_a)
4574 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_a);
4575 0 : if (geosGeometry_b)
4576 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_b);
4577 0 : throw(MAL, name, SQLSTATE(38000) "Geos operation wkb2geos failed");
4578 : }
4579 :
4580 130 : if (GEOSGetSRID_r(geoshandle, geosGeometry_a) != GEOSGetSRID_r(geoshandle, geosGeometry_b)) {
4581 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_a);
4582 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_b);
4583 0 : throw(MAL, name, SQLSTATE(38000) "Geometries of different SRID");
4584 : }
4585 :
4586 129 : res = (*func) (geoshandle, geosGeometry_a, geosGeometry_b);
4587 :
4588 129 : GEOSGeom_destroy_r(geoshandle, geosGeometry_a);
4589 131 : GEOSGeom_destroy_r(geoshandle, geosGeometry_b);
4590 :
4591 131 : if (res == 2)
4592 0 : throw(MAL, name, SQLSTATE(38000) "Geos operation GEOS%s failed", name + 5);
4593 :
4594 131 : *out = res;
4595 :
4596 131 : return MAL_SUCCEED;
4597 : }
4598 :
4599 : str
4600 30 : wkbContains(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4601 : {
4602 30 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSContains_r, "geom.Contains");
4603 : }
4604 :
4605 : str
4606 2 : wkbCrosses(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4607 : {
4608 2 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSCrosses_r, "geom.Crosses");
4609 : }
4610 :
4611 : str
4612 2 : wkbDisjoint(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4613 : {
4614 2 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSDisjoint_r, "geom.Disjoint");
4615 : }
4616 :
4617 : str
4618 9 : wkbEquals(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4619 : {
4620 9 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSEquals_r, "geom.Equals");
4621 : }
4622 :
4623 : str
4624 57 : wkbIntersects(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4625 : {
4626 57 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSIntersects_r, "geom.Intersects");
4627 : }
4628 :
4629 : str
4630 7 : wkbOverlaps(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4631 : {
4632 7 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSOverlaps_r, "geom.Overlaps");
4633 : }
4634 :
4635 : str
4636 1 : wkbRelate(bit *out, wkb **geomWKB_a, wkb **geomWKB_b, str *pattern)
4637 : {
4638 1 : int res;
4639 1 : GEOSGeom geosGeometry_a, geosGeometry_b;
4640 :
4641 1 : if (is_wkb_nil(*geomWKB_a) || is_wkb_nil(*geomWKB_b) || strNil(*pattern)) {
4642 0 : *out = bit_nil;
4643 0 : return MAL_SUCCEED;
4644 : }
4645 :
4646 1 : geosGeometry_a = wkb2geos(*geomWKB_a);
4647 1 : geosGeometry_b = wkb2geos(*geomWKB_b);
4648 1 : if (geosGeometry_a == NULL || geosGeometry_b == NULL) {
4649 0 : if (geosGeometry_a)
4650 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_a);
4651 0 : if (geosGeometry_b)
4652 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_b);
4653 0 : throw(MAL, "geom.RelatePattern", SQLSTATE(38000) "Geos operation wkb2geos failed");
4654 : }
4655 :
4656 1 : if (GEOSGetSRID_r(geoshandle, geosGeometry_a) != GEOSGetSRID_r(geoshandle, geosGeometry_b)) {
4657 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_a);
4658 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry_b);
4659 0 : throw(MAL, "geom.RelatePattern", SQLSTATE(38000) "Geometries of different SRID");
4660 : }
4661 :
4662 1 : res = GEOSRelatePattern_r(geoshandle, geosGeometry_a, geosGeometry_b, *pattern);
4663 :
4664 1 : GEOSGeom_destroy_r(geoshandle, geosGeometry_a);
4665 1 : GEOSGeom_destroy_r(geoshandle, geosGeometry_b);
4666 :
4667 1 : if (res == 2)
4668 0 : throw(MAL, "geom.RelatePattern", SQLSTATE(38000) "Geos operation GEOSRelatePattern failed");
4669 :
4670 1 : *out = res;
4671 :
4672 1 : return MAL_SUCCEED;
4673 : }
4674 :
4675 : str
4676 2 : wkbTouches(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4677 : {
4678 2 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSTouches_r, "geom.Touches");
4679 : }
4680 :
4681 : str
4682 2 : wkbWithin(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4683 : {
4684 2 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSWithin_r, "geom.Within");
4685 : }
4686 :
4687 : str
4688 9 : wkbCovers(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4689 : {
4690 9 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSCovers_r, "geom.Covers");
4691 : }
4692 :
4693 : str
4694 9 : wkbCoveredBy(bit *out, wkb **geomWKB_a, wkb **geomWKB_b)
4695 : {
4696 9 : return wkbspatial(out, geomWKB_a, geomWKB_b, GEOSCoveredBy_r, "geom.CoveredBy");
4697 : }
4698 :
4699 : str
4700 56 : wkbDWithin(bit *out, wkb **geomWKB_a, wkb **geomWKB_b, dbl *distance)
4701 : {
4702 56 : double distanceComputed;
4703 56 : str err;
4704 :
4705 56 : if (is_wkb_nil(*geomWKB_a) || is_wkb_nil(*geomWKB_b) || is_dbl_nil(*distance)) {
4706 0 : *out = bit_nil;
4707 0 : return MAL_SUCCEED;
4708 : }
4709 56 : if ((err = wkbDistance(&distanceComputed, geomWKB_a, geomWKB_b)) != MAL_SUCCEED) {
4710 : return err;
4711 : }
4712 :
4713 56 : *out = (distanceComputed <= *distance);
4714 :
4715 56 : return MAL_SUCCEED;
4716 : }
4717 :
4718 : str
4719 10 : wkbDWithinMbr(bit *out, wkb **a, wkb **b, mbr **mbr_a, mbr **mbr_b, dbl *distance)
4720 : {
4721 10 : double actualDistance, bboxDistance;
4722 10 : double halfd_a, halfd_b; // halfed diagonals of the a and b bounding boxes
4723 10 : double ambiguous_zone_min, ambiguous_zone_max; // see comments
4724 10 : str err;
4725 :
4726 10 : if (is_wkb_nil(*a) || is_wkb_nil(*b) || is_dbl_nil(*distance)) {
4727 0 : *out = bit_nil;
4728 0 : return MAL_SUCCEED;
4729 : }
4730 :
4731 : // if there are no mbr(s) fallback to wkbDWithin
4732 10 : if (is_mbr_nil(*mbr_a) || is_mbr_nil(*mbr_b))
4733 0 : return wkbDWithin(out, a, b, distance);
4734 :
4735 : // first calculate the distance of the bounding boxes (mbrs)
4736 10 : if ((err = mbrDistance(&bboxDistance, mbr_a, mbr_b)) != MAL_SUCCEED)
4737 : return err;
4738 :
4739 10 : if ((err = mbrDiagonal(&halfd_a, mbr_a)) != MAL_SUCCEED)
4740 : return err;
4741 10 : halfd_a *= .5;
4742 :
4743 10 : if ((err = mbrDiagonal(&halfd_b, mbr_b)) != MAL_SUCCEED)
4744 : return err;
4745 10 : halfd_b *= .5;
4746 :
4747 : // Every bounding box can be inscribed in a circle. When calculating the distance
4748 : // between two mbrs we do so by their centroids which are actually the origins of
4749 : // their circumscribed circles. Then, independently of the bounded geometry, we can
4750 : // find two rough distance limits which are giving us a zone outside of which the
4751 : // questions 'distance within' can be answered only by the bounding box geometry.
4752 : // If the 'distance within' check is done over distance value in this zone then we
4753 : // actually need to perform the underlying geometry distance calculation.
4754 10 : ambiguous_zone_max = bboxDistance;
4755 10 : ambiguous_zone_min = bboxDistance - halfd_a - halfd_b;
4756 :
4757 10 : if (*distance < ambiguous_zone_min) {
4758 3 : *out = false;
4759 7 : } else if (*distance > ambiguous_zone_max) {
4760 3 : *out = true;
4761 : } else {
4762 : // if we are not sure still calculate the actual distance of the geometries
4763 4 : if ((err = wkbDistance(&actualDistance, a, b)) != MAL_SUCCEED)
4764 : return err;
4765 4 : *out = (actualDistance <= *distance);
4766 : }
4767 :
4768 : return MAL_SUCCEED;
4769 : }
4770 :
4771 : /*returns the n-th geometry in a multi-geometry */
4772 : str
4773 13 : wkbGeometryN(wkb **out, wkb **geom, const int *geometryNum)
4774 : {
4775 13 : int geometriesNum = -1;
4776 13 : GEOSGeom geosGeometry = NULL;
4777 :
4778 : //no geometry at this position
4779 13 : if (is_wkb_nil(*geom) || is_int_nil(*geometryNum) || *geometryNum <= 0) {
4780 1 : if ((*out = wkbNULLcopy()) == NULL)
4781 0 : throw(MAL, "geom.GeometryN", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4782 : return MAL_SUCCEED;
4783 : }
4784 :
4785 12 : geosGeometry = wkb2geos(*geom);
4786 :
4787 12 : if (geosGeometry == NULL) {
4788 0 : *out = NULL;
4789 0 : throw(MAL, "geom.GeometryN", SQLSTATE(38000) "Geos operation wkb2geos failed");
4790 : }
4791 :
4792 12 : geometriesNum = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
4793 12 : if (geometriesNum < 0) {
4794 0 : *out = NULL;
4795 0 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4796 0 : throw(MAL, "geom.GeometryN", SQLSTATE(38000) "Geos operation GEOSGetNumGeometries failed");
4797 : }
4798 12 : if (geometriesNum == 1 || //geometry is not a multi geometry
4799 11 : geometriesNum < *geometryNum) { //no geometry at this position
4800 2 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4801 2 : if ((*out = wkbNULLcopy()) == NULL)
4802 0 : throw(MAL, "geom.GeometryN", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4803 : return MAL_SUCCEED;
4804 : }
4805 :
4806 10 : *out = geos2wkb(GEOSGetGeometryN_r(geoshandle, geosGeometry, *geometryNum - 1));
4807 10 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4808 10 : if (*out == NULL)
4809 0 : throw(MAL, "geom.GeometryN", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4810 :
4811 : return MAL_SUCCEED;
4812 : }
4813 :
4814 : /* returns the number of geometries */
4815 : str
4816 10 : wkbNumGeometries(int *out, wkb **geom)
4817 : {
4818 10 : GEOSGeom geosGeometry;
4819 :
4820 10 : if (is_wkb_nil(*geom)) {
4821 0 : *out = int_nil;
4822 0 : return MAL_SUCCEED;
4823 : }
4824 :
4825 10 : geosGeometry = wkb2geos(*geom);
4826 10 : if (geosGeometry == NULL) {
4827 0 : *out = int_nil;
4828 0 : throw(MAL, "geom.NumGeometries", SQLSTATE(38000) "Geos operation wkb2geos failed");
4829 : }
4830 :
4831 10 : *out = GEOSGetNumGeometries_r(geoshandle, geosGeometry);
4832 10 : GEOSGeom_destroy_r(geoshandle, geosGeometry);
4833 10 : if (*out < 0) {
4834 0 : *out = int_nil;
4835 0 : throw(MAL, "geom.GeometryN", SQLSTATE(38000) "Geos operation GEOSGetNumGeometries failed");
4836 : }
4837 :
4838 : return MAL_SUCCEED;
4839 : }
4840 :
4841 :
4842 : /* TODO: Analyze these functions below (what's the dif from normal contain, is it unfinished?) */
4843 :
4844 : geom_export str wkbContains_point_bat(bat *out, wkb **a, bat *point_x, bat *point_y);
4845 : geom_export str wkbContains_point(bit *out, wkb **a, dbl *point_x, dbl *point_y);
4846 :
4847 : static inline double
4848 0 : isLeft(double P0x, double P0y, double P1x, double P1y, double P2x, double P2y)
4849 : {
4850 0 : return ((P1x - P0x) * (P2y - P0y)
4851 0 : - (P2x - P0x) * (P1y - P0y));
4852 : }
4853 :
4854 : static str
4855 0 : pnpoly(int *out, int nvert, dbl *vx, dbl *vy, bat *point_x, bat *point_y)
4856 : {
4857 0 : BAT *bo = NULL, *bpx = NULL, *bpy;
4858 0 : dbl *px = NULL, *py = NULL;
4859 0 : BUN i = 0, cnt;
4860 0 : int j = 0, nv;
4861 0 : bit *cs = NULL;
4862 :
4863 : /*Get the BATs */
4864 0 : if ((bpx = BATdescriptor(*point_x)) == NULL) {
4865 0 : throw(MAL, "geom.point", SQLSTATE(38000) RUNTIME_OBJECT_MISSING);
4866 : }
4867 :
4868 0 : if ((bpy = BATdescriptor(*point_y)) == NULL) {
4869 0 : BBPunfix(bpx->batCacheid);
4870 0 : throw(MAL, "geom.point", SQLSTATE(38000) RUNTIME_OBJECT_MISSING);
4871 : }
4872 :
4873 : /*Check BATs alignment */
4874 0 : if (bpx->hseqbase != bpy->hseqbase || BATcount(bpx) != BATcount(bpy)) {
4875 0 : BBPunfix(bpx->batCacheid);
4876 0 : BBPunfix(bpy->batCacheid);
4877 0 : throw(MAL, "geom.point", SQLSTATE(38000) "both point bats must have dense and aligned heads");
4878 : }
4879 :
4880 : /*Create output BAT */
4881 0 : if ((bo = COLnew(bpx->hseqbase, TYPE_bit, BATcount(bpx), TRANSIENT)) == NULL) {
4882 0 : BBPunfix(bpx->batCacheid);
4883 0 : BBPunfix(bpy->batCacheid);
4884 0 : throw(MAL, "geom.point", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4885 : }
4886 :
4887 : /*Iterate over the Point BATs and determine if they are in Polygon represented by vertex BATs */
4888 0 : BATiter bpxi = bat_iterator(bpx);
4889 0 : BATiter bpyi = bat_iterator(bpy);
4890 0 : px = (dbl *) bpxi.base;
4891 0 : py = (dbl *) bpyi.base;
4892 :
4893 0 : nv = nvert - 1;
4894 0 : cnt = BATcount(bpx);
4895 0 : cs = (bit *) Tloc(bo, 0);
4896 0 : for (i = 0; i < cnt; i++) {
4897 : int wn = 0;
4898 0 : for (j = 0; j < nv; j++) {
4899 0 : if (vy[j] <= py[i]) {
4900 0 : if (vy[j + 1] > py[i])
4901 0 : if (isLeft(vx[j], vy[j], vx[j + 1], vy[j + 1], px[i], py[i]) > 0)
4902 0 : ++wn;
4903 : } else {
4904 0 : if (vy[j + 1] <= py[i])
4905 0 : if (isLeft(vx[j], vy[j], vx[j + 1], vy[j + 1], px[i], py[i]) < 0)
4906 0 : --wn;
4907 : }
4908 : }
4909 0 : *cs++ = wn & 1;
4910 : }
4911 0 : bat_iterator_end(&bpxi);
4912 0 : bat_iterator_end(&bpyi);
4913 0 : BATsetcount(bo, cnt);
4914 0 : bo->tsorted = bo->trevsorted = false;
4915 0 : bo->tkey = false;
4916 0 : BBPunfix(bpx->batCacheid);
4917 0 : BBPunfix(bpy->batCacheid);
4918 0 : *out = bo->batCacheid;
4919 0 : BBPkeepref(bo);
4920 0 : return MAL_SUCCEED;
4921 : }
4922 :
4923 : static str
4924 0 : pnpolyWithHoles(bat *out, int nvert, dbl *vx, dbl *vy, int nholes, dbl **hx, dbl **hy, int *hn, bat *point_x, bat *point_y)
4925 : {
4926 0 : BAT *bo = NULL, *bpx = NULL, *bpy;
4927 0 : dbl *px = NULL, *py = NULL;
4928 0 : BUN i = 0, cnt = 0;
4929 0 : int j = 0, h = 0;
4930 0 : bit *cs = NULL;
4931 :
4932 : /*Get the BATs */
4933 0 : if ((bpx = BATdescriptor(*point_x)) == NULL) {
4934 0 : throw(MAL, "geom.point", SQLSTATE(38000) RUNTIME_OBJECT_MISSING);
4935 : }
4936 0 : if ((bpy = BATdescriptor(*point_y)) == NULL) {
4937 0 : BBPunfix(bpx->batCacheid);
4938 0 : throw(MAL, "geom.point", SQLSTATE(38000) RUNTIME_OBJECT_MISSING);
4939 : }
4940 :
4941 : /*Check BATs alignment */
4942 0 : if (bpx->hseqbase != bpy->hseqbase || BATcount(bpx) != BATcount(bpy)) {
4943 0 : BBPunfix(bpx->batCacheid);
4944 0 : BBPunfix(bpy->batCacheid);
4945 0 : throw(MAL, "geom.point", SQLSTATE(38000) "Geos both point bats must have dense and aligned heads");
4946 : }
4947 :
4948 : /*Create output BAT */
4949 0 : if ((bo = COLnew(bpx->hseqbase, TYPE_bit, BATcount(bpx), TRANSIENT)) == NULL) {
4950 0 : BBPunfix(bpx->batCacheid);
4951 0 : BBPunfix(bpy->batCacheid);
4952 0 : throw(MAL, "geom.point", SQLSTATE(HY013) MAL_MALLOC_FAIL);
4953 : }
4954 :
4955 : /*Iterate over the Point BATs and determine if they are in Polygon represented by vertex BATs */
4956 0 : BATiter bpxi = bat_iterator(bpx);
4957 0 : BATiter bpyi = bat_iterator(bpy);
4958 0 : px = (dbl *) bpxi.base;
4959 0 : py = (dbl *) bpyi.base;
4960 0 : cnt = BATcount(bpx);
4961 0 : cs = (bit *) Tloc(bo, 0);
4962 0 : for (i = 0; i < cnt; i++) {
4963 : int wn = 0;
4964 :
4965 : /*First check the holes */
4966 0 : for (h = 0; h < nholes; h++) {
4967 0 : int nv = hn[h] - 1;
4968 0 : wn = 0;
4969 0 : for (j = 0; j < nv; j++) {
4970 0 : if (hy[h][j] <= py[i]) {
4971 0 : if (hy[h][j + 1] > py[i])
4972 0 : if (isLeft(hx[h][j], hy[h][j], hx[h][j + 1], hy[h][j + 1], px[i], py[i]) > 0)
4973 0 : ++wn;
4974 : } else {
4975 0 : if (hy[h][j + 1] <= py[i])
4976 0 : if (isLeft(hx[h][j], hy[h][j], hx[h][j + 1], hy[h][j + 1], px[i], py[i]) < 0)
4977 0 : --wn;
4978 : }
4979 : }
4980 :
4981 : /*It is in one of the holes */
4982 0 : if (wn) {
4983 : break;
4984 : }
4985 : }
4986 :
4987 0 : if (wn)
4988 0 : continue;
4989 :
4990 : /*If not in any of the holes, check inside the Polygon */
4991 0 : for (j = 0; j < nvert - 1; j++) {
4992 0 : if (vy[j] <= py[i]) {
4993 0 : if (vy[j + 1] > py[i])
4994 0 : if (isLeft(vx[j], vy[j], vx[j + 1], vy[j + 1], px[i], py[i]) > 0)
4995 0 : ++wn;
4996 : } else {
4997 0 : if (vy[j + 1] <= py[i])
4998 0 : if (isLeft(vx[j], vy[j], vx[j + 1], vy[j + 1], px[i], py[i]) < 0)
4999 0 : --wn;
5000 : }
5001 : }
5002 0 : *cs++ = wn & 1;
5003 : }
5004 0 : bat_iterator_end(&bpxi);
5005 0 : bat_iterator_end(&bpyi);
5006 0 : BATsetcount(bo, cnt);
5007 0 : bo->tsorted = bo->trevsorted = false;
5008 0 : bo->tkey = false;
5009 0 : BBPunfix(bpx->batCacheid);
5010 0 : BBPunfix(bpy->batCacheid);
5011 0 : *out = bo->batCacheid;
5012 0 : BBPkeepref(bo);
5013 0 : return MAL_SUCCEED;
5014 : }
5015 :
5016 : #define POLY_NUM_VERT 120
5017 : #define POLY_NUM_HOLE 10
5018 :
5019 : str
5020 0 : wkbContains_point_bat(bat *out, wkb **a, bat *point_x, bat *point_y)
5021 : {
5022 0 : double *vert_x, *vert_y, **holes_x = NULL, **holes_y = NULL;
5023 0 : int *holes_n = NULL, j;
5024 0 : wkb *geom = NULL;
5025 0 : str err = MAL_SUCCEED;
5026 0 : str geom_str = NULL;
5027 0 : char *str2, *token, *subtoken;
5028 0 : char *saveptr1 = NULL, *saveptr2 = NULL;
5029 0 : int nvert = 0, nholes = 0;
5030 :
5031 0 : geom = (wkb *) *a;
5032 :
5033 0 : if ((err = wkbAsText(&geom_str, &geom, NULL)) != MAL_SUCCEED) {
5034 : return err;
5035 : }
5036 0 : token = strchr(geom_str, '(');
5037 0 : token += 2;
5038 :
5039 : /*Lets get the polygon */
5040 0 : token = strtok_r(token, ")", &saveptr1);
5041 0 : vert_x = GDKmalloc(POLY_NUM_VERT * sizeof(double));
5042 0 : vert_y = GDKmalloc(POLY_NUM_VERT * sizeof(double));
5043 0 : if (vert_x == NULL || vert_y == NULL) {
5044 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5045 0 : goto bailout;
5046 : }
5047 :
5048 : for (str2 = token;; str2 = NULL) {
5049 0 : subtoken = strtok_r(str2, ",", &saveptr2);
5050 0 : if (subtoken == NULL)
5051 : break;
5052 0 : sscanf(subtoken, "%lf %lf", &vert_x[nvert], &vert_y[nvert]);
5053 0 : nvert++;
5054 0 : if ((nvert % POLY_NUM_VERT) == 0) {
5055 0 : double *tmp;
5056 0 : tmp = GDKrealloc(vert_x, nvert * 2 * sizeof(double));
5057 0 : if (tmp == NULL) {
5058 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5059 0 : goto bailout;
5060 : }
5061 0 : vert_x = tmp;
5062 0 : tmp = GDKrealloc(vert_y, nvert * 2 * sizeof(double));
5063 0 : if (tmp == NULL) {
5064 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5065 0 : goto bailout;
5066 : }
5067 : vert_y = tmp;
5068 : }
5069 : }
5070 :
5071 0 : token = strtok_r(NULL, ")", &saveptr1);
5072 0 : if (token) {
5073 0 : holes_x = GDKzalloc(POLY_NUM_HOLE * sizeof(double *));
5074 0 : holes_y = GDKzalloc(POLY_NUM_HOLE * sizeof(double *));
5075 0 : holes_n = GDKzalloc(POLY_NUM_HOLE * sizeof(int));
5076 0 : if (holes_x == NULL || holes_y == NULL || holes_n == NULL) {
5077 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5078 0 : goto bailout;
5079 : }
5080 : }
5081 : /*Lets get all the holes */
5082 0 : while (token) {
5083 0 : int nhole = 0;
5084 0 : token = strchr(token, '(');
5085 0 : if (!token)
5086 : break;
5087 0 : token++;
5088 :
5089 0 : if (holes_x[nholes] == NULL &&
5090 0 : (holes_x[nholes] = GDKzalloc(POLY_NUM_VERT * sizeof(double))) == NULL) {
5091 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5092 0 : goto bailout;
5093 : }
5094 0 : if (holes_y[nholes] == NULL &&
5095 0 : (holes_y[nholes] = GDKzalloc(POLY_NUM_VERT * sizeof(double))) == NULL) {
5096 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5097 0 : goto bailout;
5098 : }
5099 :
5100 : for (str2 = token;; str2 = NULL) {
5101 0 : subtoken = strtok_r(str2, ",", &saveptr2);
5102 0 : if (subtoken == NULL)
5103 : break;
5104 0 : sscanf(subtoken, "%lf %lf", &holes_x[nholes][nhole], &holes_y[nholes][nhole]);
5105 0 : nhole++;
5106 0 : if ((nhole % POLY_NUM_VERT) == 0) {
5107 0 : double *tmp;
5108 0 : tmp = GDKrealloc(holes_x[nholes], nhole * 2 * sizeof(double));
5109 0 : if (tmp == NULL) {
5110 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5111 0 : goto bailout;
5112 : }
5113 0 : holes_x[nholes] = tmp;
5114 0 : tmp = GDKrealloc(holes_y[nholes], nhole * 2 * sizeof(double));
5115 0 : if (tmp == NULL) {
5116 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5117 0 : goto bailout;
5118 : }
5119 0 : holes_y[nholes] = tmp;
5120 : }
5121 : }
5122 :
5123 0 : holes_n[nholes] = nhole;
5124 0 : nholes++;
5125 0 : if ((nholes % POLY_NUM_HOLE) == 0) {
5126 0 : double **tmp;
5127 0 : int *itmp;
5128 0 : tmp = GDKrealloc(holes_x, nholes * 2 * sizeof(double *));
5129 0 : if (tmp == NULL) {
5130 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5131 0 : goto bailout;
5132 : }
5133 0 : holes_x = tmp;
5134 0 : tmp = GDKrealloc(holes_y, nholes * 2 * sizeof(double *));
5135 0 : if (tmp == NULL) {
5136 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5137 0 : goto bailout;
5138 : }
5139 0 : holes_y = tmp;
5140 0 : itmp = GDKrealloc(holes_n, nholes * 2 * sizeof(int));
5141 0 : if (itmp == NULL) {
5142 0 : err = createException(MAL, "geom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
5143 0 : goto bailout;
5144 : }
5145 : holes_n = itmp;
5146 : }
5147 0 : token = strtok_r(NULL, ")", &saveptr1);
5148 : }
5149 :
5150 0 : if (nholes)
5151 0 : err = pnpolyWithHoles(out, nvert, vert_x, vert_y, nholes, holes_x, holes_y, holes_n, point_x, point_y);
5152 : else {
5153 0 : err = pnpoly(out, nvert, vert_x, vert_y, point_x, point_y);
5154 : }
5155 :
5156 0 : bailout:
5157 0 : GDKfree(geom_str);
5158 0 : GDKfree(vert_x);
5159 0 : GDKfree(vert_y);
5160 0 : if (holes_x && holes_y && holes_n) {
5161 0 : for (j = 0; j < nholes; j++) {
5162 0 : GDKfree(holes_x[j]);
5163 0 : GDKfree(holes_y[j]);
5164 : }
5165 : }
5166 0 : GDKfree(holes_x);
5167 0 : GDKfree(holes_y);
5168 0 : GDKfree(holes_n);
5169 :
5170 0 : return err;
5171 : }
5172 :
5173 : str
5174 0 : wkbContains_point(bit *out, wkb **a, dbl *point_x, dbl *point_y)
5175 : {
5176 0 : (void) a;
5177 0 : (void) point_x;
5178 0 : (void) point_y;
5179 0 : *out = TRUE;
5180 0 : return MAL_SUCCEED;
5181 : }
5182 :
5183 : static str
5184 37 : geom_AsText_wkb(char **ret, wkb **w)
5185 : {
5186 37 : return wkbAsText(ret, w, &(int){0});
5187 : }
5188 : static str
5189 29 : geom_AsEWKT_wkb(char **ret, wkb **w)
5190 : {
5191 29 : return wkbAsText(ret, w, &(int){1});
5192 : }
5193 : static str
5194 70 : geom_GeomFromText_str_int(wkb **ret, char **wkt, int *srid)
5195 : {
5196 70 : return wkbFromText(ret, wkt, srid, &(int){0});
5197 : }
5198 : static str
5199 13 : geom_PointFromText_str_int(wkb **ret, char **wkt, int *srid)
5200 : {
5201 13 : return wkbFromText(ret, wkt, srid, &(int){1});
5202 : }
5203 : static str
5204 31 : geom_LineFromText_str_int(wkb **ret, char **wkt, int *srid)
5205 : {
5206 31 : return wkbFromText(ret, wkt, srid, &(int){2});
5207 : }
5208 : static str
5209 18 : geom_PolygonFromText_str_int(wkb **ret, char **wkt, int *srid)
5210 : {
5211 18 : return wkbFromText(ret, wkt, srid, &(int){4});
5212 : }
5213 : static str
5214 16 : geom_MPointFromText_str_int(wkb **ret, char **wkt, int *srid)
5215 : {
5216 16 : return wkbFromText(ret, wkt, srid, &(int){5});
5217 : }
5218 : static str
5219 15 : geom_MLineFromText_str_int(wkb **ret, char **wkt, int *srid)
5220 : {
5221 15 : return wkbFromText(ret, wkt, srid, &(int){6});
5222 : }
5223 : static str
5224 12 : geom_MPolyFromText_str_int(wkb **ret, char **wkt, int *srid)
5225 : {
5226 12 : return wkbFromText(ret, wkt, srid, &(int){7});
5227 : }
5228 : static str
5229 0 : geom_GeomCollFromText_str_int(wkb **ret, char **wkt, int *srid)
5230 : {
5231 0 : return wkbFromText(ret, wkt, srid, &(int){8});
5232 : }
5233 : static str
5234 225 : geom_GeomFromText_str(wkb **ret, char **wkt)
5235 : {
5236 225 : return wkbFromText(ret, wkt, &(int){0}, &(int){0});
5237 : }
5238 : static str
5239 18 : geom_PointFromText_str(wkb **ret, char **wkt)
5240 : {
5241 18 : return wkbFromText(ret, wkt, &(int){0}, &(int){1});
5242 : }
5243 : static str
5244 29 : geom_LineFromText_str(wkb **ret, char **wkt)
5245 : {
5246 29 : return wkbFromText(ret, wkt, &(int){0}, &(int){2});
5247 : }
5248 : static str
5249 16 : geom_PolygonFromText_str(wkb **ret, char **wkt)
5250 : {
5251 16 : return wkbFromText(ret, wkt, &(int){0}, &(int){4});
5252 : }
5253 : static str
5254 12 : geom_MPointFromText_str(wkb **ret, char **wkt)
5255 : {
5256 12 : return wkbFromText(ret, wkt, &(int){0}, &(int){5});
5257 : }
5258 : static str
5259 9 : geom_MLineFromText_str(wkb **ret, char **wkt)
5260 : {
5261 9 : return wkbFromText(ret, wkt, &(int){0}, &(int){6});
5262 : }
5263 : static str
5264 10 : geom_MPolyFromText_str(wkb **ret, char **wkt)
5265 : {
5266 10 : return wkbFromText(ret, wkt, &(int){0}, &(int){7});
5267 : }
5268 : static str
5269 3 : geom_GeomCollFromText_str(wkb **ret, char **wkt)
5270 : {
5271 3 : return wkbFromText(ret, wkt, &(int){0}, &(int){8});
5272 : }
5273 : static str
5274 3 : geom_NumInteriorRings_wkb(int *ret, wkb **w)
5275 : {
5276 3 : return wkbNumRings(ret, w, &(int){0});
5277 : }
5278 : static str
5279 3 : geom_NRings_wkb(int *ret, wkb **w)
5280 : {
5281 3 : return wkbNumRings(ret, w, &(int){1});
5282 : }
5283 : static str
5284 0 : geom_BdPolyFromText_str_int(wkb **ret, char **wkt, int *srid)
5285 : {
5286 0 : return wkbMLineStringToPolygon(ret, wkt, srid, &(int){0});
5287 : }
5288 : static str
5289 0 : geom_BdMPolyFromText_str_int(wkb **ret, char **wkt, int *srid)
5290 : {
5291 0 : return wkbMLineStringToPolygon(ret, wkt, srid, &(int){1});
5292 : }
5293 : static str
5294 48 : geom_MakePoint_dbl_dbl(wkb **ret, dbl *x, dbl *y)
5295 : {
5296 48 : return wkbMakePoint(ret, x, y, &(dbl){0}, &(dbl){0}, &(int){0});
5297 : }
5298 : static str
5299 6 : geom_MakePoint_dbl_dbl_dbl(wkb **ret, dbl *x, dbl *y, dbl *z)
5300 : {
5301 6 : return wkbMakePoint(ret, x, y, z, &(dbl){0}, &(int){10});
5302 : }
5303 : static str
5304 0 : geom_MakePointM_dbl_dbl_dbl(wkb **ret, dbl *x, dbl *y, dbl *m)
5305 : {
5306 0 : return wkbMakePoint(ret, x, y, &(dbl){0}, m, &(int){1});
5307 : }
5308 : static str
5309 0 : geom_MakePoint_dbl_dbl_dbl_dbl(wkb **ret, dbl *x, dbl *y, dbl *z, dbl *m)
5310 : {
5311 0 : return wkbMakePoint(ret, x, y, z, m, &(int){11});
5312 : }
5313 : static str
5314 13 : geom_GeometryType1_wkb(char **ret, wkb **w)
5315 : {
5316 13 : return wkbGeometryType(ret, w, &(int){0});
5317 : }
5318 : static str
5319 13 : geom_GeometryType2_wkb(char **ret, wkb **w)
5320 : {
5321 13 : return wkbGeometryType(ret, w, &(int){1});
5322 : }
5323 : static str
5324 0 : geom_X_wkb(dbl *ret, wkb **w)
5325 : {
5326 0 : return wkbGetCoordinate(ret, w, &(int){0});
5327 : }
5328 : static str
5329 0 : geom_Y_wkb(dbl *ret, wkb **w)
5330 : {
5331 0 : return wkbGetCoordinate(ret, w, &(int){1});
5332 : }
5333 : static str
5334 0 : geom_Z_wkb(dbl *ret, wkb **w)
5335 : {
5336 0 : return wkbGetCoordinate(ret, w, &(int){2});
5337 : }
5338 : static str
5339 0 : geom_Force2D_wkb(wkb **ret, wkb **g)
5340 : {
5341 0 : return wkbForceDim(ret, g, &(int){2});
5342 : }
5343 : static str
5344 0 : geom_Force3D_wkb(wkb **ret, wkb **g)
5345 : {
5346 0 : return wkbForceDim(ret, g, &(int){3});
5347 : }
5348 : static str
5349 0 : geom_Translate_wkb_dbl_dbl(wkb **ret, wkb **g, dbl *dx, dbl *dy)
5350 : {
5351 0 : return wkbTranslate(ret, g, dx, dy, &(dbl){0});
5352 : }
5353 : static str
5354 0 : geom_Translate_wkb_dbl_dbl_dbl(wkb **ret, wkb **g, dbl *dx, dbl *dy, dbl *dz)
5355 : {
5356 0 : return wkbTranslate(ret, g, dx, dy, dz);
5357 : }
5358 : static str
5359 3 : geom_NumPoints_wkb(int *ret, wkb **w)
5360 : {
5361 3 : return wkbNumPoints(ret, w, &(int){1});
5362 : }
5363 : static str
5364 3 : geom_NPoints_wkb(int *ret, wkb **w)
5365 : {
5366 3 : return wkbNumPoints(ret, w, &(int){0});
5367 : }
5368 : static str
5369 0 : geom_MakeEnvelope_dbl_dbl_dbl_dbl_int(wkb **ret, dbl *xmin, dbl *ymin, dbl *xmax, dbl *ymax, int *srid)
5370 : {
5371 0 : return wkbEnvelopeFromCoordinates(ret, xmin, ymin, xmax, ymax, srid);
5372 : }
5373 : static str
5374 0 : geom_MakeEnvelope_dbl_dbl_dbl_dbl(wkb **ret, dbl *xmin, dbl *ymin, dbl *xmax, dbl *ymax)
5375 : {
5376 0 : return wkbEnvelopeFromCoordinates(ret, xmin, ymin, xmax, ymax, &(int){0});
5377 : }
5378 : static str
5379 0 : geom_MakePolygon_wkb(wkb **ret, wkb **external)
5380 : {
5381 0 : return wkbMakePolygon(ret, external, &(bat){bat_nil}, &(int){0});
5382 : }
5383 : static str
5384 0 : geom_MakePolygon_wkb_int(wkb **ret, wkb **external, int *srid)
5385 : {
5386 0 : return wkbMakePolygon(ret, external, &(bat){bat_nil}, srid);
5387 : }
5388 : static str
5389 0 : geom_XMinFromWKB_wkb(dbl *ret, wkb **g)
5390 : {
5391 0 : return wkbCoordinateFromWKB(ret, g, &(int){1});
5392 : }
5393 : static str
5394 0 : geom_YMinFromWKB_wkb(dbl *ret, wkb **g)
5395 : {
5396 0 : return wkbCoordinateFromWKB(ret, g, &(int){2});
5397 : }
5398 : static str
5399 0 : geom_XMaxFromWKB_wkb(dbl *ret, wkb **g)
5400 : {
5401 0 : return wkbCoordinateFromWKB(ret, g, &(int){3});
5402 : }
5403 : static str
5404 0 : geom_YMaxFromWKB_wkb(dbl *ret, wkb **g)
5405 : {
5406 0 : return wkbCoordinateFromWKB(ret, g, &(int){4});
5407 : }
5408 : static str
5409 0 : geom_XMinFromMBR_mbr(dbl *ret, mbr **b)
5410 : {
5411 0 : return wkbCoordinateFromMBR(ret, b, &(int){1});
5412 : }
5413 : static str
5414 0 : geom_YMinFromMBR_mbr(dbl *ret, mbr **b)
5415 : {
5416 0 : return wkbCoordinateFromMBR(ret, b, &(int){2});
5417 : }
5418 : static str
5419 0 : geom_XMaxFromMBR_mbr(dbl *ret, mbr **b)
5420 : {
5421 0 : return wkbCoordinateFromMBR(ret, b, &(int){3});
5422 : }
5423 : static str
5424 0 : geom_YMaxFromMBR_mbr(dbl *ret, mbr **b)
5425 : {
5426 0 : return wkbCoordinateFromMBR(ret, b, &(int){4});
5427 : }
5428 : static str
5429 454 : calc_wkb_str_int_int(wkb **ret, str *wkt, int *srid, int *type)
5430 : {
5431 454 : (void) srid;
5432 454 : (void) type;
5433 454 : return wkbFromText(ret, wkt, &(int){0}, &(int){0});
5434 : }
5435 :
5436 : static str
5437 0 : batgeom_GeomFromText_str_int(bat *ret, bat *wkt, int *srid)
5438 : {
5439 0 : return wkbFromText_bat(ret, wkt, srid, &(int){0});
5440 : }
5441 : static str
5442 0 : batgeom_PointFromText_str_int(bat *ret, bat *wkt, int *srid)
5443 : {
5444 0 : return wkbFromText_bat(ret, wkt, srid, &(int){1});
5445 : }
5446 : static str
5447 0 : batgeom_LineFromText_str_int(bat *ret, bat *wkt, int *srid)
5448 : {
5449 0 : return wkbFromText_bat(ret, wkt, srid, &(int){2});
5450 : }
5451 : static str
5452 0 : batgeom_PolygonFromText_str_int(bat *ret, bat *wkt, int *srid)
5453 : {
5454 0 : return wkbFromText_bat(ret, wkt, srid, &(int){4});
5455 : }
5456 : static str
5457 0 : batgeom_MPointFromText_str_int(bat *ret, bat *wkt, int *srid)
5458 : {
5459 0 : return wkbFromText_bat(ret, wkt, srid, &(int){5});
5460 : }
5461 : static str
5462 0 : batgeom_MLineFromText_str_int(bat *ret, bat *wkt, int *srid)
5463 : {
5464 0 : return wkbFromText_bat(ret, wkt, srid, &(int){6});
5465 : }
5466 : static str
5467 0 : batgeom_MPolyFromText_str_int(bat *ret, bat *wkt, int *srid)
5468 : {
5469 0 : return wkbFromText_bat(ret, wkt, srid, &(int){7});
5470 : }
5471 : static str
5472 0 : batgeom_GeomCollFromText_str_int(bat *ret, bat *wkt, int *srid)
5473 : {
5474 0 : return wkbFromText_bat(ret, wkt, srid, &(int){8});
5475 : }
5476 : static str
5477 1 : batgeom_GeomFromText_str(bat *ret, bat *wkt)
5478 : {
5479 1 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){0});
5480 : }
5481 : static str
5482 8 : batgeom_PointFromText_str(bat *ret, bat *wkt)
5483 : {
5484 8 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){1});
5485 : }
5486 : static str
5487 8 : batgeom_LineFromText_str(bat *ret, bat *wkt)
5488 : {
5489 8 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){2});
5490 : }
5491 : static str
5492 8 : batgeom_PolygonFromText_str(bat *ret, bat *wkt)
5493 : {
5494 8 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){4});
5495 : }
5496 : static str
5497 8 : batgeom_MPointFromText_str(bat *ret, bat *wkt)
5498 : {
5499 8 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){5});
5500 : }
5501 : static str
5502 8 : batgeom_MLineFromText_str(bat *ret, bat *wkt)
5503 : {
5504 8 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){6});
5505 : }
5506 : static str
5507 8 : batgeom_MPolyFromText_str(bat *ret, bat *wkt)
5508 : {
5509 8 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){7});
5510 : }
5511 : static str
5512 0 : batgeom_GeomCollFromText_str(bat *ret, bat *wkt)
5513 : {
5514 0 : return wkbFromText_bat(ret, wkt, &(int){0}, &(int){8});
5515 : }
5516 : static str
5517 26 : batgeom_AsText_wkb(bat *ret, bat *w)
5518 : {
5519 26 : return wkbAsText_bat(ret, w, &(int){0});
5520 : }
5521 : static str
5522 6 : batgeom_AsEWKT_wkb(bat *ret, bat *w)
5523 : {
5524 6 : return wkbAsText_bat(ret, w, &(int){1});
5525 : }
5526 : static str
5527 9 : batgeom_GeometryType1_wkb(bat *ret, bat *w)
5528 : {
5529 9 : return wkbGeometryType_bat(ret, w, &(int){0});
5530 : }
5531 : static str
5532 16 : batgeom_GeometryType2_wkb(bat *ret, bat *w)
5533 : {
5534 16 : return wkbGeometryType_bat(ret, w, &(int){1});
5535 : }
5536 : static str
5537 3 : batgeom_MakePoint_dbl_dbl(bat *ret, bat *x, bat *y)
5538 : {
5539 3 : return wkbMakePoint_bat(ret, x, y, &(bat){bat_nil}, &(bat){bat_nil}, &(int){0});
5540 : }
5541 : static str
5542 1 : batgeom_MakePoint_dbl_dbl_dbl(bat *ret, bat *x, bat *y, bat *z)
5543 : {
5544 1 : return wkbMakePoint_bat(ret, x, y, z, &(bat){bat_nil}, &(int){10});
5545 : }
5546 : static str
5547 1 : batgeom_MakePointM_dbl_dbl_dbl(bat *ret, bat *x, bat *y, bat *m)
5548 : {
5549 1 : return wkbMakePoint_bat(ret, x, y, &(bat){bat_nil}, m, &(int){1});
5550 : }
5551 : static str
5552 1 : batgeom_MakePoint_dbl_dbl_dbl_dbl(bat *ret, bat *x, bat *y, bat *z, bat *m)
5553 : {
5554 1 : return wkbMakePoint_bat(ret, x, y, z, m, &(int){11});
5555 : }
5556 : static str
5557 9 : batgeom_NumPoints_wkb(bat *ret, bat *w)
5558 : {
5559 9 : return wkbNumPoints_bat(ret, w, &(int){1});
5560 : }
5561 : static str
5562 8 : batgeom_NPoints_wkb(bat *ret, bat *w)
5563 : {
5564 8 : return wkbNumPoints_bat(ret, w, &(int){0});
5565 : }
5566 : static str
5567 5 : batgeom_X_wkb(bat *ret, bat *w)
5568 : {
5569 5 : return wkbGetCoordinate_bat(ret, w, &(int){0});
5570 : }
5571 : static str
5572 4 : batgeom_Y_wkb(bat *ret, bat *w)
5573 : {
5574 4 : return wkbGetCoordinate_bat(ret, w, &(int){1});
5575 : }
5576 : static str
5577 3 : batgeom_Z_wkb(bat *ret, bat *w)
5578 : {
5579 3 : return wkbGetCoordinate_bat(ret, w, &(int){2});
5580 : }
5581 : static str
5582 9 : batgeom_NumInteriorRings_wkb(bat *ret, bat *w)
5583 : {
5584 9 : return wkbNumRings_bat(ret, w, &(int){0});
5585 : }
5586 : static str
5587 8 : batgeom_NRings_wkb(bat *ret, bat *w)
5588 : {
5589 8 : return wkbNumRings_bat(ret, w, &(int){1});
5590 : }
5591 : static str
5592 1 : batgeom_XMinFromWKB_wkb(bat *ret, bat *g)
5593 : {
5594 1 : return wkbCoordinateFromWKB_bat(ret, g, &(int){1});
5595 : }
5596 : static str
5597 1 : batgeom_YMinFromWKB_wkb(bat *ret, bat *g)
5598 : {
5599 1 : return wkbCoordinateFromWKB_bat(ret, g, &(int){2});
5600 : }
5601 : static str
5602 1 : batgeom_XMaxFromWKB_wkb(bat *ret, bat *g)
5603 : {
5604 1 : return wkbCoordinateFromWKB_bat(ret, g, &(int){3});
5605 : }
5606 : static str
5607 1 : batgeom_YMaxFromWKB_wkb(bat *ret, bat *g)
5608 : {
5609 1 : return wkbCoordinateFromWKB_bat(ret, g, &(int){4});
5610 : }
5611 : static str
5612 1 : batgeom_XMinFromMBR_mbr(bat *ret, bat *b)
5613 : {
5614 1 : return wkbCoordinateFromMBR_bat(ret, b, &(int){1});
5615 : }
5616 : static str
5617 1 : batgeom_YMinFromMBR_mbr(bat *ret, bat *b)
5618 : {
5619 1 : return wkbCoordinateFromMBR_bat(ret, b, &(int){2});
5620 : }
5621 : static str
5622 1 : batgeom_XMaxFromMBR_mbr(bat *ret, bat *b)
5623 : {
5624 1 : return wkbCoordinateFromMBR_bat(ret, b, &(int){3});
5625 : }
5626 : static str
5627 1 : batgeom_YMaxFromMBR_mbr(bat *ret, bat *b)
5628 : {
5629 1 : return wkbCoordinateFromMBR_bat(ret, b, &(int){4});
5630 : }
5631 :
5632 : #include "mel.h"
5633 : static mel_atom geom_init_atoms[] = {
5634 : { .name="mbr", .basetype="lng", .size=sizeof(mbr), .tostr=mbrTOSTR, .fromstr=mbrFROMSTR, .hash=mbrHASH, .null=mbrNULL, .cmp=mbrCOMP, .read=mbrREAD, .write=mbrWRITE, },
5635 : { .name="wkb", .tostr=wkbTOSTR, .fromstr=wkbFROMSTR, .hash=wkbHASH, .null=wkbNULL, .cmp=wkbCOMP, .read=wkbREAD, .write=wkbWRITE, .put=wkbPUT, .del=wkbDEL, .length=wkbLENGTH, .heap=wkbHEAP, },
5636 : { .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 }
5637 : };
5638 : static mel_func geom_init_funcs[] = {
5639 : //TODO Fill in descriptions
5640 : command("geom", "CoversGeographic", wkbCoversGeographic, false, "TODO", args(1, 3, arg("", bit), arg("a", wkb), arg("b", wkb))),
5641 :
5642 : command("geom", "DistanceGeographic", wkbDistanceGeographic, false, "TODO", args(1, 3, arg("", dbl), arg("a", wkb), arg("b", wkb))),
5643 : command("batgeom", "DistanceGeographic", wkbDistanceGeographic_bat, false, "TODO", args(1, 3, batarg("", dbl), batarg("a", wkb), batarg("b", wkb))),
5644 : 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))),
5645 :
5646 : //Filter functions
5647 : command("geom", "DWithinGeographic", wkbDWithinGeographic, false, "TODO", args(1, 4, arg("", bit), arg("a", wkb), arg("b", wkb), arg("d", dbl))),
5648 : 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))),
5649 : 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))),
5650 : 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))),
5651 : command("geom", "IntersectsGeographicselect", wkbIntersectsGeographicSelect, false, "TODO", args(1, 5, batarg("", oid), batarg("b", wkb), batarg("s", oid), arg("c", wkb), arg("anti",bit))),
5652 : 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))),
5653 :
5654 : 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))),
5655 : command("rtree", "Intersectsselect", wkbIntersectsSelectRTree, false, "TODO", args(1, 5, batarg("", oid), batarg("b", wkb), batarg("s", oid), arg("c", wkb), arg("anti",bit))),
5656 : 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))),
5657 :
5658 : 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))),
5659 : 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))),
5660 : 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))),
5661 :
5662 : 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))),
5663 : command("geom", "Intersects_noindexselect", wkbIntersectsSelectNoIndex, false, "TODO", args(1, 5, batarg("", oid), batarg("b", wkb), batarg("s", oid), arg("c", wkb), arg("anti",bit))),
5664 : 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))),
5665 :
5666 : 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))),
5667 : 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))),
5668 : 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))),
5669 :
5670 : command("geom", "IntersectsMBR", mbrIntersects, false, "TODO", args(1,3, arg("",bit),arg("a",mbr),arg("b",mbr))),
5671 :
5672 : command("geom", "Collect", wkbCollect, false, "TODO", args(1,3, arg("",wkb),arg("a",wkb),arg("b",wkb))),
5673 :
5674 : command("aggr", "Collect", wkbCollectAggr, false, "TODO", args(1, 2, arg("", wkb), batarg("val", wkb))),
5675 : command("aggr", "subCollect", wkbCollectAggrSubGrouped, false, "TODO", args(1, 5, batarg("", wkb), batarg("val", wkb), batarg("g", oid), batarg("e", oid), arg("skip_nils", bit))),
5676 : 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))),
5677 :
5678 : command("geom", "hasZ", geoHasZ, false, "returns 1 if the geometry has z coordinate", args(1,2, arg("",int),arg("flags",int))),
5679 : command("geom", "hasM", geoHasM, false, "returns 1 if the geometry has m coordinate", args(1,2, arg("",int),arg("flags",int))),
5680 : command("geom", "getType", geoGetType, false, "returns the str representation of the geometry type", args(1,3, arg("",str),arg("flags",int),arg("format",int))),
5681 :
5682 : 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))),
5683 : command("geom", "AsBinary", wkbAsBinary, false, "Returns the wkb representation into HEX format", args(1,2, arg("",str),arg("w",wkb))),
5684 : command("geom", "FromBinary", wkbFromBinary, false, "Creates a wkb using the HEX representation", args(1,2, arg("",wkb),arg("w",str))),
5685 : command("geom", "ToText", wkbAsText, false, "", args(1,3, arg("",str),arg("w",wkb),arg("withSRID",int))),
5686 : command("geom", "FromText", wkbFromText, false, "", args(1,4, arg("",wkb),arg("wkt",str),arg("srid",int),arg("type",int))),
5687 : 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))),
5688 : 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))),
5689 : command("geom", "GeometryType", wkbGeometryType, false, "", args(1,3, arg("",str),arg("w",wkb),arg("flag",int))),
5690 : 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))),
5691 : command("geom", "Boundary", wkbBoundary, false, "Returns the closure of the combinatorial boundary of the Geometry.", args(1,2, arg("",wkb),arg("w",wkb))),
5692 : command("geom", "CoordDim", wkbCoordDim, false, "Return the coordinate dimension of the geometry", args(1,2, arg("",int),arg("w",wkb))),
5693 : 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))),
5694 : command("geom", "getSRID", wkbGetSRID, false, "Returns the Spatial Reference System ID for this Geometry.", args(1,2, arg("",int),arg("w",wkb))),
5695 : command("geom", "setSRID", wkbSetSRID, false, "Sets the Reference System ID for this Geometry.", args(1,3, arg("",wkb),arg("w",wkb),arg("srid",int))),
5696 : 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))),
5697 : 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))),
5698 : 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))),
5699 : 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))),
5700 : 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))),
5701 : command("geom", "Polygon", wkbMakePolygon, false, "Returns a Polygon created from the provided LineStrings", args(1,4, arg("",wkb),arg("",wkb),batarg("",wkb),arg("",int))),
5702 : 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))),
5703 : 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))),
5704 : command("geom", "InteriorRings", wkbInteriorRings, false, "Returns an 'array' with all the interior rings of the polygon", args(1,2, arg("",wkba),arg("w",wkb))),
5705 : 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))),
5706 : command("geom", "IsEmpty", wkbIsEmpty, false, "Returns true if this Geometry is an empty geometry.", args(1,2, arg("",bit),arg("w",wkb))),
5707 : command("geom", "IsRing", wkbIsRing, false, "Returns TRUE if this LINESTRING is both closed and simple.", args(1,2, arg("",bit),arg("w",wkb))),
5708 : 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))),
5709 : command("geom", "IsValid", wkbIsValid, false, "Returns true if the ST_Geometry is well formed.", args(1,2, arg("",bit),arg("w",wkb))),
5710 : 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))),
5711 : 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))),
5712 : 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))),
5713 : 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))),
5714 : 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))),
5715 : 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))),
5716 : 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))),
5717 : 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))),
5718 : 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))),
5719 : command("geom", "Union", wkbUnionAggr, false, "Gets a BAT with geometries and returns their union", args(1,2, arg("",wkb),batarg("a",wkb))),
5720 : 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))),
5721 : 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))),
5722 : 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))),
5723 : 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))),
5724 : 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))),
5725 : command("geom", "Disjoint", wkbDisjoint, false, "Returns true if these Geometries are 'spatially disjoint'", args(1,3, arg("",bit),arg("a",wkb),arg("b",wkb))),
5726 : 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))),
5727 : 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))),
5728 : 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))),
5729 : 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))),
5730 : 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))),
5731 : 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))),
5732 : 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))),
5733 : 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))),
5734 : 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))),
5735 : command("geom", "NumGeometries", wkbNumGeometries, false, "Returns the number of geometries", args(1,2, arg("",int),arg("g",wkb))),
5736 : 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))),
5737 : 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))),
5738 : 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))),
5739 : 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))),
5740 : 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))),
5741 : 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))),
5742 : 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))),
5743 : 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))),
5744 : 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))),
5745 : 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))),
5746 : 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))),
5747 : 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))),
5748 : command("aggr", "subMakeLine", wkbMakeLineAggrSubGrouped, false, "TODO", args(1, 5, batarg("", wkb), batarg("val", wkb), batarg("g", oid), batarg("e", oid), arg("skip_nils", bit))),
5749 : 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))),
5750 : 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))),
5751 : command("geom", "mbr", wkbMBR, false, "Creates the mbr for the given wkb.", args(1,2, arg("",mbr),arg("",wkb))),
5752 : command("geom", "MakeBox2D", wkbBox2D, false, "Creates an mbr from the two 2D points", args(1,3, arg("",mbr),arg("",wkb),arg("",wkb))),
5753 : 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))),
5754 : command("geom", "mbrOverlaps", mbrOverlaps, false, "Returns true if box1 overlaps box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5755 : 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))),
5756 : 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))),
5757 : 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))),
5758 : 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))),
5759 : 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))),
5760 : 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))),
5761 : 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))),
5762 : command("geom", "mbrLeft", mbrLeft, false, "Returns true if box1 is left of box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5763 : 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))),
5764 : command("geom", "mbrBelow", mbrBelow, false, "Returns true if box1 is below box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5765 : 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))),
5766 : 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))),
5767 : 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))),
5768 : command("geom", "mbrRight", mbrRight, false, "Returns true if box1 is right of box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5769 : 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))),
5770 : command("geom", "mbrContained", mbrContained, false, "Returns true if box1 is contained by box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5771 : 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))),
5772 : 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))),
5773 : 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))),
5774 : command("geom", "mbrAbove", mbrAbove, false, "Returns true if box1 is above box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5775 : 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))),
5776 : command("geom", "mbrContains", mbrContains, false, "Returns true if box1 contains box2", args(1,3, arg("",bit),arg("box1",mbr),arg("box2",mbr))),
5777 : 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))),
5778 : 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))),
5779 : 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))),
5780 : 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))),
5781 : command("geom", "epilogue", geom_epilogue, false, "", args(1,1, arg("",void))),
5782 : command("batgeom", "FromText", wkbFromText_bat, false, "", args(1,4, batarg("",wkb),batarg("wkt",str),arg("srid",int),arg("type",int))),
5783 : command("batgeom", "ToText", wkbAsText_bat, false, "", args(1,3, batarg("",str),batarg("w",wkb),arg("withSRID",int))),
5784 : command("batgeom", "GeometryType", wkbGeometryType_bat, false, "", args(1,3, batarg("",str),batarg("w",wkb),arg("flag",int))),
5785 : 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))),
5786 : 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))),
5787 : 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))),
5788 : 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))),
5789 : command("batgeom", "NumGeometries", wkbNumGeometries_bat, false, "Returns the number of geometries", args(1,2, batarg("",int),batarg("w",wkb))),
5790 : 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))),
5791 : command("batgeom", "Boundary", wkbBoundary_bat, false, "", args(1,2, batarg("",wkb),batarg("w",wkb))),
5792 : command("batgeom", "IsClosed", wkbIsClosed_bat, false, "", args(1,2, batarg("",bit),batarg("w",wkb))),
5793 : command("batgeom", "IsEmpty", wkbIsEmpty_bat, false, "", args(1,2, batarg("",bit),batarg("w",wkb))),
5794 : command("batgeom", "IsSimple", wkbIsSimple_bat, false, "", args(1,2, batarg("",bit),batarg("w",wkb))),
5795 : command("batgeom", "IsRing", wkbIsRing_bat, false, "", args(1,2, batarg("",bit),batarg("w",wkb))),
5796 : command("batgeom", "IsValid", wkbIsValid_bat, false, "", args(1,2, batarg("",bit),batarg("w",wkb))),
5797 : command("batgeom", "MakeBox2D", wkbBox2D_bat, false, "", args(1,3, batarg("",mbr),batarg("p1",wkb),batarg("p2",wkb))),
5798 : command("batgeom", "Dimension", wkbDimension_bat, false, "", args(1,2, batarg("",int),batarg("w",wkb))),
5799 : command("batgeom", "Distance", wkbDistance_bat, false, "", args(1,3, batarg("",dbl),batarg("a",wkb),batarg("b",wkb))),
5800 : command("batgeom", "Distance", wkbDistance_geom_bat, false, "", args(1,3, batarg("",dbl),arg("a",wkb),batarg("b",wkb))),
5801 : command("batgeom", "Distance", wkbDistance_bat_geom, false, "", args(1,3, batarg("",dbl),batarg("a",wkb),arg("b",wkb))),
5802 : command("batgeom", "Contains", wkbContains_bat, false, "", args(1,3, batarg("",bit),batarg("a",wkb),batarg("b",wkb))),
5803 : command("batgeom", "Contains", wkbContains_geom_bat, false, "", args(1,3, batarg("",bit),arg("a",wkb),batarg("b",wkb))),
5804 : command("batgeom", "Contains", wkbContains_bat_geom, false, "", args(1,3, batarg("",bit),batarg("a",wkb),arg("b",wkb))),
5805 : 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))),
5806 : command("batgeom", "Filter", wkbFilter_bat_geom, false, "", args(1,3, batarg("",wkb),batarg("a",wkb),arg("b",wkb))),
5807 : 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))),
5808 : 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))),
5809 : 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))),
5810 : command("batgeom", "mbr", wkbMBR_bat, false, "Creates the mbr for the given wkb.", args(1,2, batarg("",mbr),batarg("",wkb))),
5811 : 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))),
5812 : 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))),
5813 : 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))),
5814 : command("calc", "mbr", mbrFromString, false, "", args(1,2, arg("",mbr),arg("v",str))),
5815 : command("calc", "mbr", mbrFromMBR, false, "", args(1,2, arg("",mbr),arg("v",mbr))),
5816 : 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))),
5817 : 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))),
5818 : 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))),
5819 : command("batcalc", "wkb", wkbFromText_bat_cand, false, "", args(1,5, batarg("",wkb),batarg("wkt",str),batarg("s",oid),arg("srid",int),arg("type",int))),
5820 : command("geom", "AsText", geom_AsText_wkb, false, "", args(1,2, arg("",str),arg("w",wkb))),
5821 : command("geom", "AsEWKT", geom_AsEWKT_wkb, false, "", args(1,2, arg("",str),arg("w",wkb))),
5822 : command("geom", "GeomFromText", geom_GeomFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5823 : command("geom", "PointFromText", geom_PointFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5824 : command("geom", "LineFromText", geom_LineFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5825 : command("geom", "PolygonFromText", geom_PolygonFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5826 : command("geom", "MPointFromText", geom_MPointFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5827 : command("geom", "MLineFromText", geom_MLineFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5828 : command("geom", "MPolyFromText", geom_MPolyFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5829 : command("geom", "GeomCollFromText", geom_GeomCollFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5830 : command("geom", "GeomFromText", geom_GeomFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5831 : command("geom", "PointFromText", geom_PointFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5832 : command("geom", "LineFromText", geom_LineFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5833 : command("geom", "PolygonFromText", geom_PolygonFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5834 : command("geom", "MPointFromText", geom_MPointFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5835 : command("geom", "MLineFromText", geom_MLineFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5836 : command("geom", "MPolyFromText", geom_MPolyFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5837 : command("geom", "GeomCollFromText", geom_GeomCollFromText_str, false, "", args(1,2, arg("",wkb),arg("wkt",str))),
5838 : command("geom", "NumInteriorRings", geom_NumInteriorRings_wkb, false, "", args(1,2, arg("",int),arg("w",wkb))),
5839 : command("geom", "NRings", geom_NRings_wkb, false, "", args(1,2, arg("",int),arg("w",wkb))),
5840 : command("geom", "BdPolyFromText", geom_BdPolyFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5841 : command("geom", "BdMPolyFromText", geom_BdMPolyFromText_str_int, false, "", args(1,3, arg("",wkb),arg("wkt",str),arg("srid",int))),
5842 : command("geom", "MakePoint", geom_MakePoint_dbl_dbl, false, "", args(1,3, arg("",wkb),arg("x",dbl),arg("y",dbl))),
5843 : command("geom", "MakePoint", geom_MakePoint_dbl_dbl_dbl, false, "", args(1,4, arg("",wkb),arg("x",dbl),arg("y",dbl),arg("z",dbl))),
5844 : command("geom", "MakePointM", geom_MakePointM_dbl_dbl_dbl, false, "", args(1,4, arg("",wkb),arg("x",dbl),arg("y",dbl),arg("m",dbl))),
5845 : 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))),
5846 : command("geom", "GeometryType1", geom_GeometryType1_wkb, false, "", args(1,2, arg("",str),arg("w",wkb))),
5847 : command("geom", "GeometryType2", geom_GeometryType2_wkb, false, "", args(1,2, arg("",str),arg("w",wkb))),
5848 : command("geom", "X", geom_X_wkb, false, "", args(1,2, arg("",dbl),arg("w",wkb))),
5849 : command("geom", "Y", geom_Y_wkb, false, "", args(1,2, arg("",dbl),arg("w",wkb))),
5850 : command("geom", "Z", geom_Z_wkb, false, "", args(1,2, arg("",dbl),arg("w",wkb))),
5851 : command("geom", "Force2D", geom_Force2D_wkb, false, "", args(1,2, arg("",wkb),arg("g",wkb))),
5852 : command("geom", "Force3D", geom_Force3D_wkb, false, "", args(1,2, arg("",wkb),arg("g",wkb))),
5853 : command("geom", "Translate", geom_Translate_wkb_dbl_dbl, false, "", args(1,4, arg("",wkb),arg("g",wkb),arg("dx",dbl),arg("dy",dbl))),
5854 : 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))),
5855 : command("geom", "NumPoints", geom_NumPoints_wkb, false, "", args(1,2, arg("",int),arg("w",wkb))),
5856 : command("geom", "NPoints", geom_NPoints_wkb, false, "", args(1,2, arg("",int),arg("w",wkb))),
5857 : 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))),
5858 : 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))),
5859 : command("geom", "MakePolygon", geom_MakePolygon_wkb, false, "", args(1,2, arg("",wkb),arg("external",wkb))),
5860 : command("geom", "MakePolygon", geom_MakePolygon_wkb_int, false, "", args(1,3, arg("",wkb),arg("external",wkb),arg("srid",int))),
5861 : command("geom", "XMinFromWKB", geom_XMinFromWKB_wkb, false, "", args(1,2, arg("",dbl),arg("g",wkb))),
5862 : command("geom", "YMinFromWKB", geom_YMinFromWKB_wkb, false, "", args(1,2, arg("",dbl),arg("g",wkb))),
5863 : command("geom", "XMaxFromWKB", geom_XMaxFromWKB_wkb, false, "", args(1,2, arg("",dbl),arg("g",wkb))),
5864 : command("geom", "YMaxFromWKB", geom_YMaxFromWKB_wkb, false, "", args(1,2, arg("",dbl),arg("g",wkb))),
5865 : command("geom", "XMinFromMBR", geom_XMinFromMBR_mbr, false, "", args(1,2, arg("",dbl),arg("b",mbr))),
5866 : command("geom", "YMinFromMBR", geom_YMinFromMBR_mbr, false, "", args(1,2, arg("",dbl),arg("b",mbr))),
5867 : command("geom", "XMaxFromMBR", geom_XMaxFromMBR_mbr, false, "", args(1,2, arg("",dbl),arg("b",mbr))),
5868 : command("geom", "YMaxFromMBR", geom_YMaxFromMBR_mbr, false, "", args(1,2, arg("",dbl),arg("b",mbr))),
5869 : command("calc", "wkb", calc_wkb_str_int_int, false, "", args(1,4, arg("",wkb),arg("wkt",str),arg("srid",int),arg("type",int))),
5870 : command("batgeom", "GeomFromText", batgeom_GeomFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5871 : command("batgeom", "PointFromText", batgeom_PointFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5872 : command("batgeom", "LineFromText", batgeom_LineFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5873 : command("batgeom", "PolygonFromText", batgeom_PolygonFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5874 : command("batgeom", "MPointFromText", batgeom_MPointFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5875 : command("batgeom", "MLineFromText", batgeom_MLineFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5876 : command("batgeom", "MPolyFromText", batgeom_MPolyFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5877 : command("batgeom", "GeomCollFromText", batgeom_GeomCollFromText_str_int, false, "", args(1,3, batarg("",wkb),batarg("wkt",str),arg("srid",int))),
5878 : command("batgeom", "GeomFromText", batgeom_GeomFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5879 : command("batgeom", "PointFromText", batgeom_PointFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5880 : command("batgeom", "LineFromText", batgeom_LineFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5881 : command("batgeom", "PolygonFromText", batgeom_PolygonFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5882 : command("batgeom", "MPointFromText", batgeom_MPointFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5883 : command("batgeom", "MLineFromText", batgeom_MLineFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5884 : command("batgeom", "MPolyFromText", batgeom_MPolyFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5885 : command("batgeom", "GeomCollFromText", batgeom_GeomCollFromText_str, false, "", args(1,2, batarg("",wkb),batarg("wkt",str))),
5886 : command("batgeom", "AsText", batgeom_AsText_wkb, false, "", args(1,2, batarg("",str),batarg("w",wkb))),
5887 : command("batgeom", "AsEWKT", batgeom_AsEWKT_wkb, false, "", args(1,2, batarg("",str),batarg("w",wkb))),
5888 : command("batgeom", "GeometryType1", batgeom_GeometryType1_wkb, false, "", args(1,2, batarg("",str),batarg("w",wkb))),
5889 : command("batgeom", "GeometryType2", batgeom_GeometryType2_wkb, false, "", args(1,2, batarg("",str),batarg("w",wkb))),
5890 : command("batgeom", "MakePoint", batgeom_MakePoint_dbl_dbl, false, "", args(1,3, batarg("",wkb),batarg("x",dbl),batarg("y",dbl))),
5891 : command("batgeom", "MakePoint", batgeom_MakePoint_dbl_dbl_dbl, false, "", args(1,4, batarg("",wkb),batarg("x",dbl),batarg("y",dbl),batarg("z",dbl))),
5892 : command("batgeom", "MakePointM", batgeom_MakePointM_dbl_dbl_dbl, false, "", args(1,4, batarg("",wkb),batarg("x",dbl),batarg("y",dbl),batarg("m",dbl))),
5893 : 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))),
5894 : command("batgeom", "NumPoints", batgeom_NumPoints_wkb, false, "", args(1,2, batarg("",int),batarg("w",wkb))),
5895 : command("batgeom", "NPoints", batgeom_NPoints_wkb, false, "", args(1,2, batarg("",int),batarg("w",wkb))),
5896 : command("batgeom", "X", batgeom_X_wkb, false, "", args(1,2, batarg("",dbl),batarg("w",wkb))),
5897 : command("batgeom", "Y", batgeom_Y_wkb, false, "", args(1,2, batarg("",dbl),batarg("w",wkb))),
5898 : command("batgeom", "Z", batgeom_Z_wkb, false, "", args(1,2, batarg("",dbl),batarg("w",wkb))),
5899 : command("batgeom", "NumInteriorRings", batgeom_NumInteriorRings_wkb, false, "", args(1,2, batarg("",int),batarg("w",wkb))),
5900 : command("batgeom", "NRings", batgeom_NRings_wkb, false, "", args(1,2, batarg("",int),batarg("w",wkb))),
5901 : command("batgeom", "XMinFromWKB", batgeom_XMinFromWKB_wkb, false, "", args(1,2, batarg("",dbl),batarg("g",wkb))),
5902 : command("batgeom", "YMinFromWKB", batgeom_YMinFromWKB_wkb, false, "", args(1,2, batarg("",dbl),batarg("g",wkb))),
5903 : command("batgeom", "XMaxFromWKB", batgeom_XMaxFromWKB_wkb, false, "", args(1,2, batarg("",dbl),batarg("g",wkb))),
5904 : command("batgeom", "YMaxFromWKB", batgeom_YMaxFromWKB_wkb, false, "", args(1,2, batarg("",dbl),batarg("g",wkb))),
5905 : command("batgeom", "XMinFromMBR", batgeom_XMinFromMBR_mbr, false, "", args(1,2, batarg("",dbl),batarg("b",mbr))),
5906 : command("batgeom", "YMinFromMBR", batgeom_YMinFromMBR_mbr, false, "", args(1,2, batarg("",dbl),batarg("b",mbr))),
5907 : command("batgeom", "XMaxFromMBR", batgeom_XMaxFromMBR_mbr, false, "", args(1,2, batarg("",dbl),batarg("b",mbr))),
5908 : command("batgeom", "YMaxFromMBR", batgeom_YMaxFromMBR_mbr, false, "", args(1,2, batarg("",dbl),batarg("b",mbr))),
5909 : { .imp=NULL }
5910 : };
5911 : #include "mal_import.h"
5912 : #ifdef _MSC_VER
5913 : #undef read
5914 : #pragma section(".CRT$XCU",read)
5915 : #endif
5916 329 : LIB_STARTUP_FUNC(init_geom_mal)
5917 329 : { mal_module2("geom", geom_init_atoms, geom_init_funcs, geom_prelude, NULL); }
|