PostGIS  2.5.0beta2dev-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 <errno.h>
33 #include <assert.h>
34 #include "../postgis_svn_revision.h"
35 
36 const char *
38 {
39  static char *ptr = NULL;
40  static char buf[256];
41  if ( ! ptr )
42  {
43  ptr = buf;
44  snprintf(ptr, 256, LIBLWGEOM_VERSION" r%d", POSTGIS_SVN_REVISION);
45  }
46 
47  return ptr;
48 }
49 
50 
51 inline float
53 {
54  float result = d;
55 
56  if ( ((double)result) <=d )
57  return result;
58 
59  return nextafterf(result, -1*FLT_MAX);
60 
61 }
62 
63 /*
64  * Returns the float that's very close to the input, but >=.
65  * handles the funny differences in float4 and float8 reps.
66  */
67 inline float
69 {
70  float result = d;
71 
72  if ( ((double)result) >=d )
73  return result;
74 
75  return nextafterf(result, FLT_MAX);
76 }
77 
78 
79 
80 
81 /************************************************************************
82  * POINTARRAY support functions
83  *
84  * TODO: should be moved to ptarray.c probably
85  *
86  ************************************************************************/
87 
88 /*
89  * Copies a point from the point array into the parameter point
90  * will set point's z=NO_Z_VALUE if pa is 2d
91  * will set point's m=NO_M_VALUE if pa is 3d or 2d
92  *
93  * NOTE: point is a real POINT3D *not* a pointer
94  */
95 POINT4D
97 {
98  POINT4D result;
99  getPoint4d_p(pa, n, &result);
100  return result;
101 }
102 
103 /*
104  * Copies a point from the point array into the parameter point
105  * will set point's z=NO_Z_VALUE if pa is 2d
106  * will set point's m=NO_M_VALUE if pa is 3d or 2d
107  *
108  * NOTE: this will modify the point4d pointed to by 'point'.
109  *
110  * @return 0 on error, 1 on success
111  */
112 int
114 {
115  uint8_t *ptr;
116  int zmflag;
117 
118  if ( ! pa )
119  {
120  lwerror("%s [%d] NULL POINTARRAY input", __FILE__, __LINE__);
121  return 0;
122  }
123 
124  if ( n>=pa->npoints )
125  {
126  lwnotice("%s [%d] called with n=%d and npoints=%d", __FILE__, __LINE__, n, pa->npoints);
127  return 0;
128  }
129 
130  LWDEBUG(4, "getPoint4d_p called.");
131 
132  /* Get a pointer to nth point offset and zmflag */
133  ptr=getPoint_internal(pa, n);
134  zmflag=FLAGS_GET_ZM(pa->flags);
135 
136  LWDEBUGF(4, "ptr %p, zmflag %d", ptr, zmflag);
137 
138  switch (zmflag)
139  {
140  case 0: /* 2d */
141  memcpy(op, ptr, sizeof(POINT2D));
142  op->m=NO_M_VALUE;
143  op->z=NO_Z_VALUE;
144  break;
145 
146  case 3: /* ZM */
147  memcpy(op, ptr, sizeof(POINT4D));
148  break;
149 
150  case 2: /* Z */
151  memcpy(op, ptr, sizeof(POINT3DZ));
152  op->m=NO_M_VALUE;
153  break;
154 
155  case 1: /* M */
156  memcpy(op, ptr, sizeof(POINT3DM));
157  op->m=op->z; /* we use Z as temporary storage */
158  op->z=NO_Z_VALUE;
159  break;
160 
161  default:
162  lwerror("Unknown ZM flag ??");
163  return 0;
164  }
165  return 1;
166 
167 }
168 
169 
170 
171 /*
172  * Copy a point from the point array into the parameter point
173  * will set point's z=NO_Z_VALUE if pa is 2d
174  * NOTE: point is a real POINT3DZ *not* a pointer
175  */
176 POINT3DZ
178 {
179  POINT3DZ result;
180  getPoint3dz_p(pa, n, &result);
181  return result;
182 }
183 
184 /*
185  * Copy a point from the point array into the parameter point
186  * will set point's z=NO_Z_VALUE if pa is 2d
187  *
188  * NOTE: point is a real POINT3DZ *not* a pointer
189  */
190 POINT3DM
192 {
193  POINT3DM result;
194  getPoint3dm_p(pa, n, &result);
195  return result;
196 }
197 
198 /*
199  * Copy a point from the point array into the parameter point
200  * will set point's z=NO_Z_VALUE if pa is 2d
201  *
202  * NOTE: this will modify the point3dz pointed to by 'point'.
203  */
204 int
206 {
207  uint8_t *ptr;
208 
209  if ( ! pa )
210  {
211  lwerror("%s [%d] NULL POINTARRAY input", __FILE__, __LINE__);
212  return 0;
213  }
214 
215  if ( n>=pa->npoints )
216  {
217  lwnotice("%s [%d] called with n=%d and npoints=%d", __FILE__, __LINE__, n, pa->npoints);
218  return 0;
219  }
220 
221  LWDEBUGF(2, "getPoint3dz_p called on array of %d-dimensions / %u pts",
222  FLAGS_NDIMS(pa->flags), pa->npoints);
223 
224  /* Get a pointer to nth point offset */
225  ptr=getPoint_internal(pa, n);
226 
227  /*
228  * if input POINTARRAY has the Z, it is always
229  * at third position so make a single copy
230  */
231  if ( FLAGS_GET_Z(pa->flags) )
232  {
233  memcpy(op, ptr, sizeof(POINT3DZ));
234  }
235 
236  /*
237  * Otherwise copy the 2d part and initialize
238  * Z to NO_Z_VALUE
239  */
240  else
241  {
242  memcpy(op, ptr, sizeof(POINT2D));
243  op->z=NO_Z_VALUE;
244  }
245 
246  return 1;
247 
248 }
249 
250 /*
251  * Copy a point from the point array into the parameter point
252  * will set point's m=NO_Z_VALUE if pa has no M
253  *
254  * NOTE: this will modify the point3dm pointed to by 'point'.
255  */
256 int
258 {
259  uint8_t *ptr;
260  int zmflag;
261 
262  if ( ! pa )
263  {
264  lwerror("%s [%d] NULL POINTARRAY input", __FILE__, __LINE__);
265  return 0;
266  }
267 
268  if ( n>=pa->npoints )
269  {
270  lwnotice("%s [%d] called with n=%d and npoints=%d", __FILE__, __LINE__, n, pa->npoints);
271  return 0;
272  }
273 
274  LWDEBUGF(2, "getPoint3dm_p(%d) called on array of %d-dimensions / %u pts",
275  n, FLAGS_NDIMS(pa->flags), pa->npoints);
276 
277 
278  /* Get a pointer to nth point offset and zmflag */
279  ptr=getPoint_internal(pa, n);
280  zmflag=FLAGS_GET_ZM(pa->flags);
281 
282  /*
283  * if input POINTARRAY has the M and NO Z,
284  * we can issue a single memcpy
285  */
286  if ( zmflag == 1 )
287  {
288  memcpy(op, ptr, sizeof(POINT3DM));
289  return 1;
290  }
291 
292  /*
293  * Otherwise copy the 2d part and
294  * initialize M to NO_M_VALUE
295  */
296  memcpy(op, ptr, sizeof(POINT2D));
297 
298  /*
299  * Then, if input has Z skip it and
300  * copy next double, otherwise initialize
301  * M to NO_M_VALUE
302  */
303  if ( zmflag == 3 )
304  {
305  ptr+=sizeof(POINT3DZ);
306  memcpy(&(op->m), ptr, sizeof(double));
307  }
308  else
309  {
310  op->m=NO_M_VALUE;
311  }
312 
313  return 1;
314 }
315 
316 
317 /*
318  * Copy a point from the point array into the parameter point
319  * z value (if present) is not returned.
320  *
321  * NOTE: point is a real POINT2D *not* a pointer
322  */
323 POINT2D
325 {
326  const POINT2D *result;
327  result = getPoint2d_cp(pa, n);
328  return *result;
329 }
330 
331 /*
332  * Copy a point from the point array into the parameter point
333  * z value (if present) is not returned.
334  *
335  * NOTE: this will modify the point2d pointed to by 'point'.
336  */
337 int
339 {
340  if ( ! pa )
341  {
342  lwerror("%s [%d] NULL POINTARRAY input", __FILE__, __LINE__);
343  return 0;
344  }
345 
346  if ( n>=pa->npoints )
347  {
348  lwnotice("%s [%d] called with n=%d and npoints=%d", __FILE__, __LINE__, n, pa->npoints);
349  return 0;
350  }
351 
352  /* this does x,y */
353  memcpy(point, getPoint_internal(pa, n), sizeof(POINT2D));
354  return 1;
355 }
356 
363 const POINT2D*
365 {
366  if ( ! pa ) return 0;
367 
368  if ( n>=pa->npoints )
369  {
370  lwerror("getPoint2d_cp: point offset out of range");
371  return 0; /*error */
372  }
373 
374  return (const POINT2D*)getPoint_internal(pa, n);
375 }
376 
377 const POINT3DZ*
379 {
380  if ( ! pa ) return 0;
381 
382  if ( ! FLAGS_GET_Z(pa->flags) )
383  {
384  lwerror("getPoint3dz_cp: no Z coordinates in point array");
385  return 0; /*error */
386  }
387 
388  if ( n>=pa->npoints )
389  {
390  lwerror("getPoint3dz_cp: point offset out of range");
391  return 0; /*error */
392  }
393 
394  return (const POINT3DZ*)getPoint_internal(pa, n);
395 }
396 
397 const POINT4D*
399 {
400  if (!pa) return 0;
401 
402  if (!(FLAGS_GET_Z(pa->flags) && FLAGS_GET_M(pa->flags)))
403  {
404  lwerror("getPoint4d_cp: no Z and M coordinates in point array");
405  return 0; /*error */
406  }
407 
408  if (n >= pa->npoints)
409  {
410  lwerror("getPoint4d_cp: point offset out of range");
411  return 0; /*error */
412  }
413 
414  return (const POINT4D*)getPoint_internal(pa, n);
415 }
416 
417 /*
418  * set point N to the given value
419  * NOTE that the pointarray can be of any
420  * dimension, the appropriate ordinate values
421  * will be extracted from it
422  *
423  */
424 void
426 {
427  uint8_t *ptr;
428  assert(n < pa->npoints);
429  ptr=getPoint_internal(pa, n);
430  switch ( FLAGS_GET_ZM(pa->flags) )
431  {
432  case 3:
433  memcpy(ptr, p4d, sizeof(POINT4D));
434  break;
435  case 2:
436  memcpy(ptr, p4d, sizeof(POINT3DZ));
437  break;
438  case 1:
439  memcpy(ptr, p4d, sizeof(POINT2D));
440  ptr+=sizeof(POINT2D);
441  memcpy(ptr, &(p4d->m), sizeof(double));
442  break;
443  case 0:
444  memcpy(ptr, p4d, sizeof(POINT2D));
445  break;
446  }
447 }
448 
449 void
451 {
452  int ndims = FLAGS_NDIMS(pa->flags);
453  switch (ndims)
454  {
455  case 2:
456  {
457  POINT2D *p_from = (POINT2D*)(getPoint_internal(pa, from));
458  POINT2D *p_to = (POINT2D*)(getPoint_internal(pa, to));
459  *p_to = *p_from;
460  return;
461  }
462  case 3:
463  {
464  POINT3D *p_from = (POINT3D*)(getPoint_internal(pa, from));
465  POINT3D *p_to = (POINT3D*)(getPoint_internal(pa, to));
466  *p_to = *p_from;
467  return;
468  }
469  case 4:
470  {
471  POINT4D *p_from = (POINT4D*)(getPoint_internal(pa, from));
472  POINT4D *p_to = (POINT4D*)(getPoint_internal(pa, to));
473  *p_to = *p_from;
474  return;
475  }
476  default:
477  {
478  lwerror("%s: unsupported number of dimensions - %d", __func__, ndims);
479  return;
480  }
481  }
482  return;
483 }
484 
485 
486 /************************************************
487  * debugging routines
488  ************************************************/
489 
490 void printBOX3D(BOX3D *box)
491 {
492  lwnotice("BOX3D: %g %g, %g %g", box->xmin, box->ymin,
493  box->xmax, box->ymax);
494 }
495 
497 {
498  uint32_t t;
499  POINT4D pt;
500  char *mflag;
501 
502 
503  if ( FLAGS_GET_M(pa->flags) ) mflag = "M";
504  else mflag = "";
505 
506  lwnotice(" POINTARRAY%s{", mflag);
507  lwnotice(" ndims=%i, ptsize=%i",
509  lwnotice(" npoints = %i", pa->npoints);
510 
511  for (t =0; t<pa->npoints; t++)
512  {
513  getPoint4d_p(pa, t, &pt);
514  if (FLAGS_NDIMS(pa->flags) == 2)
515  {
516  lwnotice(" %i : %lf,%lf",t,pt.x,pt.y);
517  }
518  if (FLAGS_NDIMS(pa->flags) == 3)
519  {
520  lwnotice(" %i : %lf,%lf,%lf",t,pt.x,pt.y,pt.z);
521  }
522  if (FLAGS_NDIMS(pa->flags) == 4)
523  {
524  lwnotice(" %i : %lf,%lf,%lf,%lf",t,pt.x,pt.y,pt.z,pt.m);
525  }
526  }
527 
528  lwnotice(" }");
529 }
530 
531 
536 uint8_t
537 parse_hex(char *str)
538 {
539  /* do this a little brute force to make it faster */
540 
541  uint8_t result_high = 0;
542  uint8_t result_low = 0;
543 
544  switch (str[0])
545  {
546  case '0' :
547  result_high = 0;
548  break;
549  case '1' :
550  result_high = 1;
551  break;
552  case '2' :
553  result_high = 2;
554  break;
555  case '3' :
556  result_high = 3;
557  break;
558  case '4' :
559  result_high = 4;
560  break;
561  case '5' :
562  result_high = 5;
563  break;
564  case '6' :
565  result_high = 6;
566  break;
567  case '7' :
568  result_high = 7;
569  break;
570  case '8' :
571  result_high = 8;
572  break;
573  case '9' :
574  result_high = 9;
575  break;
576  case 'A' :
577  case 'a' :
578  result_high = 10;
579  break;
580  case 'B' :
581  case 'b' :
582  result_high = 11;
583  break;
584  case 'C' :
585  case 'c' :
586  result_high = 12;
587  break;
588  case 'D' :
589  case 'd' :
590  result_high = 13;
591  break;
592  case 'E' :
593  case 'e' :
594  result_high = 14;
595  break;
596  case 'F' :
597  case 'f' :
598  result_high = 15;
599  break;
600  }
601  switch (str[1])
602  {
603  case '0' :
604  result_low = 0;
605  break;
606  case '1' :
607  result_low = 1;
608  break;
609  case '2' :
610  result_low = 2;
611  break;
612  case '3' :
613  result_low = 3;
614  break;
615  case '4' :
616  result_low = 4;
617  break;
618  case '5' :
619  result_low = 5;
620  break;
621  case '6' :
622  result_low = 6;
623  break;
624  case '7' :
625  result_low = 7;
626  break;
627  case '8' :
628  result_low = 8;
629  break;
630  case '9' :
631  result_low = 9;
632  break;
633  case 'A' :
634  case 'a' :
635  result_low = 10;
636  break;
637  case 'B' :
638  case 'b' :
639  result_low = 11;
640  break;
641  case 'C' :
642  case 'c' :
643  result_low = 12;
644  break;
645  case 'D' :
646  case 'd' :
647  result_low = 13;
648  break;
649  case 'E' :
650  case 'e' :
651  result_low = 14;
652  break;
653  case 'F' :
654  case 'f' :
655  result_low = 15;
656  break;
657  }
658  return (uint8_t) ((result_high<<4) + result_low);
659 }
660 
661 
671 void
672 deparse_hex(uint8_t str, char *result)
673 {
674  int input_high;
675  int input_low;
676  static char outchr[]=
677  {
678  "0123456789ABCDEF"
679  };
680 
681  input_high = (str>>4);
682  input_low = (str & 0x0F);
683 
684  result[0] = outchr[input_high];
685  result[1] = outchr[input_low];
686 
687 }
688 
689 
703 void
704 interpolate_point4d(const POINT4D *A, const POINT4D *B, POINT4D *I, double F)
705 {
706 #if PARANOIA_LEVEL > 0
707  if (F < 0 || F > 1) lwerror("interpolate_point4d: invalid F (%g)", F);
708 #endif
709  I->x=A->x+((B->x-A->x)*F);
710  I->y=A->y+((B->y-A->y)*F);
711  I->z=A->z+((B->z-A->z)*F);
712  I->m=A->m+((B->m-A->m)*F);
713 }
714 
715 
717 void
720 }
721 void
724 }
725 
731  return old;
732 }
double x
Definition: liblwgeom.h:354
size_t ptarray_point_size(const POINTARRAY *pa)
Definition: ptarray.c:54
double z
Definition: liblwgeom.h:336
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:704
double m
Definition: liblwgeom.h:354
void lwgeom_request_interrupt()
Request interruption of any running code.
Definition: lwgeom_api.c:718
int _lwgeom_interrupt_requested
Definition: lwgeom_api.c:716
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:177
POINT2D getPoint2d(const POINTARRAY *pa, uint32_t n)
Definition: lwgeom_api.c:324
const POINT3DZ * getPoint3dz_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT3DZ pointer into the POINTARRAY serialized_ptlist, suitable for reading from...
Definition: lwgeom_api.c:378
void() lwinterrupt_callback()
Install a callback to be called periodically during algorithm execution.
Definition: liblwgeom.h:266
float next_float_down(double d)
Definition: lwgeom_api.c:52
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:152
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
#define LIBLWGEOM_VERSION
liblwgeom versions
Definition: liblwgeom.h:64
void lwgeom_cancel_interrupt()
Cancel any interruption request.
Definition: lwgeom_api.c:722
int getPoint3dz_p(const POINTARRAY *pa, uint32_t n, POINT3DZ *op)
Definition: lwgeom_api.c:205
double ymin
Definition: liblwgeom.h:279
unsigned int uint32_t
Definition: uthash.h:78
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
Definition: lwgeom_api.c:338
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *op)
Definition: lwgeom_api.c:113
const char * lwgeom_version()
Return lwgeom version string (not to be freed)
Definition: lwgeom_api.c:37
POINT3DZ getPoint3dz(const POINTARRAY *pa, uint32_t n)
Definition: lwgeom_api.c:177
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:537
double xmin
Definition: liblwgeom.h:279
double m
Definition: liblwgeom.h:348
uint8_t flags
Definition: liblwgeom.h:371
void printBOX3D(BOX3D *box)
Definition: lwgeom_api.c:490
const POINT4D * getPoint4d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT4D pointer into the POINTARRAY serialized_ptlist, suitable for reading from...
Definition: lwgeom_api.c:398
#define FLAGS_GET_Z(flags)
Macros for manipulating the &#39;flags&#39; byte.
Definition: liblwgeom.h:139
double z
Definition: liblwgeom.h:354
const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition: lwgeom_api.c:364
#define NO_Z_VALUE
int getPoint3dm_p(const POINTARRAY *pa, uint32_t n, POINT3DM *op)
Definition: lwgeom_api.c:257
lwinterrupt_callback * lwgeom_register_interrupt_callback(lwinterrupt_callback *cb)
Definition: lwgeom_api.c:728
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
Definition: lwgeom_api.c:425
double xmax
Definition: liblwgeom.h:280
uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: ptarray.c:1743
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:140
#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:672
float next_float_up(double d)
Definition: lwgeom_api.c:68
void printPA(POINTARRAY *pa)
Definition: lwgeom_api.c:496
double y
Definition: liblwgeom.h:354
double ymax
Definition: liblwgeom.h:280
POINT3DM getPoint3dm(const POINTARRAY *pa, uint32_t n)
Definition: lwgeom_api.c:191
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:151
unsigned char uint8_t
Definition: uthash.h:79
lwinterrupt_callback * _lwgeom_interrupt_callback
Definition: lwgeom_api.c:726
void ptarray_copy_point(POINTARRAY *pa, uint32_t from, uint32_t to)
Definition: lwgeom_api.c:450
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
POINT4D getPoint4d(const POINTARRAY *pa, uint32_t n)
Definition: lwgeom_api.c:96
uint32_t npoints
Definition: liblwgeom.h:373