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