PostGIS 3.0.6dev-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#include "../postgis_revision.h"
34
35#define xstr(s) str(s)
36#define str(s) #s
37
38const char *
40{
41 static char *ptr = NULL;
42 static char buf[256];
43 if ( ! ptr )
44 {
45 ptr = buf;
46 snprintf(ptr, 256, LIBLWGEOM_VERSION" " xstr(POSTGIS_REVISION));
47 }
48
49 return ptr;
50}
51
52
53inline float
55{
56 float result;
57 if (d > (double)FLT_MAX)
58 return FLT_MAX;
59 if (d <= (double)-FLT_MAX)
60 return -FLT_MAX;
61 result = d;
62
63 if ( ((double)result) <=d )
64 return result;
65
66 return nextafterf(result, -1*FLT_MAX);
67
68}
69
70/*
71 * Returns the float that's very close to the input, but >=.
72 * handles the funny differences in float4 and float8 reps.
73 */
74inline float
76{
77 float result;
78 if (d >= (double)FLT_MAX)
79 return FLT_MAX;
80 if (d < (double)-FLT_MAX)
81 return -FLT_MAX;
82 result = d;
83
84 if ( ((double)result) >=d )
85 return result;
86
87 return nextafterf(result, FLT_MAX);
88}
89
90
91
92
93/************************************************************************
94 * POINTARRAY support functions
95 *
96 * TODO: should be moved to ptarray.c probably
97 *
98 ************************************************************************/
99
100/*
101 * Copies a point from the point array into the parameter point
102 * will set point's z=NO_Z_VALUE if pa is 2d
103 * will set point's m=NO_M_VALUE if pa is 3d or 2d
104 *
105 * NOTE: point is a real POINT3D *not* a pointer
106 */
108getPoint4d(const POINTARRAY *pa, uint32_t n)
109{
110 POINT4D result;
111 getPoint4d_p(pa, n, &result);
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 lwnotice("%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{
189 POINT3DZ result;
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{
203 POINT3DM result;
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 emtpy/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 0;
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 0;
283 }
284
285 LWDEBUGF(2, "getPoint3dm_p(%d) called on array of %d-dimensions / %u pts",
286 n, FLAGS_NDIMS(pa->flags), pa->npoints);
287
288
289 /* Get a pointer to nth point offset and zmflag */
290 ptr=getPoint_internal(pa, n);
291 zmflag=FLAGS_GET_ZM(pa->flags);
292
293 /*
294 * if input POINTARRAY has the M and NO Z,
295 * we can issue a single memcpy
296 */
297 if ( zmflag == 1 )
298 {
299 memcpy(op, ptr, sizeof(POINT3DM));
300 return 1;
301 }
302
303 /*
304 * Otherwise copy the 2d part and
305 * initialize M to NO_M_VALUE
306 */
307 memcpy(op, ptr, sizeof(POINT2D));
308
309 /*
310 * Then, if input has Z skip it and
311 * copy next double, otherwise initialize
312 * M to NO_M_VALUE
313 */
314 if ( zmflag == 3 )
315 {
316 ptr+=sizeof(POINT3DZ);
317 memcpy(&(op->m), ptr, sizeof(double));
318 }
319 else
320 {
321 op->m=NO_M_VALUE;
322 }
323
324 return 1;
325}
326
327
328/*
329 * Copy a point from the point array into the parameter point
330 * z value (if present) is not returned.
331 *
332 * NOTE: point is a real POINT2D *not* a pointer
333 */
335getPoint2d(const POINTARRAY *pa, uint32_t n)
336{
337 const POINT2D *result;
338 result = getPoint2d_cp(pa, n);
339 return *result;
340}
341
342/*
343 * Copy a point from the point array into the parameter point
344 * z value (if present) is not returned.
345 *
346 * NOTE: this will modify the point2d pointed to by 'point'.
347 */
348int
349getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
350{
351 if ( ! pa )
352 {
353 lwerror("%s [%d] NULL POINTARRAY input", __FILE__, __LINE__);
354 return 0;
355 }
356
357 if ( n>=pa->npoints )
358 {
359 lwnotice("%s [%d] called with n=%d and npoints=%d", __FILE__, __LINE__, n, pa->npoints);
360 return 0;
361 }
362
363 /* this does x,y */
364 memcpy(point, getPoint_internal(pa, n), sizeof(POINT2D));
365 return 1;
366}
367
368/*
369 * set point N to the given value
370 * NOTE that the pointarray can be of any
371 * dimension, the appropriate ordinate values
372 * will be extracted from it
373 *
374 */
375void
376ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
377{
378 uint8_t *ptr;
379 assert(n < pa->npoints);
380 ptr = getPoint_internal(pa, n);
381 switch ( FLAGS_GET_ZM(pa->flags) )
382 {
383 case 3:
384 memcpy(ptr, p4d, sizeof(POINT4D));
385 break;
386 case 2:
387 memcpy(ptr, p4d, sizeof(POINT3DZ));
388 break;
389 case 1:
390 memcpy(ptr, p4d, sizeof(POINT2D));
391 ptr+=sizeof(POINT2D);
392 memcpy(ptr, &(p4d->m), sizeof(double));
393 break;
394 case 0:
395 memcpy(ptr, p4d, sizeof(POINT2D));
396 break;
397 }
398}
399
400void
401ptarray_copy_point(POINTARRAY *pa, uint32_t from, uint32_t to)
402{
403 int ndims = FLAGS_NDIMS(pa->flags);
404 switch (ndims)
405 {
406 case 2:
407 {
408 POINT2D *p_from = (POINT2D*)(getPoint_internal(pa, from));
409 POINT2D *p_to = (POINT2D*)(getPoint_internal(pa, to));
410 *p_to = *p_from;
411 return;
412 }
413 case 3:
414 {
415 POINT3D *p_from = (POINT3D*)(getPoint_internal(pa, from));
416 POINT3D *p_to = (POINT3D*)(getPoint_internal(pa, to));
417 *p_to = *p_from;
418 return;
419 }
420 case 4:
421 {
422 POINT4D *p_from = (POINT4D*)(getPoint_internal(pa, from));
423 POINT4D *p_to = (POINT4D*)(getPoint_internal(pa, to));
424 *p_to = *p_from;
425 return;
426 }
427 default:
428 {
429 lwerror("%s: unsupported number of dimensions - %d", __func__, ndims);
430 return;
431 }
432 }
433 return;
434}
435
436
437/************************************************
438 * debugging routines
439 ************************************************/
440
442{
443 lwnotice("BOX3D: %g %g, %g %g", box->xmin, box->ymin,
444 box->xmax, box->ymax);
445}
446
448{
449 uint32_t t;
450 POINT4D pt;
451 char *mflag;
452
453
454 if ( FLAGS_GET_M(pa->flags) ) mflag = "M";
455 else mflag = "";
456
457 lwnotice(" POINTARRAY%s{", mflag);
458 lwnotice(" ndims=%i, ptsize=%i",
460 lwnotice(" npoints = %i", pa->npoints);
461
462 if (!pa)
463 {
464 lwnotice(" PTARRAY is null pointer!");
465 }
466 else
467 {
468
469 for (t = 0; t < pa->npoints; t++)
470 {
471 getPoint4d_p(pa, t, &pt);
472 if (FLAGS_NDIMS(pa->flags) == 2)
473 lwnotice(" %i : %lf,%lf", t, pt.x, pt.y);
474 if (FLAGS_NDIMS(pa->flags) == 3)
475 lwnotice(" %i : %lf,%lf,%lf", t, pt.x, pt.y, pt.z);
476 if (FLAGS_NDIMS(pa->flags) == 4)
477 lwnotice(" %i : %lf,%lf,%lf,%lf", t, pt.x, pt.y, pt.z, pt.m);
478 }
479 }
480 lwnotice(" }");
481}
482
483
488uint8_t
490{
491 /* do this a little brute force to make it faster */
492
493 uint8_t result_high = 0;
494 uint8_t result_low = 0;
495
496 switch (str[0])
497 {
498 case '0' :
499 result_high = 0;
500 break;
501 case '1' :
502 result_high = 1;
503 break;
504 case '2' :
505 result_high = 2;
506 break;
507 case '3' :
508 result_high = 3;
509 break;
510 case '4' :
511 result_high = 4;
512 break;
513 case '5' :
514 result_high = 5;
515 break;
516 case '6' :
517 result_high = 6;
518 break;
519 case '7' :
520 result_high = 7;
521 break;
522 case '8' :
523 result_high = 8;
524 break;
525 case '9' :
526 result_high = 9;
527 break;
528 case 'A' :
529 case 'a' :
530 result_high = 10;
531 break;
532 case 'B' :
533 case 'b' :
534 result_high = 11;
535 break;
536 case 'C' :
537 case 'c' :
538 result_high = 12;
539 break;
540 case 'D' :
541 case 'd' :
542 result_high = 13;
543 break;
544 case 'E' :
545 case 'e' :
546 result_high = 14;
547 break;
548 case 'F' :
549 case 'f' :
550 result_high = 15;
551 break;
552 }
553 switch (str[1])
554 {
555 case '0' :
556 result_low = 0;
557 break;
558 case '1' :
559 result_low = 1;
560 break;
561 case '2' :
562 result_low = 2;
563 break;
564 case '3' :
565 result_low = 3;
566 break;
567 case '4' :
568 result_low = 4;
569 break;
570 case '5' :
571 result_low = 5;
572 break;
573 case '6' :
574 result_low = 6;
575 break;
576 case '7' :
577 result_low = 7;
578 break;
579 case '8' :
580 result_low = 8;
581 break;
582 case '9' :
583 result_low = 9;
584 break;
585 case 'A' :
586 case 'a' :
587 result_low = 10;
588 break;
589 case 'B' :
590 case 'b' :
591 result_low = 11;
592 break;
593 case 'C' :
594 case 'c' :
595 result_low = 12;
596 break;
597 case 'D' :
598 case 'd' :
599 result_low = 13;
600 break;
601 case 'E' :
602 case 'e' :
603 result_low = 14;
604 break;
605 case 'F' :
606 case 'f' :
607 result_low = 15;
608 break;
609 }
610 return (uint8_t) ((result_high<<4) + result_low);
611}
612
613
623void
624deparse_hex(uint8_t str, char *result)
625{
626 int input_high;
627 int input_low;
628 static char outchr[]=
629 {
630 "0123456789ABCDEF"
631 };
632
633 input_high = (str>>4);
634 input_low = (str & 0x0F);
635
636 result[0] = outchr[input_high];
637 result[1] = outchr[input_low];
638
639}
640
641
655void
656interpolate_point4d(const POINT4D *A, const POINT4D *B, POINT4D *I, double F)
657{
658#if PARANOIA_LEVEL > 0
659 if (F < 0 || F > 1) lwerror("interpolate_point4d: invalid F (%g)", F);
660#endif
661 I->x=A->x+((B->x-A->x)*F);
662 I->y=A->y+((B->y-A->y)*F);
663 I->z=A->z+((B->z-A->z)*F);
664 I->m=A->m+((B->m-A->m)*F);
665}
666
667
669void
673void
677
#define LIBLWGEOM_VERSION
liblwgeom versions
Definition liblwgeom.h:96
void() lwinterrupt_callback()
Install a callback to be called periodically during algorithm execution.
Definition liblwgeom.h:305
#define FLAGS_GET_Z(flags)
Definition liblwgeom.h:179
#define FLAGS_NDIMS(flags)
Definition liblwgeom.h:193
#define FLAGS_GET_M(flags)
Definition liblwgeom.h:180
#define FLAGS_GET_ZM(flags)
Definition liblwgeom.h:194
#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:624
POINT4D getPoint4d(const POINTARRAY *pa, uint32_t n)
Definition lwgeom_api.c:108
lwinterrupt_callback * _lwgeom_interrupt_callback
Definition lwgeom_api.c:678
void lwgeom_cancel_interrupt()
Cancel any interruption request.
Definition lwgeom_api.c:674
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:656
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:668
void printPA(POINTARRAY *pa)
Definition lwgeom_api.c:447
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
Definition lwgeom_api.c:349
const char * lwgeom_version()
Return lwgeom version string (not to be freed)
Definition lwgeom_api.c:39
void printBOX3D(BOX3D *box)
Definition lwgeom_api.c:441
void lwgeom_request_interrupt()
Request interruption of any running code.
Definition lwgeom_api.c:670
lwinterrupt_callback * lwgeom_register_interrupt_callback(lwinterrupt_callback *cb)
Definition lwgeom_api.c:680
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:335
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:489
float next_float_up(double d)
Definition lwgeom_api.c:75
#define str(s)
Definition lwgeom_api.c:36
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:376
void ptarray_copy_point(POINTARRAY *pa, uint32_t from, uint32_t to)
Definition lwgeom_api.c:401
float next_float_down(double d)
Definition lwgeom_api.c:54
#define xstr(s)
Definition lwgeom_api.c:35
int getPoint3dz_p(const POINTARRAY *pa, uint32_t n, POINT3DZ *op)
Definition lwgeom_api.c:215
#define LWDEBUG(level, msg)
Definition lwgeom_log.h:83
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:88
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition lwutil.c:190
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition lwutil.c:177
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition lwinline.h:67
static size_t ptarray_point_size(const POINTARRAY *pa)
Definition lwinline.h:48
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:91
double xmax
Definition liblwgeom.h:326
double ymax
Definition liblwgeom.h:326
double ymin
Definition liblwgeom.h:325
double xmin
Definition liblwgeom.h:325
double m
Definition liblwgeom.h:394
double z
Definition liblwgeom.h:382
double m
Definition liblwgeom.h:400
double x
Definition liblwgeom.h:400
double z
Definition liblwgeom.h:400
double y
Definition liblwgeom.h:400
lwflags_t flags
Definition liblwgeom.h:417
uint32_t npoints
Definition liblwgeom.h:413