PostGIS  3.0.6dev-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  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  */
186 POINT3DZ
187 getPoint3dz(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  */
200 POINT3DM
201 getPoint3dm(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  */
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 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  */
334 POINT2D
335 getPoint2d(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  */
348 int
349 getPoint2d_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  */
375 void
376 ptarray_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 
400 void
401 ptarray_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 
441 void printBOX3D(BOX3D *box)
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 
488 uint8_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 
623 void
624 deparse_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 
655 void
656 interpolate_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 
669 void
672 }
673 void
676 }
677 
683  return old;
684 }
#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
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: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
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 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
static size_t ptarray_point_size(const POINTARRAY *pa)
Definition: lwinline.h:48
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: lwinline.h:67
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