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