PostGIS  3.3.9dev-r@@SVN_REVISION@@
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 
38 const 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 
53 inline float
54 next_float_down(double d)
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  */
74 inline float
75 next_float_up(double d)
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  */
107 POINT4D
108 getPoint4d(const POINTARRAY *pa, uint32_t n)
109 {
110  POINT4D result;
111  if (getPoint4d_p(pa, n, &result) == 0)
112  lwerror("%s [%d] error returned by getPoint4d_p", __FILE__, __LINE__);
113  return result;
114 }
115 
116 /*
117  * Copies a point from the point array into the parameter point
118  * will set point's z=NO_Z_VALUE if pa is 2d
119  * will set point's m=NO_M_VALUE if pa is 3d or 2d
120  *
121  * NOTE: this will modify the point4d pointed to by 'point'.
122  *
123  * @return 0 on error, 1 on success
124  */
125 int
126 getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *op)
127 {
128  uint8_t *ptr;
129  int zmflag;
130 
131  if ( ! pa )
132  {
133  lwerror("%s [%d] NULL POINTARRAY input", __FILE__, __LINE__);
134  return 0;
135  }
136 
137  if ( n>=pa->npoints )
138  {
139  lwerror("%s [%d] called with n=%d and npoints=%d", __FILE__, __LINE__, n, pa->npoints);
140  return 0;
141  }
142 
143  LWDEBUG(4, "getPoint4d_p called.");
144 
145  /* Get a pointer to nth point offset and zmflag */
146  ptr=getPoint_internal(pa, n);
147  zmflag=FLAGS_GET_ZM(pa->flags);
148 
149  LWDEBUGF(4, "ptr %p, zmflag %d", ptr, zmflag);
150 
151  switch (zmflag)
152  {
153  case 0: /* 2d */
154  memcpy(op, ptr, sizeof(POINT2D));
155  op->m=NO_M_VALUE;
156  op->z=NO_Z_VALUE;
157  break;
158 
159  case 3: /* ZM */
160  memcpy(op, ptr, sizeof(POINT4D));
161  break;
162 
163  case 2: /* Z */
164  memcpy(op, ptr, sizeof(POINT3DZ));
165  op->m=NO_M_VALUE;
166  break;
167 
168  case 1: /* M */
169  memcpy(op, ptr, sizeof(POINT3DM));
170  op->m=op->z; /* we use Z as temporary storage */
171  op->z=NO_Z_VALUE;
172  break;
173 
174  default:
175  lwerror("Unknown ZM flag ??");
176  return 0;
177  }
178  return 1;
179 
180 }
181 
182 /*
183  * Copy a point from the point array into the parameter point
184  * will set point's z=NO_Z_VALUE if pa is 2d
185  * NOTE: point is a real POINT3DZ *not* a pointer
186  */
187 POINT3DZ
188 getPoint3dz(const POINTARRAY *pa, uint32_t n)
189 {
191  getPoint3dz_p(pa, n, &result);
192  return result;
193 }
194 
195 /*
196  * Copy a point from the point array into the parameter point
197  * will set point's z=NO_Z_VALUE if pa is 2d
198  *
199  * NOTE: point is a real POINT3DZ *not* a pointer
200  */
201 POINT3DM
202 getPoint3dm(const POINTARRAY *pa, uint32_t n)
203 {
205  getPoint3dm_p(pa, n, &result);
206  return result;
207 }
208 
209 /*
210  * Copy a point from the point array into the parameter point
211  * will set point's z=NO_Z_VALUE if pa is 2d
212  *
213  * NOTE: this will modify the point3dz pointed to by 'point'.
214  */
215 int
216 getPoint3dz_p(const POINTARRAY *pa, uint32_t n, POINT3DZ *op)
217 {
218  uint8_t *ptr;
219 
220  if ( ! pa )
221  {
222  lwerror("%s [%d] NULL POINTARRAY input", __FILE__, __LINE__);
223  return 0;
224  }
225 
226  //assert(n < pa->npoints); --causes point emtpy/point empty to crash
227  if ( n>=pa->npoints )
228  {
229  lwnotice("%s [%d] called with n=%d and npoints=%d", __FILE__, __LINE__, n, pa->npoints);
230  return 0;
231  }
232 
233  LWDEBUGF(2, "getPoint3dz_p called on array of %d-dimensions / %u pts",
234  FLAGS_NDIMS(pa->flags), pa->npoints);
235 
236  /* Get a pointer to nth point offset */
237  ptr=getPoint_internal(pa, n);
238 
239  /*
240  * if input POINTARRAY has the Z, it is always
241  * at third position so make a single copy
242  */
243  if ( FLAGS_GET_Z(pa->flags) )
244  {
245  memcpy(op, ptr, sizeof(POINT3DZ));
246  }
247 
248  /*
249  * Otherwise copy the 2d part and initialize
250  * Z to NO_Z_VALUE
251  */
252  else
253  {
254  memcpy(op, ptr, sizeof(POINT2D));
255  op->z=NO_Z_VALUE;
256  }
257 
258  return 1;
259 
260 }
261 
262 /*
263  * Copy a point from the point array into the parameter point
264  * will set point's m=NO_Z_VALUE if pa has no M
265  *
266  * NOTE: this will modify the point3dm pointed to by 'point'.
267  */
268 int
269 getPoint3dm_p(const POINTARRAY *pa, uint32_t n, POINT3DM *op)
270 {
271  uint8_t *ptr;
272  int zmflag;
273 
274  if (!pa)
275  {
276  lwerror("%s [%d] NULL POINTARRAY input", __FILE__, __LINE__);
277  return LW_FALSE;
278  }
279 
280  if (n >= pa->npoints)
281  {
282  lwerror("%s [%d] called with n=%d and npoints=%d", __FILE__, __LINE__, n, pa->npoints);
283  return LW_FALSE;
284  }
285 
286  /* Get a pointer to nth point offset and zmflag */
287  ptr = getPoint_internal(pa, n);
288  zmflag = FLAGS_GET_ZM(pa->flags);
289 
290  /*
291  * if input POINTARRAY has the M and NO Z,
292  * we can issue a single memcpy
293  */
294  if (zmflag == 1)
295  {
296  memcpy(op, ptr, sizeof(POINT3DM));
297  return LW_TRUE;
298  }
299 
300  /*
301  * Otherwise copy the 2d part and
302  * initialize M to NO_M_VALUE
303  */
304  memcpy(op, ptr, sizeof(POINT2D));
305 
306  /*
307  * Then, if input has Z skip it and
308  * copy next double, otherwise initialize
309  * M to NO_M_VALUE
310  */
311  if (zmflag == 3)
312  {
313  ptr += sizeof(POINT3DZ);
314  memcpy(&(op->m), ptr, sizeof(double));
315  }
316  else
317  op->m = NO_M_VALUE;
318 
319  return LW_TRUE;
320 }
321 
322 /*
323  * Copy a point from the point array into the parameter point
324  * z value (if present) is not returned.
325  *
326  * NOTE: point is a real POINT2D *not* a pointer
327  */
328 POINT2D
329 getPoint2d(const POINTARRAY *pa, uint32_t n)
330 {
331  const POINT2D *result;
332  result = getPoint2d_cp(pa, n);
333  return *result;
334 }
335 
336 /*
337  * Copy a point from the point array into the parameter point
338  * z value (if present) is not returned.
339  *
340  * NOTE: this will modify the point2d pointed to by 'point'.
341  */
342 int
343 getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
344 {
345  if ( ! pa )
346  {
347  lwerror("%s [%d] NULL POINTARRAY input", __FILE__, __LINE__);
348  return 0;
349  }
350 
351  if ( n>=pa->npoints )
352  {
353  lwnotice("%s [%d] called with n=%d and npoints=%d", __FILE__, __LINE__, n, pa->npoints);
354  return 0;
355  }
356 
357  /* this does x,y */
358  memcpy(point, getPoint_internal(pa, n), sizeof(POINT2D));
359  return 1;
360 }
361 
362 /*
363  * set point N to the given value
364  * NOTE that the pointarray can be of any
365  * dimension, the appropriate ordinate values
366  * will be extracted from it
367  *
368  */
369 void
370 ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
371 {
372  uint8_t *ptr;
373  assert(n < pa->npoints);
374  ptr = getPoint_internal(pa, n);
375  switch ( FLAGS_GET_ZM(pa->flags) )
376  {
377  case 3:
378  memcpy(ptr, p4d, sizeof(POINT4D));
379  break;
380  case 2:
381  memcpy(ptr, p4d, sizeof(POINT3DZ));
382  break;
383  case 1:
384  memcpy(ptr, p4d, sizeof(POINT2D));
385  ptr+=sizeof(POINT2D);
386  memcpy(ptr, &(p4d->m), sizeof(double));
387  break;
388  case 0:
389  memcpy(ptr, p4d, sizeof(POINT2D));
390  break;
391  }
392 }
393 
394 void
395 ptarray_copy_point(POINTARRAY *pa, uint32_t from, uint32_t to)
396 {
397  int ndims = FLAGS_NDIMS(pa->flags);
398  switch (ndims)
399  {
400  case 2:
401  {
402  POINT2D *p_from = (POINT2D*)(getPoint_internal(pa, from));
403  POINT2D *p_to = (POINT2D*)(getPoint_internal(pa, to));
404  *p_to = *p_from;
405  return;
406  }
407  case 3:
408  {
409  POINT3D *p_from = (POINT3D*)(getPoint_internal(pa, from));
410  POINT3D *p_to = (POINT3D*)(getPoint_internal(pa, to));
411  *p_to = *p_from;
412  return;
413  }
414  case 4:
415  {
416  POINT4D *p_from = (POINT4D*)(getPoint_internal(pa, from));
417  POINT4D *p_to = (POINT4D*)(getPoint_internal(pa, to));
418  *p_to = *p_from;
419  return;
420  }
421  default:
422  {
423  lwerror("%s: unsupported number of dimensions - %d", __func__, ndims);
424  return;
425  }
426  }
427  return;
428 }
429 
430 
431 /************************************************
432  * debugging routines
433  ************************************************/
434 
435 void printBOX3D(BOX3D *box)
436 {
437  lwnotice("BOX3D: %g %g, %g %g", box->xmin, box->ymin,
438  box->xmax, box->ymax);
439 }
440 
442 {
443  uint32_t t;
444  POINT4D pt;
445  char *mflag;
446 
447 
448  if ( FLAGS_GET_M(pa->flags) ) mflag = "M";
449  else mflag = "";
450 
451  lwnotice(" POINTARRAY%s{", mflag);
452  lwnotice(" ndims=%i, ptsize=%i",
454  lwnotice(" npoints = %i", pa->npoints);
455 
456  if (!pa)
457  {
458  lwnotice(" PTARRAY is null pointer!");
459  }
460  else
461  {
462 
463  for (t = 0; t < pa->npoints; t++)
464  {
465  getPoint4d_p(pa, t, &pt);
466  if (FLAGS_NDIMS(pa->flags) == 2)
467  lwnotice(" %i : %lf,%lf", t, pt.x, pt.y);
468  if (FLAGS_NDIMS(pa->flags) == 3)
469  lwnotice(" %i : %lf,%lf,%lf", t, pt.x, pt.y, pt.z);
470  if (FLAGS_NDIMS(pa->flags) == 4)
471  lwnotice(" %i : %lf,%lf,%lf,%lf", t, pt.x, pt.y, pt.z, pt.m);
472  }
473  }
474  lwnotice(" }");
475 }
476 
477 
482 uint8_t
484 {
485  /* do this a little brute force to make it faster */
486 
487  uint8_t result_high = 0;
488  uint8_t result_low = 0;
489 
490  switch (str[0])
491  {
492  case '0' :
493  result_high = 0;
494  break;
495  case '1' :
496  result_high = 1;
497  break;
498  case '2' :
499  result_high = 2;
500  break;
501  case '3' :
502  result_high = 3;
503  break;
504  case '4' :
505  result_high = 4;
506  break;
507  case '5' :
508  result_high = 5;
509  break;
510  case '6' :
511  result_high = 6;
512  break;
513  case '7' :
514  result_high = 7;
515  break;
516  case '8' :
517  result_high = 8;
518  break;
519  case '9' :
520  result_high = 9;
521  break;
522  case 'A' :
523  case 'a' :
524  result_high = 10;
525  break;
526  case 'B' :
527  case 'b' :
528  result_high = 11;
529  break;
530  case 'C' :
531  case 'c' :
532  result_high = 12;
533  break;
534  case 'D' :
535  case 'd' :
536  result_high = 13;
537  break;
538  case 'E' :
539  case 'e' :
540  result_high = 14;
541  break;
542  case 'F' :
543  case 'f' :
544  result_high = 15;
545  break;
546  }
547  switch (str[1])
548  {
549  case '0' :
550  result_low = 0;
551  break;
552  case '1' :
553  result_low = 1;
554  break;
555  case '2' :
556  result_low = 2;
557  break;
558  case '3' :
559  result_low = 3;
560  break;
561  case '4' :
562  result_low = 4;
563  break;
564  case '5' :
565  result_low = 5;
566  break;
567  case '6' :
568  result_low = 6;
569  break;
570  case '7' :
571  result_low = 7;
572  break;
573  case '8' :
574  result_low = 8;
575  break;
576  case '9' :
577  result_low = 9;
578  break;
579  case 'A' :
580  case 'a' :
581  result_low = 10;
582  break;
583  case 'B' :
584  case 'b' :
585  result_low = 11;
586  break;
587  case 'C' :
588  case 'c' :
589  result_low = 12;
590  break;
591  case 'D' :
592  case 'd' :
593  result_low = 13;
594  break;
595  case 'E' :
596  case 'e' :
597  result_low = 14;
598  break;
599  case 'F' :
600  case 'f' :
601  result_low = 15;
602  break;
603  }
604  return (uint8_t) ((result_high<<4) + result_low);
605 }
606 
607 
617 void
618 deparse_hex(uint8_t str, char *result)
619 {
620  int input_high;
621  int input_low;
622  static char outchr[]=
623  {
624  "0123456789ABCDEF"
625  };
626 
627  input_high = (str>>4);
628  input_low = (str & 0x0F);
629 
630  result[0] = outchr[input_high];
631  result[1] = outchr[input_low];
632 
633 }
634 
635 
649 void
650 interpolate_point4d(const POINT4D *A, const POINT4D *B, POINT4D *I, double F)
651 {
652 #if PARANOIA_LEVEL > 0
653  if (F < 0 || F > 1) lwerror("interpolate_point4d: invalid F (%g)", F);
654 #endif
655  I->x=A->x+((B->x-A->x)*F);
656  I->y=A->y+((B->y-A->y)*F);
657  I->z=A->z+((B->z-A->z)*F);
658  I->m=A->m+((B->m-A->m)*F);
659 }
660 
661 
663 void
666 }
667 void
670 }
671 
677  return old;
678 }
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:267
#define LIBLWGEOM_VERSION
liblwgeom versions
Definition: liblwgeom.h:97
#define LW_FALSE
Definition: liblwgeom.h:109
void() lwinterrupt_callback()
Install a callback to be called periodically during algorithm execution.
Definition: liblwgeom.h:306
#define FLAGS_GET_Z(flags)
Definition: liblwgeom.h:180
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:194
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:181
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:195
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:108
#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:618
POINT4D getPoint4d(const POINTARRAY *pa, uint32_t n)
Definition: lwgeom_api.c:108
lwinterrupt_callback * _lwgeom_interrupt_callback
Definition: lwgeom_api.c:672
const char * lwgeom_version()
Return lwgeom version string (not to be freed)
Definition: lwgeom_api.c:39
void lwgeom_cancel_interrupt()
Cancel any interruption request.
Definition: lwgeom_api.c:668
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:650
POINT3DM getPoint3dm(const POINTARRAY *pa, uint32_t n)
Definition: lwgeom_api.c:202
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *op)
Definition: lwgeom_api.c:126
int _lwgeom_interrupt_requested
Definition: lwgeom_api.c:662
void printPA(POINTARRAY *pa)
Definition: lwgeom_api.c:441
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
Definition: lwgeom_api.c:343
void printBOX3D(BOX3D *box)
Definition: lwgeom_api.c:435
void lwgeom_request_interrupt()
Request interruption of any running code.
Definition: lwgeom_api.c:664
lwinterrupt_callback * lwgeom_register_interrupt_callback(lwinterrupt_callback *cb)
Definition: lwgeom_api.c:674
POINT3DZ getPoint3dz(const POINTARRAY *pa, uint32_t n)
Definition: lwgeom_api.c:188
POINT2D getPoint2d(const POINTARRAY *pa, uint32_t n)
Definition: lwgeom_api.c:329
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:483
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:269
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
Definition: lwgeom_api.c:370
void ptarray_copy_point(POINTARRAY *pa, uint32_t from, uint32_t to)
Definition: lwgeom_api.c:395
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:216
#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 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:101
static size_t ptarray_point_size(const POINTARRAY *pa)
Definition: lwinline.h:58
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: lwinline.h:77
double xmax
Definition: liblwgeom.h:355
double ymax
Definition: liblwgeom.h:355
double ymin
Definition: liblwgeom.h:354
double xmin
Definition: liblwgeom.h:354
double m
Definition: liblwgeom.h:423
double z
Definition: liblwgeom.h:411
double m
Definition: liblwgeom.h:429
double x
Definition: liblwgeom.h:429
double z
Definition: liblwgeom.h:429
double y
Definition: liblwgeom.h:429
lwflags_t flags
Definition: liblwgeom.h:446
uint32_t npoints
Definition: liblwgeom.h:442