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