PostGIS  3.4.0dev-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  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  */
124 int
125 getPoint4d_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  LWDEBUGF(2, "%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  */
186 POINT3DZ
187 getPoint3dz(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  */
200 POINT3DM
201 getPoint3dm(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  */
214 int
215 getPoint3dz_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  */
267 int
268 getPoint3dm_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  */
327 POINT2D
328 getPoint2d(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  */
341 int
342 getPoint2d_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  */
368 void
369 ptarray_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 
393 void
394 ptarray_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 
434 void printBOX3D(BOX3D *box)
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 
447  if ( FLAGS_GET_M(pa->flags) ) mflag = "M";
448  else mflag = "";
449 
450  lwnotice(" POINTARRAY%s{", mflag);
451  lwnotice(" ndims=%i, ptsize=%i",
453  lwnotice(" npoints = %i", pa->npoints);
454 
455  if (!pa)
456  {
457  lwnotice(" PTARRAY is null pointer!");
458  }
459  else
460  {
461 
462  for (t = 0; t < pa->npoints; t++)
463  {
464  getPoint4d_p(pa, t, &pt);
465  if (FLAGS_NDIMS(pa->flags) == 2)
466  lwnotice(" %i : %lf,%lf", t, pt.x, pt.y);
467  if (FLAGS_NDIMS(pa->flags) == 3)
468  lwnotice(" %i : %lf,%lf,%lf", t, pt.x, pt.y, pt.z);
469  if (FLAGS_NDIMS(pa->flags) == 4)
470  lwnotice(" %i : %lf,%lf,%lf,%lf", t, pt.x, pt.y, pt.z, pt.m);
471  }
472  }
473  lwnotice(" }");
474 }
475 
476 
481 uint8_t
483 {
484  /* do this a little brute force to make it faster */
485 
486  uint8_t result_high = 0;
487  uint8_t result_low = 0;
488 
489  switch (str[0])
490  {
491  case '0' :
492  result_high = 0;
493  break;
494  case '1' :
495  result_high = 1;
496  break;
497  case '2' :
498  result_high = 2;
499  break;
500  case '3' :
501  result_high = 3;
502  break;
503  case '4' :
504  result_high = 4;
505  break;
506  case '5' :
507  result_high = 5;
508  break;
509  case '6' :
510  result_high = 6;
511  break;
512  case '7' :
513  result_high = 7;
514  break;
515  case '8' :
516  result_high = 8;
517  break;
518  case '9' :
519  result_high = 9;
520  break;
521  case 'A' :
522  case 'a' :
523  result_high = 10;
524  break;
525  case 'B' :
526  case 'b' :
527  result_high = 11;
528  break;
529  case 'C' :
530  case 'c' :
531  result_high = 12;
532  break;
533  case 'D' :
534  case 'd' :
535  result_high = 13;
536  break;
537  case 'E' :
538  case 'e' :
539  result_high = 14;
540  break;
541  case 'F' :
542  case 'f' :
543  result_high = 15;
544  break;
545  }
546  switch (str[1])
547  {
548  case '0' :
549  result_low = 0;
550  break;
551  case '1' :
552  result_low = 1;
553  break;
554  case '2' :
555  result_low = 2;
556  break;
557  case '3' :
558  result_low = 3;
559  break;
560  case '4' :
561  result_low = 4;
562  break;
563  case '5' :
564  result_low = 5;
565  break;
566  case '6' :
567  result_low = 6;
568  break;
569  case '7' :
570  result_low = 7;
571  break;
572  case '8' :
573  result_low = 8;
574  break;
575  case '9' :
576  result_low = 9;
577  break;
578  case 'A' :
579  case 'a' :
580  result_low = 10;
581  break;
582  case 'B' :
583  case 'b' :
584  result_low = 11;
585  break;
586  case 'C' :
587  case 'c' :
588  result_low = 12;
589  break;
590  case 'D' :
591  case 'd' :
592  result_low = 13;
593  break;
594  case 'E' :
595  case 'e' :
596  result_low = 14;
597  break;
598  case 'F' :
599  case 'f' :
600  result_low = 15;
601  break;
602  }
603  return (uint8_t) ((result_high<<4) + result_low);
604 }
605 
606 
616 void
617 deparse_hex(uint8_t str, char *result)
618 {
619  int input_high;
620  int input_low;
621  static char outchr[]=
622  {
623  "0123456789ABCDEF"
624  };
625 
626  input_high = (str>>4);
627  input_low = (str & 0x0F);
628 
629  result[0] = outchr[input_high];
630  result[1] = outchr[input_low];
631 
632 }
633 
634 
648 void
649 interpolate_point4d(const POINT4D *A, const POINT4D *B, POINT4D *I, double F)
650 {
651 #if PARANOIA_LEVEL > 0
652  if (F < 0 || F > 1) lwerror("interpolate_point4d: invalid F (%g)", F);
653 #endif
654  I->x=A->x+((B->x-A->x)*F);
655  I->y=A->y+((B->y-A->y)*F);
656  I->z=A->z+((B->z-A->z)*F);
657  I->m=A->m+((B->m-A->m)*F);
658 }
659 
660 
662 void
665 }
666 void
669 }
670 
676  return old;
677 }
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:262
#define LIBLWGEOM_VERSION
liblwgeom versions
Definition: liblwgeom.h:82
#define LW_FALSE
Definition: liblwgeom.h:94
void() lwinterrupt_callback()
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:617
POINT4D getPoint4d(const POINTARRAY *pa, uint32_t n)
Definition: lwgeom_api.c:108
lwinterrupt_callback * _lwgeom_interrupt_callback
Definition: lwgeom_api.c:671
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:667
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:649
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:661
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
void printBOX3D(BOX3D *box)
Definition: lwgeom_api.c:434
void lwgeom_request_interrupt()
Request interruption of any running code.
Definition: lwgeom_api.c:663
lwinterrupt_callback * lwgeom_register_interrupt_callback(lwinterrupt_callback *cb)
Definition: lwgeom_api.c:673
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:482
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: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: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 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: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