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