PostGIS  3.0.6dev-r@@SVN_REVISION@@
lwalgorithm.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 2008 Paul Ramsey
22  *
23  **********************************************************************/
24 
25 
26 #include "liblwgeom_internal.h"
27 #include "lwgeom_log.h"
28 #include <ctype.h> /* for tolower */
29 #include <stdbool.h>
30 
31 int
32 p4d_same(const POINT4D *p1, const POINT4D *p2)
33 {
34  if( FP_EQUALS(p1->x,p2->x) && FP_EQUALS(p1->y,p2->y) && FP_EQUALS(p1->z,p2->z) && FP_EQUALS(p1->m,p2->m) )
35  return LW_TRUE;
36  else
37  return LW_FALSE;
38 }
39 
40 int
41 p3d_same(const POINT3D *p1, const POINT3D *p2)
42 {
43  if( FP_EQUALS(p1->x,p2->x) && FP_EQUALS(p1->y,p2->y) && FP_EQUALS(p1->z,p2->z) )
44  return LW_TRUE;
45  else
46  return LW_FALSE;
47 }
48 
49 int
50 p2d_same(const POINT2D *p1, const POINT2D *p2)
51 {
52  if( FP_EQUALS(p1->x,p2->x) && FP_EQUALS(p1->y,p2->y) )
53  return LW_TRUE;
54  else
55  return LW_FALSE;
56 }
57 
65 int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
66 {
67  double side = ( (q->x - p1->x) * (p2->y - p1->y) - (p2->x - p1->x) * (q->y - p1->y) );
68  return SIGNUM(side);
69 }
70 
74 double
75 lw_seg_length(const POINT2D *A1, const POINT2D *A2)
76 {
77  return sqrt((A1->x-A2->x)*(A1->x-A2->x)+(A1->y-A2->y)*(A1->y-A2->y));
78 }
79 
85 int
86 lw_pt_in_arc(const POINT2D *P, const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
87 {
88  return lw_segment_side(A1, A3, A2) == lw_segment_side(A1, A3, P);
89 }
90 
95 int
96 lw_pt_in_seg(const POINT2D *P, const POINT2D *A1, const POINT2D *A2)
97 {
98  return ((A1->x <= P->x && P->x < A2->x) || (A1->x >= P->x && P->x > A2->x)) ||
99  ((A1->y <= P->y && P->y < A2->y) || (A1->y >= P->y && P->y > A2->y));
100 }
101 
105 int
106 lw_arc_is_pt(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
107 {
108  if ( A1->x == A2->x && A2->x == A3->x &&
109  A1->y == A2->y && A2->y == A3->y )
110  return LW_TRUE;
111  else
112  return LW_FALSE;
113 }
114 
118 double
119 lw_arc_length(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
120 {
121  POINT2D C;
122  double radius_A, circumference_A;
123  int a2_side, clockwise;
124  double a1, a3;
125  double angle;
126 
127  if ( lw_arc_is_pt(A1, A2, A3) )
128  return 0.0;
129 
130  radius_A = lw_arc_center(A1, A2, A3, &C);
131 
132  /* Co-linear! Return linear distance! */
133  if ( radius_A < 0 )
134  {
135  double dx = A1->x - A3->x;
136  double dy = A1->y - A3->y;
137  return sqrt(dx*dx + dy*dy);
138  }
139 
140  /* Closed circle! Return the circumference! */
141  circumference_A = M_PI * 2 * radius_A;
142  if ( p2d_same(A1, A3) )
143  return circumference_A;
144 
145  /* Determine the orientation of the arc */
146  a2_side = lw_segment_side(A1, A3, A2);
147 
148  /* The side of the A1/A3 line that A2 falls on dictates the sweep
149  direction from A1 to A3. */
150  if ( a2_side == -1 )
151  clockwise = LW_TRUE;
152  else
153  clockwise = LW_FALSE;
154 
155  /* Angles of each point that defines the arc section */
156  a1 = atan2(A1->y - C.y, A1->x - C.x);
157  a3 = atan2(A3->y - C.y, A3->x - C.x);
158 
159  /* What's the sweep from A1 to A3? */
160  if ( clockwise )
161  {
162  if ( a1 > a3 )
163  angle = a1 - a3;
164  else
165  angle = 2*M_PI + a1 - a3;
166  }
167  else
168  {
169  if ( a3 > a1 )
170  angle = a3 - a1;
171  else
172  angle = 2*M_PI + a3 - a1;
173  }
174 
175  /* Length as proportion of circumference */
176  return circumference_A * (angle / (2*M_PI));
177 }
178 
179 int lw_arc_side(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, const POINT2D *Q)
180 {
181  POINT2D C;
182  double radius_A;
183  double side_Q, side_A2;
184  double d;
185 
186  side_Q = lw_segment_side(A1, A3, Q);
187  radius_A = lw_arc_center(A1, A2, A3, &C);
188  side_A2 = lw_segment_side(A1, A3, A2);
189 
190  /* Linear case */
191  if ( radius_A < 0 )
192  return side_Q;
193 
194  d = distance2d_pt_pt(Q, &C);
195 
196  /* Q is on the arc boundary */
197  if ( d == radius_A && side_Q == side_A2 )
198  {
199  return 0;
200  }
201 
202  /* Q on A1-A3 line, so its on opposite side to A2 */
203  if ( side_Q == 0 )
204  {
205  return -1 * side_A2;
206  }
207 
208  /*
209  * Q is inside the arc boundary, so it's not on the side we
210  * might think from examining only the end points
211  */
212  if ( d < radius_A && side_Q == side_A2 )
213  {
214  side_Q *= -1;
215  }
216 
217  return side_Q;
218 }
219 
228 double
229 lw_arc_center(const POINT2D *p1, const POINT2D *p2, const POINT2D *p3, POINT2D *result)
230 {
231  POINT2D c;
232  double cx, cy, cr;
233  double dx21, dy21, dx31, dy31, h21, h31, d;
234 
235  c.x = c.y = 0.0;
236 
237  LWDEBUGF(2, "lw_arc_center called (%.16f,%.16f), (%.16f,%.16f), (%.16f,%.16f).", p1->x, p1->y, p2->x, p2->y, p3->x, p3->y);
238 
239  /* Closed circle */
240  if (fabs(p1->x - p3->x) < EPSILON_SQLMM &&
241  fabs(p1->y - p3->y) < EPSILON_SQLMM)
242  {
243  cx = p1->x + (p2->x - p1->x) / 2.0;
244  cy = p1->y + (p2->y - p1->y) / 2.0;
245  c.x = cx;
246  c.y = cy;
247  *result = c;
248  cr = sqrt(pow(cx - p1->x, 2.0) + pow(cy - p1->y, 2.0));
249  return cr;
250  }
251 
252  /* Using cartesian eguations from page https://en.wikipedia.org/wiki/Circumscribed_circle */
253  dx21 = p2->x - p1->x;
254  dy21 = p2->y - p1->y;
255  dx31 = p3->x - p1->x;
256  dy31 = p3->y - p1->y;
257 
258  h21 = pow(dx21, 2.0) + pow(dy21, 2.0);
259  h31 = pow(dx31, 2.0) + pow(dy31, 2.0);
260 
261  /* 2 * |Cross product|, d<0 means clockwise and d>0 counterclockwise sweeping angle */
262  d = 2 * (dx21 * dy31 - dx31 * dy21);
263 
264  /* Check colinearity, |Cross product| = 0 */
265  if (fabs(d) < EPSILON_SQLMM)
266  return -1.0;
267 
268  /* Calculate centroid coordinates and radius */
269  cx = p1->x + (h21 * dy31 - h31 * dy21) / d;
270  cy = p1->y - (h21 * dx31 - h31 * dx21) / d;
271  c.x = cx;
272  c.y = cy;
273  *result = c;
274  cr = sqrt(pow(cx - p1->x, 2) + pow(cy - p1->y, 2));
275 
276  LWDEBUGF(2, "lw_arc_center center is (%.16f,%.16f)", result->x, result->y);
277 
278  return cr;
279 }
280 
281 int
282 pt_in_ring_2d(const POINT2D *p, const POINTARRAY *ring)
283 {
284  int cn = 0; /* the crossing number counter */
285  uint32_t i;
286  const POINT2D *v1, *v2;
287  const POINT2D *first, *last;
288 
289  first = getPoint2d_cp(ring, 0);
290  last = getPoint2d_cp(ring, ring->npoints-1);
291  if ( memcmp(first, last, sizeof(POINT2D)) )
292  {
293  lwerror("pt_in_ring_2d: V[n] != V[0] (%g %g != %g %g)",
294  first->x, first->y, last->x, last->y);
295  return LW_FALSE;
296 
297  }
298 
299  LWDEBUGF(2, "pt_in_ring_2d called with point: %g %g", p->x, p->y);
300  /* printPA(ring); */
301 
302  /* loop through all edges of the polygon */
303  v1 = getPoint2d_cp(ring, 0);
304  for (i=0; i<ring->npoints-1; i++)
305  {
306  double vt;
307  v2 = getPoint2d_cp(ring, i+1);
308 
309  /* edge from vertex i to vertex i+1 */
310  if
311  (
312  /* an upward crossing */
313  ((v1->y <= p->y) && (v2->y > p->y))
314  /* a downward crossing */
315  || ((v1->y > p->y) && (v2->y <= p->y))
316  )
317  {
318 
319  vt = (double)(p->y - v1->y) / (v2->y - v1->y);
320 
321  /* P->x <intersect */
322  if (p->x < v1->x + vt * (v2->x - v1->x))
323  {
324  /* a valid crossing of y=p->y right of p->x */
325  ++cn;
326  }
327  }
328  v1 = v2;
329  }
330 
331  LWDEBUGF(3, "pt_in_ring_2d returning %d", cn&1);
332 
333  return (cn&1); /* 0 if even (out), and 1 if odd (in) */
334 }
335 
336 
337 static int
338 lw_seg_interact(const POINT2D *p1, const POINT2D *p2, const POINT2D *q1, const POINT2D *q2)
339 {
340  double minq=FP_MIN(q1->x,q2->x);
341  double maxq=FP_MAX(q1->x,q2->x);
342  double minp=FP_MIN(p1->x,p2->x);
343  double maxp=FP_MAX(p1->x,p2->x);
344 
345  if (FP_GT(minp,maxq) || FP_LT(maxp,minq))
346  return LW_FALSE;
347 
348  minq=FP_MIN(q1->y,q2->y);
349  maxq=FP_MAX(q1->y,q2->y);
350  minp=FP_MIN(p1->y,p2->y);
351  maxp=FP_MAX(p1->y,p2->y);
352 
353  if (FP_GT(minp,maxq) || FP_LT(maxp,minq))
354  return LW_FALSE;
355 
356  return LW_TRUE;
357 }
358 
373 int lw_segment_intersects(const POINT2D *p1, const POINT2D *p2, const POINT2D *q1, const POINT2D *q2)
374 {
375 
376  int pq1, pq2, qp1, qp2;
377 
378  /* No envelope interaction => we are done. */
379  if (!lw_seg_interact(p1, p2, q1, p2))
380  {
381  return SEG_NO_INTERSECTION;
382  }
383 
384  /* Are the start and end points of q on the same side of p? */
385  pq1=lw_segment_side(p1,p2,q1);
386  pq2=lw_segment_side(p1,p2,q2);
387  if ((pq1>0 && pq2>0) || (pq1<0 && pq2<0))
388  {
389  return SEG_NO_INTERSECTION;
390  }
391 
392  /* Are the start and end points of p on the same side of q? */
393  qp1=lw_segment_side(q1,q2,p1);
394  qp2=lw_segment_side(q1,q2,p2);
395  if ( (qp1 > 0.0 && qp2 > 0.0) || (qp1 < 0.0 && qp2 < 0.0) )
396  {
397  return SEG_NO_INTERSECTION;
398  }
399 
400  /* Nobody is on one side or another? Must be colinear. */
401  if ( pq1 == 0.0 && pq2 == 0.0 && qp1 == 0.0 && qp2 == 0.0 )
402  {
403  return SEG_COLINEAR;
404  }
405 
406  /*
407  ** When one end-point touches, the sidedness is determined by the
408  ** location of the other end-point. Only touches by the first point
409  ** will be considered "real" to avoid double counting.
410  */
411  LWDEBUGF(4, "pq1=%.15g pq2=%.15g", pq1, pq2);
412  LWDEBUGF(4, "qp1=%.15g qp2=%.15g", qp1, qp2);
413 
414  /* Second point of p or q touches, it's not a crossing. */
415  if ( pq2 == 0 || qp2 == 0 )
416  {
417  return SEG_NO_INTERSECTION;
418  }
419 
420  /* First point of p touches, it's a "crossing". */
421  if ( pq1 == 0 )
422  {
423  if ( pq2 > 0 )
424  return SEG_CROSS_RIGHT;
425  else
426  return SEG_CROSS_LEFT;
427  }
428 
429  /* First point of q touches, it's a crossing. */
430  if ( qp1 == 0 )
431  {
432  if ( pq1 < pq2 )
433  return SEG_CROSS_RIGHT;
434  else
435  return SEG_CROSS_LEFT;
436  }
437 
438  /* The segments cross, what direction is the crossing? */
439  if ( pq1 < pq2 )
440  return SEG_CROSS_RIGHT;
441  else
442  return SEG_CROSS_LEFT;
443 
444  /* This should never happen! */
445  return SEG_ERROR;
446 }
447 
462 int lwline_crossing_direction(const LWLINE *l1, const LWLINE *l2)
463 {
464  uint32_t i = 0, j = 0;
465  const POINT2D *p1, *p2, *q1, *q2;
466  POINTARRAY *pa1 = NULL, *pa2 = NULL;
467  int cross_left = 0;
468  int cross_right = 0;
469  int first_cross = 0;
470  int this_cross = 0;
471 #if POSTGIS_DEBUG_LEVEL >= 4
472  char *geom_ewkt;
473 #endif
474 
475  pa1 = (POINTARRAY*)l1->points;
476  pa2 = (POINTARRAY*)l2->points;
477 
478  /* One-point lines can't intersect (and shouldn't exist). */
479  if ( pa1->npoints < 2 || pa2->npoints < 2 )
480  return LINE_NO_CROSS;
481 
482  /* Zero length lines don't have a side. */
483  if ( ptarray_length_2d(pa1) == 0 || ptarray_length_2d(pa2) == 0 )
484  return LINE_NO_CROSS;
485 
486 
487 #if POSTGIS_DEBUG_LEVEL >= 4
488  geom_ewkt = lwgeom_to_ewkt((LWGEOM*)l1);
489  LWDEBUGF(4, "l1 = %s", geom_ewkt);
490  lwfree(geom_ewkt);
491  geom_ewkt = lwgeom_to_ewkt((LWGEOM*)l2);
492  LWDEBUGF(4, "l2 = %s", geom_ewkt);
493  lwfree(geom_ewkt);
494 #endif
495 
496  /* Initialize first point of q */
497  q1 = getPoint2d_cp(pa2, 0);
498 
499  for ( i = 1; i < pa2->npoints; i++ )
500  {
501 
502  /* Update second point of q to next value */
503  q2 = getPoint2d_cp(pa2, i);
504 
505  /* Initialize first point of p */
506  p1 = getPoint2d_cp(pa1, 0);
507 
508  for ( j = 1; j < pa1->npoints; j++ )
509  {
510 
511  /* Update second point of p to next value */
512  p2 = getPoint2d_cp(pa1, j);
513 
514  this_cross = lw_segment_intersects(p1, p2, q1, q2);
515 
516  LWDEBUGF(4, "i=%d, j=%d (%.8g %.8g, %.8g %.8g)", this_cross, i, j, p1->x, p1->y, p2->x, p2->y);
517 
518  if ( this_cross == SEG_CROSS_LEFT )
519  {
520  LWDEBUG(4,"this_cross == SEG_CROSS_LEFT");
521  cross_left++;
522  if ( ! first_cross )
523  first_cross = SEG_CROSS_LEFT;
524  }
525 
526  if ( this_cross == SEG_CROSS_RIGHT )
527  {
528  LWDEBUG(4,"this_cross == SEG_CROSS_RIGHT");
529  cross_right++;
530  if ( ! first_cross )
531  first_cross = SEG_CROSS_RIGHT;
532  }
533 
534  /*
535  ** Crossing at a co-linearity can be turned handled by extending
536  ** segment to next vertex and seeing if the end points straddle
537  ** the co-linear segment.
538  */
539  if ( this_cross == SEG_COLINEAR )
540  {
541  LWDEBUG(4,"this_cross == SEG_COLINEAR");
542  /* TODO: Add logic here and in segment_intersects()
543  continue;
544  */
545  }
546 
547  LWDEBUG(4,"this_cross == SEG_NO_INTERSECTION");
548 
549  /* Turn second point of p into first point */
550  p1 = p2;
551 
552  }
553 
554  /* Turn second point of q into first point */
555  q1 = q2;
556 
557  }
558 
559  LWDEBUGF(4, "first_cross=%d, cross_left=%d, cross_right=%d", first_cross, cross_left, cross_right);
560 
561  if ( !cross_left && !cross_right )
562  return LINE_NO_CROSS;
563 
564  if ( !cross_left && cross_right == 1 )
565  return LINE_CROSS_RIGHT;
566 
567  if ( !cross_right && cross_left == 1 )
568  return LINE_CROSS_LEFT;
569 
570  if ( cross_left - cross_right == 1 )
572 
573  if ( cross_left - cross_right == -1 )
575 
576  if ( cross_left - cross_right == 0 && first_cross == SEG_CROSS_LEFT )
578 
579  if ( cross_left - cross_right == 0 && first_cross == SEG_CROSS_RIGHT )
581 
582  return LINE_NO_CROSS;
583 
584 }
585 
586 
587 
588 
589 
590 static char *base32 = "0123456789bcdefghjkmnpqrstuvwxyz";
591 
592 /*
593 ** Calculate the geohash, iterating downwards and gaining precision.
594 ** From geohash-native.c, (c) 2008 David Troy <dave@roundhousetech.com>
595 ** Released under the MIT License.
596 */
597 char *geohash_point(double longitude, double latitude, int precision)
598 {
599  int is_even=1, i=0;
600  double lat[2], lon[2], mid;
601  char bits[] = {16,8,4,2,1};
602  int bit=0, ch=0;
603  char *geohash = NULL;
604 
605  geohash = lwalloc(precision + 1);
606 
607  lat[0] = -90.0;
608  lat[1] = 90.0;
609  lon[0] = -180.0;
610  lon[1] = 180.0;
611 
612  while (i < precision)
613  {
614  if (is_even)
615  {
616  mid = (lon[0] + lon[1]) / 2;
617  if (longitude >= mid)
618  {
619  ch |= bits[bit];
620  lon[0] = mid;
621  }
622  else
623  {
624  lon[1] = mid;
625  }
626  }
627  else
628  {
629  mid = (lat[0] + lat[1]) / 2;
630  if (latitude >= mid)
631  {
632  ch |= bits[bit];
633  lat[0] = mid;
634  }
635  else
636  {
637  lat[1] = mid;
638  }
639  }
640 
641  is_even = !is_even;
642  if (bit < 4)
643  {
644  bit++;
645  }
646  else
647  {
648  geohash[i++] = base32[ch];
649  bit = 0;
650  ch = 0;
651  }
652  }
653  geohash[i] = 0;
654  return geohash;
655 }
656 
657 
658 /*
659 ** Calculate the geohash, iterating downwards and gaining precision.
660 ** From geohash-native.c, (c) 2008 David Troy <dave@roundhousetech.com>
661 ** Released under the MIT License.
662 */
663 unsigned int geohash_point_as_int(POINT2D *pt)
664 {
665  int is_even=1;
666  double lat[2], lon[2], mid;
667  int bit=32;
668  unsigned int ch = 0;
669 
670  double longitude = pt->x;
671  double latitude = pt->y;
672 
673  lat[0] = -90.0;
674  lat[1] = 90.0;
675  lon[0] = -180.0;
676  lon[1] = 180.0;
677 
678  while (--bit >= 0)
679  {
680  if (is_even)
681  {
682  mid = (lon[0] + lon[1]) / 2;
683  if (longitude > mid)
684  {
685  ch |= 0x0001u << bit;
686  lon[0] = mid;
687  }
688  else
689  {
690  lon[1] = mid;
691  }
692  }
693  else
694  {
695  mid = (lat[0] + lat[1]) / 2;
696  if (latitude > mid)
697  {
698  ch |= 0x0001 << bit;
699  lat[0] = mid;
700  }
701  else
702  {
703  lat[1] = mid;
704  }
705  }
706 
707  is_even = !is_even;
708  }
709  return ch;
710 }
711 
712 /*
713 ** Decode a GeoHash into a bounding box. The lat and lon arguments should
714 ** both be passed as double arrays of length 2 at a minimum where the values
715 ** set in them will be the southwest and northeast coordinates of the bounding
716 ** box accordingly. A precision less than 0 indicates that the entire length
717 ** of the GeoHash should be used.
718 ** It will call `lwerror` if an invalid character is found
719 */
720 void decode_geohash_bbox(char *geohash, double *lat, double *lon, int precision)
721 {
722  bool is_even = 1;
723 
724  lat[0] = -90.0;
725  lat[1] = 90.0;
726  lon[0] = -180.0;
727  lon[1] = 180.0;
728 
729  size_t hashlen = strlen(geohash);
730  if (precision < 0 || (size_t)precision > hashlen)
731  {
732  precision = (int)hashlen;
733  }
734 
735  for (int i = 0; i < precision; i++)
736  {
737  char c = tolower(geohash[i]);
738 
739  /* Valid characters are all digits in base32 */
740  char *base32_pos = strchr(base32, c);
741  if (!base32_pos)
742  {
743  lwerror("%s: Invalid character '%c'", __func__, geohash[i]);
744  return;
745  }
746  char cd = base32_pos - base32;
747 
748  for (size_t j = 0; j < 5; j++)
749  {
750  const char bits[] = {16, 8, 4, 2, 1};
751  char mask = bits[j];
752  if (is_even)
753  {
754  lon[!(cd & mask)] = (lon[0] + lon[1]) / 2;
755  }
756  else
757  {
758  lat[!(cd & mask)] = (lat[0] + lat[1]) / 2;
759  }
760  is_even = !is_even;
761  }
762  }
763 }
764 
766 {
767  double minx, miny, maxx, maxy;
768  double latmax, latmin, lonmax, lonmin;
769  double lonwidth, latwidth;
770  double latmaxadjust, lonmaxadjust, latminadjust, lonminadjust;
771  int precision = 0;
772 
773  /* Get the bounding box, return error if things don't work out. */
774  minx = bbox.xmin;
775  miny = bbox.ymin;
776  maxx = bbox.xmax;
777  maxy = bbox.ymax;
778 
779  if ( minx == maxx && miny == maxy )
780  {
781  /* It's a point. Doubles have 51 bits of precision.
782  ** 2 * 51 / 5 == 20 */
783  return 20;
784  }
785 
786  lonmin = -180.0;
787  latmin = -90.0;
788  lonmax = 180.0;
789  latmax = 90.0;
790 
791  /* Shrink a world bounding box until one of the edges interferes with the
792  ** bounds of our rectangle. */
793  while ( 1 )
794  {
795  lonwidth = lonmax - lonmin;
796  latwidth = latmax - latmin;
797  latmaxadjust = lonmaxadjust = latminadjust = lonminadjust = 0.0;
798 
799  if ( minx > lonmin + lonwidth / 2.0 )
800  {
801  lonminadjust = lonwidth / 2.0;
802  }
803  else if ( maxx < lonmax - lonwidth / 2.0 )
804  {
805  lonmaxadjust = -1 * lonwidth / 2.0;
806  }
807  if ( lonminadjust || lonmaxadjust )
808  {
809  lonmin += lonminadjust;
810  lonmax += lonmaxadjust;
811  /* Each adjustment cycle corresponds to 2 bits of storage in the
812  ** geohash. */
813  precision++;
814  }
815  else
816  {
817  break;
818  }
819 
820  if ( miny > latmin + latwidth / 2.0 )
821  {
822  latminadjust = latwidth / 2.0;
823  }
824  else if (maxy < latmax - latwidth / 2.0 )
825  {
826  latmaxadjust = -1 * latwidth / 2.0;
827  }
828  /* Only adjust if adjustments are legal (we haven't crossed any edges). */
829  if ( latminadjust || latmaxadjust )
830  {
831  latmin += latminadjust;
832  latmax += latmaxadjust;
833  /* Each adjustment cycle corresponds to 2 bits of storage in the
834  ** geohash. */
835  precision++;
836  }
837  else
838  {
839  break;
840  }
841  }
842 
843  /* Save the edges of our bounds, in case someone cares later. */
844  bounds->xmin = lonmin;
845  bounds->xmax = lonmax;
846  bounds->ymin = latmin;
847  bounds->ymax = latmax;
848 
849  /* Each geohash character (base32) can contain 5 bits of information.
850  ** We are returning the precision in characters, so here we divide. */
851  return precision / 5;
852 }
853 
854 
855 /*
856 ** Return a geohash string for the geometry. <http://geohash.org>
857 ** Where the precision is non-positive, calculate a precision based on the
858 ** bounds of the feature. Big features have loose precision.
859 ** Small features have tight precision.
860 */
861 char *lwgeom_geohash(const LWGEOM *lwgeom, int precision)
862 {
863  GBOX gbox;
864  GBOX gbox_bounds;
865  double lat, lon;
866  int result;
867 
868  gbox_init(&gbox);
869  gbox_init(&gbox_bounds);
870 
871  result = lwgeom_calculate_gbox_cartesian(lwgeom, &gbox);
872  if ( result == LW_FAILURE ) return NULL;
873 
874  /* Return error if we are being fed something outside our working bounds */
875  if ( gbox.xmin < -180 || gbox.ymin < -90 || gbox.xmax > 180 || gbox.ymax > 90 )
876  {
877  lwerror("Geohash requires inputs in decimal degrees, got (%g %g, %g %g).",
878  gbox.xmin, gbox.ymin,
879  gbox.xmax, gbox.ymax);
880  return NULL;
881  }
882 
883  /* What is the center of our geometry bounds? We'll use that to
884  ** approximate location. */
885  lon = gbox.xmin + (gbox.xmax - gbox.xmin) / 2;
886  lat = gbox.ymin + (gbox.ymax - gbox.ymin) / 2;
887 
888  if ( precision <= 0 )
889  {
890  precision = lwgeom_geohash_precision(gbox, &gbox_bounds);
891  }
892 
893  /*
894  ** Return the geohash of the center, with a precision determined by the
895  ** extent of the bounds.
896  ** Possible change: return the point at the center of the precision bounds?
897  */
898  return geohash_point(lon, lat, precision);
899 }
static uint8_t precision
Definition: cu_in_twkb.c:25
int lwgeom_calculate_gbox_cartesian(const LWGEOM *lwgeom, GBOX *gbox)
Calculate the 2-4D bounding box of a geometry.
Definition: gbox.c:740
void gbox_init(GBOX *gbox)
Zero out all the entries in the GBOX.
Definition: gbox.c:40
#define LW_FALSE
Definition: liblwgeom.h:108
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition: measures.c:2397
#define LW_FAILURE
Definition: liblwgeom.h:110
double ptarray_length_2d(const POINTARRAY *pts)
Find the 2d length of the given POINTARRAY (even if it's 3d)
Definition: ptarray.c:1700
char * lwgeom_to_ewkt(const LWGEOM *lwgeom)
Return an alloced string.
Definition: lwgeom.c:547
void lwfree(void *mem)
Definition: lwutil.c:242
@ LINE_MULTICROSS_END_RIGHT
Definition: liblwgeom.h:1628
@ LINE_MULTICROSS_END_SAME_FIRST_LEFT
Definition: liblwgeom.h:1629
@ LINE_MULTICROSS_END_LEFT
Definition: liblwgeom.h:1627
@ LINE_CROSS_LEFT
Definition: liblwgeom.h:1625
@ LINE_MULTICROSS_END_SAME_FIRST_RIGHT
Definition: liblwgeom.h:1630
@ LINE_CROSS_RIGHT
Definition: liblwgeom.h:1626
@ LINE_NO_CROSS
Definition: liblwgeom.h:1624
void * lwalloc(size_t size)
Definition: lwutil.c:227
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:107
#define EPSILON_SQLMM
Tolerance used to determine equality.
#define FP_LT(A, B)
#define SIGNUM(n)
Macro that returns: -1 if n < 0, 1 if n > 0, 0 if n == 0.
#define FP_MAX(A, B)
#define FP_MIN(A, B)
@ SEG_NO_INTERSECTION
@ SEG_ERROR
@ SEG_COLINEAR
@ SEG_CROSS_RIGHT
@ SEG_CROSS_LEFT
#define FP_EQUALS(A, B)
#define FP_GT(A, B)
int lwgeom_geohash_precision(GBOX bbox, GBOX *bounds)
Definition: lwalgorithm.c:765
int p4d_same(const POINT4D *p1, const POINT4D *p2)
Definition: lwalgorithm.c:32
int p3d_same(const POINT3D *p1, const POINT3D *p2)
Definition: lwalgorithm.c:41
double lw_arc_length(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns the length of a circular arc segment.
Definition: lwalgorithm.c:119
unsigned int geohash_point_as_int(POINT2D *pt)
Definition: lwalgorithm.c:663
int lwline_crossing_direction(const LWLINE *l1, const LWLINE *l2)
lwline_crossing_direction: returns the kind of CG_LINE_CROSS_TYPE behavior of 2 linestrings
Definition: lwalgorithm.c:462
int lw_segment_intersects(const POINT2D *p1, const POINT2D *p2, const POINT2D *q1, const POINT2D *q2)
returns the kind of CG_SEGMENT_INTERSECTION_TYPE behavior of lineseg 1 (constructed from p1 and p2) a...
Definition: lwalgorithm.c:373
double lw_arc_center(const POINT2D *p1, const POINT2D *p2, const POINT2D *p3, POINT2D *result)
Determines the center of the circle defined by the three given points.
Definition: lwalgorithm.c:229
int pt_in_ring_2d(const POINT2D *p, const POINTARRAY *ring)
Definition: lwalgorithm.c:282
int lw_arc_side(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, const POINT2D *Q)
Definition: lwalgorithm.c:179
char * lwgeom_geohash(const LWGEOM *lwgeom, int precision)
Calculate the GeoHash (http://geohash.org) string for a geometry.
Definition: lwalgorithm.c:861
double lw_seg_length(const POINT2D *A1, const POINT2D *A2)
Returns the length of a linear segment.
Definition: lwalgorithm.c:75
static int lw_seg_interact(const POINT2D *p1, const POINT2D *p2, const POINT2D *q1, const POINT2D *q2)
Definition: lwalgorithm.c:338
int lw_pt_in_seg(const POINT2D *P, const POINT2D *A1, const POINT2D *A2)
Returns true if P is between A1/A2.
Definition: lwalgorithm.c:96
static char * base32
Definition: lwalgorithm.c:590
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
Definition: lwalgorithm.c:65
int lw_arc_is_pt(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns true if arc A is actually a point (all vertices are the same) .
Definition: lwalgorithm.c:106
void decode_geohash_bbox(char *geohash, double *lat, double *lon, int precision)
Definition: lwalgorithm.c:720
int lw_pt_in_arc(const POINT2D *P, const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns true if P is on the same side of the plane partition defined by A1/A3 as A2 is.
Definition: lwalgorithm.c:86
char * geohash_point(double longitude, double latitude, int precision)
Definition: lwalgorithm.c:597
int p2d_same(const POINT2D *p1, const POINT2D *p2)
Definition: lwalgorithm.c:50
#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
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
double ymax
Definition: liblwgeom.h:343
double xmax
Definition: liblwgeom.h:341
double ymin
Definition: liblwgeom.h:342
double xmin
Definition: liblwgeom.h:340
POINTARRAY * points
Definition: liblwgeom.h:469
double y
Definition: liblwgeom.h:376
double x
Definition: liblwgeom.h:376
double z
Definition: liblwgeom.h:388
double x
Definition: liblwgeom.h:388
double y
Definition: liblwgeom.h:388
double m
Definition: liblwgeom.h:400
double x
Definition: liblwgeom.h:400
double z
Definition: liblwgeom.h:400
double y
Definition: liblwgeom.h:400
uint32_t npoints
Definition: liblwgeom.h:413