PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
lwgeom_api.c
Go to the documentation of this file.
1/**********************************************************************
2 *
3 * PostGIS - Spatial Types for PostgreSQL
4 * http://postgis.net
5 *
6 * PostGIS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * PostGIS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18 *
19 **********************************************************************
20 *
21 * Copyright 2001-2006 Refractions Research Inc.
22 * Copyright 2017 Darafei Praliaskouski <me@komzpa.net>
23 *
24 **********************************************************************/
25
26
27
28#include "liblwgeom_internal.h"
29#include "lwgeom_log.h"
30
31#include <stdio.h>
32#include <assert.h>
33
34#define xstr(s) str(s)
35#define str(s) #s
36
37const char *
39{
40 static char *ptr = NULL;
41 static char buf[256];
42 if ( ! ptr )
43 {
44 ptr = buf;
45 snprintf(ptr, 256, LIBLWGEOM_VERSION" " xstr(POSTGIS_REVISION));
46 }
47
48 return ptr;
49}
50
51
52inline float
54{
55 float result;
56 if (d > (double)FLT_MAX)
57 return FLT_MAX;
58 if (d <= (double)-FLT_MAX)
59 return -FLT_MAX;
60 result = d;
61
62 if ( ((double)result) <=d )
63 return result;
64
65 return nextafterf(result, -1*FLT_MAX);
66
67}
68
69/*
70 * Returns the float that's very close to the input, but >=.
71 * handles the funny differences in float4 and float8 reps.
72 */
73inline float
75{
76 float result;
77 if (d >= (double)FLT_MAX)
78 return FLT_MAX;
79 if (d < (double)-FLT_MAX)
80 return -FLT_MAX;
81 result = d;
82
83 if ( ((double)result) >=d )
84 return result;
85
86 return nextafterf(result, FLT_MAX);
87}
88
89
90
91
92/************************************************************************
93 * POINTARRAY support functions
94 *
95 * TODO: should be moved to ptarray.c probably
96 *
97 ************************************************************************/
98
99/*
100 * Copies a point from the point array into the parameter point
101 * will set point's z=NO_Z_VALUE if pa is 2d
102 * will set point's m=NO_M_VALUE if pa is 3d or 2d
103 *
104 * NOTE: point is a real POINT3D *not* a pointer
105 */
107getPoint4d(const POINTARRAY *pa, uint32_t n)
108{
110 if (getPoint4d_p(pa, n, &result) == 0)
111 lwerror("%s [%d] error returned by getPoint4d_p", __FILE__, __LINE__);
112 return result;
113}
114
115/*
116 * Copies a point from the point array into the parameter point
117 * will set point's z=NO_Z_VALUE if pa is 2d
118 * will set point's m=NO_M_VALUE if pa is 3d or 2d
119 *
120 * NOTE: this will modify the point4d pointed to by 'point'.
121 *
122 * @return 0 on error, 1 on success
123 */
124int
125getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *op)
126{
127 uint8_t *ptr;
128 int zmflag;
129
130 if ( ! pa )
131 {
132 lwerror("%s [%d] NULL POINTARRAY input", __FILE__, __LINE__);
133 return 0;
134 }
135
136 if ( n>=pa->npoints )
137 {
138 lwerror("%s [%d] called with n=%d and npoints=%d", __FILE__, __LINE__, n, pa->npoints);
139 return 0;
140 }
141
142 LWDEBUG(4, "getPoint4d_p called.");
143
144 /* Get a pointer to nth point offset and zmflag */
145 ptr=getPoint_internal(pa, n);
146 zmflag=FLAGS_GET_ZM(pa->flags);
147
148 LWDEBUGF(4, "ptr %p, zmflag %d", ptr, zmflag);
149
150 switch (zmflag)
151 {
152 case 0: /* 2d */
153 memcpy(op, ptr, sizeof(POINT2D));
154 op->m=NO_M_VALUE;
155 op->z=NO_Z_VALUE;
156 break;
157
158 case 3: /* ZM */
159 memcpy(op, ptr, sizeof(POINT4D));
160 break;
161
162 case 2: /* Z */
163 memcpy(op, ptr, sizeof(POINT3DZ));
164 op->m=NO_M_VALUE;
165 break;
166
167 case 1: /* M */
168 memcpy(op, ptr, sizeof(POINT3DM));
169 op->m=op->z; /* we use Z as temporary storage */
170 op->z=NO_Z_VALUE;
171 break;
172
173 default:
174 lwerror("Unknown ZM flag ??");
175 return 0;
176 }
177 return 1;
178
179}
180
181/*
182 * Copy a point from the point array into the parameter point
183 * will set point's z=NO_Z_VALUE if pa is 2d
184 * NOTE: point is a real POINT3DZ *not* a pointer
185 */
187getPoint3dz(const POINTARRAY *pa, uint32_t n)
188{
190 getPoint3dz_p(pa, n, &result);
191 return result;
192}
193
194/*
195 * Copy a point from the point array into the parameter point
196 * will set point's z=NO_Z_VALUE if pa is 2d
197 *
198 * NOTE: point is a real POINT3DZ *not* a pointer
199 */
201getPoint3dm(const POINTARRAY *pa, uint32_t n)
202{
204 getPoint3dm_p(pa, n, &result);
205 return result;
206}
207
208/*
209 * Copy a point from the point array into the parameter point
210 * will set point's z=NO_Z_VALUE if pa is 2d
211 *
212 * NOTE: this will modify the point3dz pointed to by 'point'.
213 */
214int
215getPoint3dz_p(const POINTARRAY *pa, uint32_t n, POINT3DZ *op)
216{
217 uint8_t *ptr;
218
219 if ( ! pa )
220 {
221 lwerror("%s [%d] NULL POINTARRAY input", __FILE__, __LINE__);
222 return 0;
223 }
224
225 //assert(n < pa->npoints); --causes point empty/point empty to crash
226 if ( n>=pa->npoints )
227 {
228 lwnotice("%s [%d] called with n=%d and npoints=%d", __FILE__, __LINE__, n, pa->npoints);
229 return 0;
230 }
231
232 LWDEBUGF(2, "getPoint3dz_p called on array of %d-dimensions / %u pts",
233 FLAGS_NDIMS(pa->flags), pa->npoints);
234
235 /* Get a pointer to nth point offset */
236 ptr=getPoint_internal(pa, n);
237
238 /*
239 * if input POINTARRAY has the Z, it is always
240 * at third position so make a single copy
241 */
242 if ( FLAGS_GET_Z(pa->flags) )
243 {
244 memcpy(op, ptr, sizeof(POINT3DZ));
245 }
246
247 /*
248 * Otherwise copy the 2d part and initialize
249 * Z to NO_Z_VALUE
250 */
251 else
252 {
253 memcpy(op, ptr, sizeof(POINT2D));
254 op->z=NO_Z_VALUE;
255 }
256
257 return 1;
258
259}
260
261/*
262 * Copy a point from the point array into the parameter point
263 * will set point's m=NO_Z_VALUE if pa has no M
264 *
265 * NOTE: this will modify the point3dm pointed to by 'point'.
266 */
267int
268getPoint3dm_p(const POINTARRAY *pa, uint32_t n, POINT3DM *op)
269{
270 uint8_t *ptr;
271 int zmflag;
272
273 if (!pa)
274 {
275 lwerror("%s [%d] NULL POINTARRAY input", __FILE__, __LINE__);
276 return LW_FALSE;
277 }
278
279 if (n >= pa->npoints)
280 {
281 lwerror("%s [%d] called with n=%d and npoints=%d", __FILE__, __LINE__, n, pa->npoints);
282 return LW_FALSE;
283 }
284
285 /* Get a pointer to nth point offset and zmflag */
286 ptr = getPoint_internal(pa, n);
287 zmflag = FLAGS_GET_ZM(pa->flags);
288
289 /*
290 * if input POINTARRAY has the M and NO Z,
291 * we can issue a single memcpy
292 */
293 if (zmflag == 1)
294 {
295 memcpy(op, ptr, sizeof(POINT3DM));
296 return LW_TRUE;
297 }
298
299 /*
300 * Otherwise copy the 2d part and
301 * initialize M to NO_M_VALUE
302 */
303 memcpy(op, ptr, sizeof(POINT2D));
304
305 /*
306 * Then, if input has Z skip it and
307 * copy next double, otherwise initialize
308 * M to NO_M_VALUE
309 */
310 if (zmflag == 3)
311 {
312 ptr += sizeof(POINT3DZ);
313 memcpy(&(op->m), ptr, sizeof(double));
314 }
315 else
316 op->m = NO_M_VALUE;
317
318 return LW_TRUE;
319}
320
321/*
322 * Copy a point from the point array into the parameter point
323 * z value (if present) is not returned.
324 *
325 * NOTE: point is a real POINT2D *not* a pointer
326 */
328getPoint2d(const POINTARRAY *pa, uint32_t n)
329{
330 const POINT2D *result;
331 result = getPoint2d_cp(pa, n);
332 return *result;
333}
334
335/*
336 * Copy a point from the point array into the parameter point
337 * z value (if present) is not returned.
338 *
339 * NOTE: this will modify the point2d pointed to by 'point'.
340 */
341int
342getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
343{
344 if ( ! pa )
345 {
346 lwerror("%s [%d] NULL POINTARRAY input", __FILE__, __LINE__);
347 return 0;
348 }
349
350 if ( n>=pa->npoints )
351 {
352 lwnotice("%s [%d] called with n=%d and npoints=%d", __FILE__, __LINE__, n, pa->npoints);
353 return 0;
354 }
355
356 /* this does x,y */
357 memcpy(point, getPoint_internal(pa, n), sizeof(POINT2D));
358 return 1;
359}
360
361/*
362 * set point N to the given value
363 * NOTE that the pointarray can be of any
364 * dimension, the appropriate ordinate values
365 * will be extracted from it
366 *
367 */
368void
369ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
370{
371 uint8_t *ptr;
372 assert(n < pa->npoints);
373 ptr = getPoint_internal(pa, n);
374 switch ( FLAGS_GET_ZM(pa->flags) )
375 {
376 case 3:
377 memcpy(ptr, p4d, sizeof(POINT4D));
378 break;
379 case 2:
380 memcpy(ptr, p4d, sizeof(POINT3DZ));
381 break;
382 case 1:
383 memcpy(ptr, p4d, sizeof(POINT2D));
384 ptr+=sizeof(POINT2D);
385 memcpy(ptr, &(p4d->m), sizeof(double));
386 break;
387 case 0:
388 memcpy(ptr, p4d, sizeof(POINT2D));
389 break;
390 }
391}
392
393void
394ptarray_copy_point(POINTARRAY *pa, uint32_t from, uint32_t to)
395{
396 int ndims = FLAGS_NDIMS(pa->flags);
397 switch (ndims)
398 {
399 case 2:
400 {
401 POINT2D *p_from = (POINT2D*)(getPoint_internal(pa, from));
402 POINT2D *p_to = (POINT2D*)(getPoint_internal(pa, to));
403 *p_to = *p_from;
404 return;
405 }
406 case 3:
407 {
408 POINT3D *p_from = (POINT3D*)(getPoint_internal(pa, from));
409 POINT3D *p_to = (POINT3D*)(getPoint_internal(pa, to));
410 *p_to = *p_from;
411 return;
412 }
413 case 4:
414 {
415 POINT4D *p_from = (POINT4D*)(getPoint_internal(pa, from));
416 POINT4D *p_to = (POINT4D*)(getPoint_internal(pa, to));
417 *p_to = *p_from;
418 return;
419 }
420 default:
421 {
422 lwerror("%s: unsupported number of dimensions - %d", __func__, ndims);
423 return;
424 }
425 }
426 return;
427}
428
429
430/************************************************
431 * debugging routines
432 ************************************************/
433
435{
436 lwnotice("BOX3D: %g %g, %g %g", box->xmin, box->ymin,
437 box->xmax, box->ymax);
438}
439
441{
442 uint32_t t;
443 POINT4D pt;
444 char *mflag;
445
446 if (!pa)
447 {
448 lwnotice(" PTARRAY is null pointer!");
449 return;
450 }
451 if ( FLAGS_GET_M(pa->flags) ) mflag = "M";
452 else mflag = "";
453
454 lwnotice(" POINTARRAY%s{", mflag);
455 lwnotice(" ndims=%i, ptsize=%zu",
457 lwnotice(" npoints = %u", pa->npoints);
458
459 for (t = 0; t < pa->npoints; t++)
460 {
461 getPoint4d_p(pa, t, &pt);
462 if (FLAGS_NDIMS(pa->flags) == 2)
463 lwnotice(" %i : %lf,%lf", t, pt.x, pt.y);
464 if (FLAGS_NDIMS(pa->flags) == 3)
465 lwnotice(" %i : %lf,%lf,%lf", t, pt.x, pt.y, pt.z);
466 if (FLAGS_NDIMS(pa->flags) == 4)
467 lwnotice(" %i : %lf,%lf,%lf,%lf", t, pt.x, pt.y, pt.z, pt.m);
468 }
469
470 lwnotice(" }");
471}
472
473
478uint8_t
480{
481 /* do this a little brute force to make it faster */
482
483 uint8_t result_high = 0;
484 uint8_t result_low = 0;
485
486 switch (str[0])
487 {
488 case '0' :
489 result_high = 0;
490 break;
491 case '1' :
492 result_high = 1;
493 break;
494 case '2' :
495 result_high = 2;
496 break;
497 case '3' :
498 result_high = 3;
499 break;
500 case '4' :
501 result_high = 4;
502 break;
503 case '5' :
504 result_high = 5;
505 break;
506 case '6' :
507 result_high = 6;
508 break;
509 case '7' :
510 result_high = 7;
511 break;
512 case '8' :
513 result_high = 8;
514 break;
515 case '9' :
516 result_high = 9;
517 break;
518 case 'A' :
519 case 'a' :
520 result_high = 10;
521 break;
522 case 'B' :
523 case 'b' :
524 result_high = 11;
525 break;
526 case 'C' :
527 case 'c' :
528 result_high = 12;
529 break;
530 case 'D' :
531 case 'd' :
532 result_high = 13;
533 break;
534 case 'E' :
535 case 'e' :
536 result_high = 14;
537 break;
538 case 'F' :
539 case 'f' :
540 result_high = 15;
541 break;
542 }
543 switch (str[1])
544 {
545 case '0' :
546 result_low = 0;
547 break;
548 case '1' :
549 result_low = 1;
550 break;
551 case '2' :
552 result_low = 2;
553 break;
554 case '3' :
555 result_low = 3;
556 break;
557 case '4' :
558 result_low = 4;
559 break;
560 case '5' :
561 result_low = 5;
562 break;
563 case '6' :
564 result_low = 6;
565 break;
566 case '7' :
567 result_low = 7;
568 break;
569 case '8' :
570 result_low = 8;
571 break;
572 case '9' :
573 result_low = 9;
574 break;
575 case 'A' :
576 case 'a' :
577 result_low = 10;
578 break;
579 case 'B' :
580 case 'b' :
581 result_low = 11;
582 break;
583 case 'C' :
584 case 'c' :
585 result_low = 12;
586 break;
587 case 'D' :
588 case 'd' :
589 result_low = 13;
590 break;
591 case 'E' :
592 case 'e' :
593 result_low = 14;
594 break;
595 case 'F' :
596 case 'f' :
597 result_low = 15;
598 break;
599 }
600 return (uint8_t) ((result_high<<4) + result_low);
601}
602
603
613void
614deparse_hex(uint8_t str, char *result)
615{
616 int input_high;
617 int input_low;
618 static char outchr[]=
619 {
620 "0123456789ABCDEF"
621 };
622
623 input_high = (str>>4);
624 input_low = (str & 0x0F);
625
626 result[0] = outchr[input_high];
627 result[1] = outchr[input_low];
628
629}
630
631
645void
646interpolate_point4d(const POINT4D *A, const POINT4D *B, POINT4D *I, double F)
647{
648 assert(F >= 0 && F <= 1);
649 I->x=A->x+((B->x-A->x)*F);
650 I->y=A->y+((B->y-A->y)*F);
651 I->z=A->z+((B->z-A->z)*F);
652 I->m=A->m+((B->m-A->m)*F);
653}
654
655
657void
661void
665
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
#define LIBLWGEOM_VERSION
liblwgeom versions
Definition liblwgeom.h:82
#define LW_FALSE
Definition liblwgeom.h:94
void() lwinterrupt_callback(void)
Install a callback to be called periodically during algorithm execution.
Definition liblwgeom.h:291
#define FLAGS_GET_Z(flags)
Definition liblwgeom.h:165
#define FLAGS_NDIMS(flags)
Definition liblwgeom.h:179
#define FLAGS_GET_M(flags)
Definition liblwgeom.h:166
#define FLAGS_GET_ZM(flags)
Definition liblwgeom.h:180
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:93
#define NO_Z_VALUE
#define NO_M_VALUE
void deparse_hex(uint8_t str, char *result)
Given one byte, populate result with two byte representing the hex number.
Definition lwgeom_api.c:614
POINT4D getPoint4d(const POINTARRAY *pa, uint32_t n)
Definition lwgeom_api.c:107
lwinterrupt_callback * _lwgeom_interrupt_callback
Definition lwgeom_api.c:666
void lwgeom_cancel_interrupt()
Cancel any interruption request.
Definition lwgeom_api.c:662
void interpolate_point4d(const POINT4D *A, const POINT4D *B, POINT4D *I, double F)
Find interpolation point I between point A and point B so that the len(AI) == len(AB)*F and I falls o...
Definition lwgeom_api.c:646
POINT3DM getPoint3dm(const POINTARRAY *pa, uint32_t n)
Definition lwgeom_api.c:201
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *op)
Definition lwgeom_api.c:125
int _lwgeom_interrupt_requested
Definition lwgeom_api.c:656
void printPA(POINTARRAY *pa)
Definition lwgeom_api.c:440
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
Definition lwgeom_api.c:342
const char * lwgeom_version()
Return lwgeom version string (not to be freed)
Definition lwgeom_api.c:38
void printBOX3D(BOX3D *box)
Definition lwgeom_api.c:434
void lwgeom_request_interrupt()
Request interruption of any running code.
Definition lwgeom_api.c:658
lwinterrupt_callback * lwgeom_register_interrupt_callback(lwinterrupt_callback *cb)
Definition lwgeom_api.c:668
POINT3DZ getPoint3dz(const POINTARRAY *pa, uint32_t n)
Definition lwgeom_api.c:187
POINT2D getPoint2d(const POINTARRAY *pa, uint32_t n)
Definition lwgeom_api.c:328
uint8_t parse_hex(char *str)
Given a string with at least 2 chars in it, convert them to a byte value.
Definition lwgeom_api.c:479
float next_float_up(double d)
Definition lwgeom_api.c:74
#define str(s)
Definition lwgeom_api.c:35
int getPoint3dm_p(const POINTARRAY *pa, uint32_t n, POINT3DM *op)
Definition lwgeom_api.c:268
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
Definition lwgeom_api.c:369
void ptarray_copy_point(POINTARRAY *pa, uint32_t from, uint32_t to)
Definition lwgeom_api.c:394
float next_float_down(double d)
Definition lwgeom_api.c:53
#define xstr(s)
Definition lwgeom_api.c:34
int getPoint3dz_p(const POINTARRAY *pa, uint32_t n, POINT3DZ *op)
Definition lwgeom_api.c:215
#define LWDEBUG(level, msg)
Definition lwgeom_log.h:101
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:106
void lwnotice(const char *fmt,...) __attribute__((format(printf
Write a notice out to the notice handler.
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition lwinline.h:75
static size_t ptarray_point_size(const POINTARRAY *pa)
Definition lwinline.h:56
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition lwinline.h:97
double xmax
Definition liblwgeom.h:340
double ymax
Definition liblwgeom.h:340
double ymin
Definition liblwgeom.h:339
double xmin
Definition liblwgeom.h:339
double m
Definition liblwgeom.h:408
double z
Definition liblwgeom.h:396
double m
Definition liblwgeom.h:414
double x
Definition liblwgeom.h:414
double z
Definition liblwgeom.h:414
double y
Definition liblwgeom.h:414
lwflags_t flags
Definition liblwgeom.h:431
uint32_t npoints
Definition liblwgeom.h:427