PostGIS  3.7.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 
34 #define xstr(s) str(s)
35 #define str(s) #s
36 
37 const 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 
52 inline float
53 next_float_down(double d)
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  */
73 inline float
74 next_float_up(double d)
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  */
106 POINT4D
107 getPoint4d(const POINTARRAY *pa, uint32_t n)
108 {
109  POINT4D result;
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  */
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  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  */
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 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  */
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  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 
478 uint8_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 
613 void
614 deparse_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 
645 void
646 interpolate_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 
657 void
660 }
661 void
664 }
665 
671  return old;
672 }
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
const char * lwgeom_version()
Return lwgeom version string (not to be freed)
Definition: lwgeom_api.c:38
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
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 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
static size_t ptarray_point_size(const POINTARRAY *pa)
Definition: lwinline.h:56
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: lwinline.h:75
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