OmniSciDB  a5dc49c757
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ExtensionFunctionsGeo.hpp
Go to the documentation of this file.
3 #include "Geospatial/Types.h"
4 #include "Geospatial/Utm.h"
5 
6 #ifndef __CUDACC__
7 #include <iomanip>
8 #include <string>
9 #include "Shared/likely.h"
10 #else
11 #define LIKELY
12 #define UNLIKELY
13 #endif
14 
15 #ifdef __clang__
16 #pragma clang diagnostic push
17 #pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
18 #endif
19 
20 // #define DEBUG_STMT(x) x;
21 #define DEBUG_STMT(x)
22 
23 namespace {
24 struct CoordData {
25  int8_t* ptr{nullptr};
26  int64_t size{0};
27 };
28 } // namespace
29 
30 // Adjustable tolerance, determined by compression mode.
31 // The criteria is to still recognize a compressed+decompressed number.
32 // For example 1.0 longitude compressed with GEOINT32 and then decompressed
33 // comes back as 0.99999994086101651, which is still within GEOINT32
34 // tolerance val 0.0000001
35 DEVICE ALWAYS_INLINE double tol(int32_t ic) {
36  if (ic == COMPRESSION_GEOINT32) {
37  return TOLERANCE_GEOINT32;
38  }
39  return TOLERANCE_DEFAULT;
40 }
41 
42 // Combine tolerances for two-component calculations
43 DEVICE ALWAYS_INLINE double tol(const int32_t ic1, const int32_t ic2) {
44  return fmax(tol(ic1), tol(ic2));
45 }
46 
47 DEVICE ALWAYS_INLINE bool tol_zero(const double x,
48  const double tolerance = TOLERANCE_DEFAULT) {
49  return (-tolerance <= x) && (x <= tolerance);
50 }
51 
52 DEVICE ALWAYS_INLINE bool tol_eq(const double x,
53  const double y,
54  const double tolerance = TOLERANCE_DEFAULT) {
55  auto diff = x - y;
56  return (-tolerance <= diff) && (diff <= tolerance);
57 }
58 
59 DEVICE ALWAYS_INLINE bool tol_le(const double x,
60  const double y,
61  const double tolerance = TOLERANCE_DEFAULT) {
62  return x <= (y + tolerance);
63 }
64 
65 DEVICE ALWAYS_INLINE bool tol_ge(const double x,
66  const double y,
67  const double tolerance = TOLERANCE_DEFAULT) {
68  return (x + tolerance) >= y;
69 }
70 
71 namespace {
72 enum Coords {
73  None = 0,
74  Y, // 01
75  X, // 10
76  XY // 11
77 };
78 
79 struct Point2D {
80  double x{std::numeric_limits<double>::quiet_NaN()};
81  double y{std::numeric_limits<double>::quiet_NaN()};
82 };
83 } // namespace
84 
85 // x_index is always of the x coordinate, y is assumed to be at x_index + 1.
86 template <Coords C>
87 DEVICE ALWAYS_INLINE double decompress_coord(const int8_t* data,
88  const int32_t x_index,
89  const int32_t ic) {
90  static_assert(C == Coords::X || C == Coords::Y);
91  const int32_t adjusted_index = x_index + (C == Coords::Y);
92  if (ic == COMPRESSION_GEOINT32) {
93  auto compressed_coords = reinterpret_cast<const int32_t*>(data);
94  auto compressed_coord = compressed_coords[adjusted_index];
95  if constexpr (C == Coords::X) {
97  } else {
99  }
100  }
101  auto double_coords = reinterpret_cast<const double*>(data);
102  return double_coords[adjusted_index];
103 }
104 
105 DEVICE ALWAYS_INLINE int32_t compression_unit_size(const int32_t ic) {
106  if (ic == COMPRESSION_GEOINT32) {
107  return 4;
108  }
109  return 8;
110 }
111 
112 template <Coords C>
113 DEVICE ALWAYS_INLINE Point2D conv_4326_900913(const Point2D point) {
114  Point2D retval;
115  if constexpr (static_cast<bool>(C & Coords::X)) {
116  retval.x = conv_4326_900913_x(point.x);
117  }
118  if constexpr (static_cast<bool>(C & Coords::Y)) {
119  retval.y = conv_4326_900913_y(point.y);
120  }
121  return retval;
122 }
123 
124 template <Coords C>
125 DEVICE ALWAYS_INLINE Point2D conv_4326_utm(const Point2D point, const int32_t utm_srid) {
126  Point2D retval;
127  Transform4326ToUTM const utm(utm_srid, point.x, point.y);
128  if constexpr (static_cast<bool>(C & Coords::X)) {
129  retval.x = utm.calculateX();
130  }
131  if constexpr (static_cast<bool>(C & Coords::Y)) {
132  retval.y = utm.calculateY();
133  }
134  return retval;
135 }
136 
137 template <Coords C>
138 DEVICE ALWAYS_INLINE Point2D conv_utm_4326(const Point2D point, const int32_t utm_srid) {
139  Point2D retval;
140  TransformUTMTo4326 const wgs84(utm_srid, point.x, point.y);
141  if constexpr (static_cast<bool>(C & Coords::X)) {
142  retval.x = wgs84.calculateX();
143  }
144  if constexpr (static_cast<bool>(C & Coords::Y)) {
145  retval.y = wgs84.calculateY();
146  }
147  return retval;
148 }
149 
150 // C = Coordinate(s) to calculate.
151 // isr = input SRID
152 // osr = output SRID
153 // return: Point2D where only the coordinates C are calculated.
154 template <Coords C>
155 DEVICE ALWAYS_INLINE Point2D transform_point(const Point2D point,
156  const int32_t isr,
157  const int32_t osr) {
158  if (isr == osr || osr == 0) {
159  return point;
160  } else if (isr == 4326) {
161  if (osr == 900913) {
162  return conv_4326_900913<C>(point); // WGS 84 --> Web Mercator
163 #ifdef ENABLE_UTM_TRANSFORM
164  } else if (is_utm_srid(osr)) {
165  return conv_4326_utm<C>(point, osr); // WGS 84 --> UTM
166  }
167  } else if (is_utm_srid(isr)) {
168  if (osr == 4326) {
169  return conv_utm_4326<C>(point, osr); // UTM --> WGS 84
170 #endif
171  }
172  }
173 #ifdef __CUDACC__
174  return {}; // (NaN,NaN)
175 #else
176  throw std::runtime_error("Unhandled geo transformation from " + std::to_string(isr) +
177  " to " + std::to_string(osr) + '.');
178 #endif
179 }
180 
181 // Return false iff osr(x) depends only on isr(x), and same with y.
182 DEVICE ALWAYS_INLINE bool x_and_y_are_dependent(const int32_t isr, const int32_t osr) {
183 #ifdef ENABLE_UTM_TRANSFORM
184  return isr != osr && (is_utm_srid(isr) || is_utm_srid(osr));
185 #else
186  return false;
187 #endif
188 }
189 
190 // Point2D accessor handling on-the-fly decompression and transforms.
191 // x_index is always of the x coordinate, y is assumed to be at x_index + 1.
192 DEVICE ALWAYS_INLINE Point2D get_point(const int8_t* data,
193  const int32_t x_index,
194  const int32_t ic,
195  const int32_t isr,
196  const int32_t osr) {
197  Point2D const decompressed{decompress_coord<X>(data, x_index, ic),
198  decompress_coord<Y>(data, x_index, ic)};
199  return transform_point<XY>(decompressed, isr, osr);
200 }
201 
202 // Point2D accessor handling on-the-fly decompression and transforms for x or y.
203 // x_index is always of the x coordinate, y is assumed to be at x_index + 1.
204 template <Coords C>
205 DEVICE ALWAYS_INLINE Point2D coord(const int8_t* data,
206  const int32_t x_index,
207  const int32_t ic,
208  const int32_t isr,
209  const int32_t osr) {
210  Point2D decompressed;
211  static_assert(C == Coords::X || C == Coords::Y, "Use get_point() instead of XY.");
212  if (x_and_y_are_dependent(isr, osr)) {
213  decompressed = {decompress_coord<X>(data, x_index, ic),
214  decompress_coord<Y>(data, x_index, ic)};
215  } else {
216  if constexpr (C == Coords::X) {
217  decompressed.x = decompress_coord<X>(data, x_index, ic);
218  } else {
219  decompressed.y = decompress_coord<Y>(data, x_index, ic);
220  }
221  }
222  return transform_point<C>(decompressed, isr, osr);
223 }
224 
225 // coord accessor for compressed coords at location index
226 DEVICE ALWAYS_INLINE int32_t compressed_coord(const int8_t* data, const int32_t index) {
227  const auto compressed_coords = reinterpret_cast<const int32_t*>(data);
228  return compressed_coords[index];
229 }
230 
231 // Cartesian distance between points, squared
233  double p1y,
234  double p2x,
235  double p2y) {
236  auto x = p1x - p2x;
237  auto y = p1y - p2y;
238  auto x2 = x * x;
239  auto y2 = y * y;
240  auto d2 = x2 + y2;
242  return 0.0;
243  }
244  return d2;
245 }
246 
247 // Cartesian distance between points
249  double p1y,
250  double p2x,
251  double p2y) {
252  auto d2 = distance_point_point_squared(p1x, p1y, p2x, p2y);
253  return sqrt(d2);
254 }
255 
256 // Cartesian distance between a point and a line segment
257 DEVICE
258 double distance_point_line(double px,
259  double py,
260  double l1x,
261  double l1y,
262  double l2x,
263  double l2y) {
264  double length = distance_point_point(l1x, l1y, l2x, l2y);
265  if (tol_zero(length)) {
266  return distance_point_point(px, py, l1x, l1y);
267  }
268 
269  // Find projection of point P onto the line segment AB:
270  // Line containing that segment: A + k * (B - A)
271  // Projection of point P onto the line touches it at
272  // k = dot(P-A,B-A) / length^2
273  // AB segment is represented by k = [0,1]
274  // Clamping k to [0,1] will give the shortest distance from P to AB segment
275  double dotprod = (px - l1x) * (l2x - l1x) + (py - l1y) * (l2y - l1y);
276  double k = dotprod / (length * length);
277  k = fmax(0.0, fmin(1.0, k));
278  double projx = l1x + k * (l2x - l1x);
279  double projy = l1y + k * (l2y - l1y);
280  return distance_point_point(px, py, projx, projy);
281 }
282 
283 // Cartesian distance between a point and a line segment
284 DEVICE
286  double py,
287  double l1x,
288  double l1y,
289  double l2x,
290  double l2y) {
291  double length = distance_point_point_squared(l1x, l1y, l2x, l2y);
292  if (tol_zero(length, TOLERANCE_DEFAULT_SQUARED)) {
293  return distance_point_point_squared(px, py, l1x, l1y);
294  }
295 
296  // Find projection of point P onto the line segment AB:
297  // Line containing that segment: A + k * (B - A)
298  // Projection of point P onto the line touches it at
299  // k = dot(P-A,B-A) / length^2
300  // AB segment is represented by k = [0,1]
301  // Clamping k to [0,1] will give the shortest distance from P to AB segment
302  double dotprod = (px - l1x) * (l2x - l1x) + (py - l1y) * (l2y - l1y);
303  double k = dotprod / (length * length);
304  k = fmax(0.0, fmin(1.0, k));
305  double projx = l1x + k * (l2x - l1x);
306  double projy = l1y + k * (l2y - l1y);
307  return distance_point_point_squared(px, py, projx, projy);
308 }
309 
310 // Given three colinear points p, q, r, the function checks if
311 // point q lies on line segment 'pr'
313  double py,
314  double qx,
315  double qy,
316  double rx,
317  double ry) {
318  return (tol_le(qx, fmax(px, rx)) && tol_ge(qx, fmin(px, rx)) &&
319  tol_le(qy, fmax(py, ry)) && tol_ge(qy, fmin(py, ry)));
320 }
321 
322 DEVICE ALWAYS_INLINE int16_t
323 orientation(double px, double py, double qx, double qy, double rx, double ry) {
324  auto val = ((qy - py) * (rx - qx) - (qx - px) * (ry - qy));
325  if (tol_zero(val)) {
326  return 0; // Points p, q and r are colinear
327  }
328  if (val > 0.0) {
329  return 1; // Clockwise point orientation
330  }
331  return 2; // Counterclockwise point orientation
332 }
333 
334 // Cartesian intersection of two line segments l11-l12 and l21-l22
335 DEVICE
336 bool line_intersects_line(double l11x,
337  double l11y,
338  double l12x,
339  double l12y,
340  double l21x,
341  double l21y,
342  double l22x,
343  double l22y) {
344  auto o1 = orientation(l11x, l11y, l12x, l12y, l21x, l21y);
345  auto o2 = orientation(l11x, l11y, l12x, l12y, l22x, l22y);
346  auto o3 = orientation(l21x, l21y, l22x, l22y, l11x, l11y);
347  auto o4 = orientation(l21x, l21y, l22x, l22y, l12x, l12y);
348 
349  // General case
350  if (o1 != o2 && o3 != o4) {
351  return true;
352  }
353 
354  // Special Cases
355  // l11, l12 and l21 are colinear and l21 lies on segment l11-l12
356  if (o1 == 0 && on_segment(l11x, l11y, l21x, l21y, l12x, l12y)) {
357  return true;
358  }
359 
360  // l11, l12 and l21 are colinear and l22 lies on segment l11-l12
361  if (o2 == 0 && on_segment(l11x, l11y, l22x, l22y, l12x, l12y)) {
362  return true;
363  }
364 
365  // l21, l22 and l11 are colinear and l11 lies on segment l21-l22
366  if (o3 == 0 && on_segment(l21x, l21y, l11x, l11y, l22x, l22y)) {
367  return true;
368  }
369 
370  // l21, l22 and l12 are colinear and l12 lies on segment l21-l22
371  if (o4 == 0 && on_segment(l21x, l21y, l12x, l12y, l22x, l22y)) {
372  return true;
373  }
374 
375  return false;
376 }
377 
378 DEVICE
380  int32_t lnum_coords,
381  double l1x,
382  double l1y,
383  double l2x,
384  double l2y,
385  int32_t ic1,
386  int32_t isr1,
387  int32_t osr) {
388  Point2D e1 = get_point(l, 0, ic1, isr1, osr);
389  for (int64_t i = 2; i < lnum_coords; i += 2) {
390  Point2D e2 = get_point(l, i, ic1, isr1, osr);
391  if (line_intersects_line(e1.x, e1.y, e2.x, e2.y, l1x, l1y, l2x, l2y)) {
392  return true;
393  }
394  e1 = e2;
395  }
396  return false;
397 }
398 
399 DEVICE
400 bool ring_intersects_line(int8_t* ring,
401  int32_t ring_num_coords,
402  double l1x,
403  double l1y,
404  double l2x,
405  double l2y,
406  int32_t ic1,
407  int32_t isr1,
408  int32_t osr) {
409  Point2D e1 = get_point(ring, ring_num_coords - 2, ic1, isr1, osr);
410  Point2D e2 = get_point(ring, 0, ic1, isr1, osr);
411  if (line_intersects_line(e1.x, e1.y, e2.x, e2.y, l1x, l1y, l2x, l2y)) {
412  return true;
413  }
415  ring, ring_num_coords, l1x, l1y, l2x, l2y, ic1, isr1, osr);
416 }
417 
418 DEVICE
420  int32_t lnum_coords,
421  double l1x,
422  double l1y,
423  double l2x,
424  double l2y,
425  int32_t ic1,
426  int32_t isr1,
427  int32_t osr) {
428  Point2D e1 = get_point(l, 0, ic1, isr1, osr);
429  for (int64_t i = 2; i < lnum_coords; i += 2) {
430  Point2D e2 = get_point(l, i, ic1, isr1, osr);
431  if (line_intersects_line(e1.x, e1.y, e2.x, e2.y, l1x, l1y, l2x, l2y)) {
432  return true;
433  }
434  e1 = e2;
435  }
436  return false;
437 }
438 
439 // Cartesian distance between two line segments l11-l12 and l21-l22
440 DEVICE
441 double distance_line_line(double l11x,
442  double l11y,
443  double l12x,
444  double l12y,
445  double l21x,
446  double l21y,
447  double l22x,
448  double l22y) {
449  if (line_intersects_line(l11x, l11y, l12x, l12y, l21x, l21y, l22x, l22y)) {
450  return 0.0;
451  }
452  double dist12 = fmin(distance_point_line(l11x, l11y, l21x, l21y, l22x, l22y),
453  distance_point_line(l12x, l12y, l21x, l21y, l22x, l22y));
454  double dist21 = fmin(distance_point_line(l21x, l21y, l11x, l11y, l12x, l12y),
455  distance_point_line(l22x, l22y, l11x, l11y, l12x, l12y));
456  return fmin(dist12, dist21);
457 }
458 
459 // Cartesian squared distance between two line segments l11-l12 and l21-l22
460 DEVICE
461 double distance_line_line_squared(double l11x,
462  double l11y,
463  double l12x,
464  double l12y,
465  double l21x,
466  double l21y,
467  double l22x,
468  double l22y) {
469  if (line_intersects_line(l11x, l11y, l12x, l12y, l21x, l21y, l22x, l22y)) {
470  return 0.0;
471  }
472  double dist12 = fmin(distance_point_line_squared(l11x, l11y, l21x, l21y, l22x, l22y),
473  distance_point_line_squared(l12x, l12y, l21x, l21y, l22x, l22y));
474  double dist21 = fmin(distance_point_line_squared(l21x, l21y, l11x, l11y, l12x, l12y),
475  distance_point_line_squared(l22x, l22y, l11x, l11y, l12x, l12y));
476  return fmin(dist12, dist21);
477 }
478 
479 DEVICE
480 double distance_ring_linestring(int8_t* ring,
481  int32_t ring_num_coords,
482  int8_t* l,
483  int32_t lnum_coords,
484  int32_t ic1,
485  int32_t isr1,
486  int32_t ic2,
487  int32_t isr2,
488  int32_t osr,
489  double threshold) {
490  double min_distance = 0.0;
491 
492  Point2D re1 = get_point(ring, ring_num_coords - 2, ic1, isr1, osr);
493  for (auto i = 0; i < ring_num_coords; i += 2) {
494  Point2D re2 = get_point(ring, i, ic1, isr1, osr);
495  Point2D le1 = get_point(l, 0, ic2, isr2, osr);
496  for (auto j = 2; j < lnum_coords; j += 2) {
497  Point2D le2 = get_point(l, j, ic2, isr2, osr);
498  auto distance =
499  distance_line_line(re1.x, re1.y, re2.x, re2.y, le1.x, le1.y, le2.x, le2.y);
500  if ((i == 0 && j == 2) || min_distance > distance) {
501  min_distance = distance;
502  if (tol_zero(min_distance)) {
503  return 0.0;
504  }
505  if (min_distance <= threshold) {
506  return min_distance;
507  }
508  }
509  le1 = le2;
510  }
511  re1 = re2;
512  }
513  return min_distance;
514 }
515 
516 DEVICE
517 double distance_ring_ring(int8_t* ring1,
518  int32_t ring1_num_coords,
519  int8_t* ring2,
520  int32_t ring2_num_coords,
521  int32_t ic1,
522  int32_t isr1,
523  int32_t ic2,
524  int32_t isr2,
525  int32_t osr,
526  double threshold) {
527  double min_distance = 0.0;
528  Point2D e11 = get_point(ring1, ring1_num_coords - 2, ic1, isr1, osr);
529  for (auto i = 0; i < ring1_num_coords; i += 2) {
530  Point2D e12 = get_point(ring1, i, ic1, isr1, osr);
531  Point2D e21 = get_point(ring2, ring2_num_coords - 2, ic2, isr2, osr);
532  for (auto j = 0; j < ring2_num_coords; j += 2) {
533  Point2D e22 = get_point(ring2, j, ic2, isr2, osr);
534  auto distance =
535  distance_line_line(e11.x, e11.y, e12.x, e12.y, e21.x, e21.y, e22.x, e22.y);
536  if ((i == 0 && j == 0) || min_distance > distance) {
537  min_distance = distance;
538  if (tol_zero(min_distance)) {
539  return 0.0;
540  }
541  if (min_distance <= threshold) {
542  return min_distance;
543  }
544  }
545  e21 = e22;
546  }
547  e11 = e12;
548  }
549  return min_distance;
550 }
551 
556 template <typename T>
558 is_left(const T lx0, const T ly0, const T lx1, const T ly1, const T px, const T py) {
559  return ((lx1 - lx0) * (py - ly0) - (px - lx0) * (ly1 - ly0));
560 }
561 
562 template <typename T>
564  const T tolerance = TOLERANCE_DEFAULT) {
565  if constexpr (!std::is_floating_point<T>::value) {
566  return x == 0; // assume integer 0s are always 0
567  }
568  return (-tolerance <= x) && (x <= tolerance);
569 }
570 
572 
586 template <typename T, EdgeBehavior TEdgeBehavior>
588  const int32_t poly_num_coords,
589  const T px,
590  const T py,
591  const int32_t ic1,
592  const int32_t isr1,
593  const int32_t osr) {
594  int32_t wn = 0;
595 
596  constexpr bool include_point_on_edge =
597  TEdgeBehavior == EdgeBehavior::kIncludePointOnEdge;
598 
599  auto get_x_coord = [=](const auto data, const auto index) -> T {
600  if constexpr (std::is_floating_point<T>::value) {
601  return get_point(data, index, ic1, isr1, osr).x;
602  } else {
603  return compressed_coord(data, index);
604  }
605  return T{}; // https://stackoverflow.com/a/64561686/2700898
606  };
607 
608  auto get_y_coord = [=](const auto data, const auto index) -> T {
609  if constexpr (std::is_floating_point<T>::value) {
610  return get_point(data, index, ic1, isr1, osr).y;
611  } else {
612  return compressed_coord(data, index + 1);
613  }
614  return T{}; // https://stackoverflow.com/a/64561686/2700898
615  };
616 
617  DEBUG_STMT(printf("Poly num coords: %d\n", poly_num_coords));
618  const int64_t num_edges = poly_num_coords / 2;
619 
620  int64_t e0_index = 0;
621  T e0x = get_x_coord(poly, e0_index * 2);
622  T e0y = get_y_coord(poly, e0_index * 2);
623 
624  int64_t e1_index;
625  T e1x, e1y;
626 
627  for (int64_t edge = 1; edge <= num_edges; edge++) {
628  DEBUG_STMT(printf("Edge %ld\n", edge));
629  // build the edge
630  e1_index = edge % num_edges;
631  e1x = get_x_coord(poly, e1_index * 2);
632  e1y = get_y_coord(poly, e1_index * 2);
633 
634  DEBUG_STMT(printf("edge 0: %ld : %f, %f\n", e0_index, (double)e0x, (double)e0y));
635  DEBUG_STMT(printf("edge 1: %ld : %f, %f\n", e1_index, (double)e1x, (double)e1y));
636 
637  auto get_epsilon = [=]() -> T {
638  if constexpr (std::is_floating_point<T>::value) {
639  const T edge_vec_magnitude =
640  (e1x - e0x) * (e1x - e0x) + (e1y - e0y) * (e1y - e0y);
641  return 0.003 * edge_vec_magnitude;
642  } else {
643  return T(0);
644  }
645  return T{}; // https://stackoverflow.com/a/64561686/2700898
646  };
647 
648  const T epsilon = get_epsilon();
649  DEBUG_STMT(printf("using epsilon value %e\n", (double)epsilon));
650 
651  if constexpr (include_point_on_edge) {
652  const T xp = (px - e1x) * (e0y - e1y) - (py - e1y) * (e0x - e1x);
653  const T pt_vec_magnitude = (px - e0x) * (px - e0x) + (py - e0y) * (py - e0y);
654  const T edge_vec_magnitude = (e1x - e0x) * (e1x - e0x) + (e1y - e0y) * (e1y - e0y);
655  if (tol_zero_template(xp, epsilon) && (pt_vec_magnitude <= edge_vec_magnitude)) {
656  DEBUG_STMT(printf("point is on edge: %e && %e <= %e\n",
657  (double)xp,
658  (double)pt_vec_magnitude,
659  (double)edge_vec_magnitude));
660  return include_point_on_edge;
661  }
662  }
663 
664  if (e0y <= py) {
665  if (e1y > py) {
666  // upward crossing
667  DEBUG_STMT(printf("upward crossing\n"));
668  const auto is_left_val = is_left(e0x, e0y, e1x, e1y, px, py);
669  DEBUG_STMT(printf("Left val %f and tol zero left val %d\n",
670  (double)is_left_val,
671  tol_zero_template(is_left_val, epsilon)));
672  if (UNLIKELY(tol_zero_template(is_left_val, epsilon))) {
673  // p is on the edge
674  return include_point_on_edge;
675  } else if (is_left_val > T(0)) { // p left of edge
676  // valid up intersection
677  DEBUG_STMT(printf("++wn\n"));
678  ++wn;
679  }
680  }
681  } else if (e1y <= py) {
682  // downward crossing
683  DEBUG_STMT(printf("downward crossing\n"));
684  const auto is_left_val = is_left(e0x, e0y, e1x, e1y, px, py);
685  DEBUG_STMT(printf("Left val %f and tol zero left val %d\n",
686  (double)is_left_val,
687  tol_zero_template(is_left_val, epsilon)));
688  if (UNLIKELY(tol_zero_template(is_left_val, epsilon))) {
689  // p is on the edge
690  return include_point_on_edge;
691  } else if (is_left_val < T(0)) { // p right of edge
692  // valid down intersection
693  DEBUG_STMT(printf("--wn\n"));
694  --wn;
695  }
696  }
697 
698  e0_index = e1_index;
699  e0x = e1x;
700  e0y = e1y;
701  }
702  DEBUG_STMT(printf("wn: %d\n", wn));
703  // wn == 0 --> P is outside the polygon
704  return !(wn == 0);
705 }
706 
707 // Checks if a simple polygon (no holes) contains a point.
708 //
709 // Poly coords are extracted from raw data, based on compression (ic1) and input/output
710 // SRIDs (isr1/osr).
711 //
712 // Shoot a ray from point P to the right, register intersections with any of polygon's
713 // edges. Each intersection means entrance into or exit from the polygon. Odd number of
714 // intersections means the polygon does contain P. Account for special cases: touch+cross,
715 // touch+leave, touch+overlay+cross, touch+overlay+leave, on edge, etc.
716 //
717 // Secondary ray is shot from point P down for simple redundancy, to reduce main probe's
718 // chance of error. No intersections means P is outside, irrespective of main probe's
719 // result.
720 //
722  const int32_t poly_num_coords,
723  const double px,
724  const double py,
725  const int32_t ic1,
726  const int32_t isr1,
727  const int32_t osr) {
728  bool result = false;
729  int xray_touch = 0;
730  bool horizontal_edge = false;
731  bool yray_intersects = false;
732 
733  Point2D e1 = get_point(poly, poly_num_coords - 2, ic1, isr1, osr);
734  for (int64_t i = 0; i < poly_num_coords; i += 2) {
735  Point2D e2 = get_point(poly, i, ic1, isr1, osr);
736 
737  // Check if point sits on an edge.
738  if (tol_zero(distance_point_line(px, py, e1.x, e1.y, e2.x, e2.y))) {
739  return true;
740  }
741 
742  // Before flipping the switch, check if xray hit a horizontal edge
743  // - If an edge lays on the xray, one of the previous edges touched it
744  // so while moving horizontally we're in 'xray_touch' state
745  // - Last edge that touched xray at (e2.x,e2.y) didn't register intersection
746  // - Next edge that diverges from xray at (e1,e1y) will register intersection
747  // - Can have several horizontal edges, one after the other, keep moving though
748  // in 'xray_touch' state without flipping the switch
749  horizontal_edge = (xray_touch != 0) && tol_eq(py, e1.y) && tol_eq(py, e2.y);
750 
751  // Main probe: xray
752  // Overshoot the xray to detect an intersection if there is one.
753  double xray = fmax(e2.x, e1.x) + 1.0;
754  if (px <= xray && // Only check for intersection if the edge is on the right
755  !horizontal_edge && // Keep moving through horizontal edges
756  line_intersects_line(px, // xray shooting from point p to the right
757  py,
758  xray,
759  py,
760  e1.x, // polygon edge
761  e1.y,
762  e2.x,
763  e2.y)) {
764  // Register intersection
765  result = !result;
766 
767  // Adjust for special cases
768  if (xray_touch == 0) {
769  if (tol_zero(distance_point_line(e2.x, e2.y, px, py, xray + 1.0, py))) {
770  // Xray goes through the edge's second vertex, unregister intersection -
771  // that vertex will be crossed again when we look at the following edge(s)
772  result = !result;
773  // Enter the xray-touch state:
774  // (1) - xray was touched by the edge from above, (-1) from below
775  xray_touch = (e1.y > py) ? 1 : -1;
776  }
777  } else {
778  // Previous edge touched the xray, intersection hasn't been registered,
779  // it has to be registered now if this edge continues across the xray.
780  if (xray_touch > 0) {
781  // Previous edge touched the xray from above
782  if (e2.y <= py) {
783  // Current edge crosses under xray: intersection is already registered
784  } else {
785  // Current edge just touched the xray and pulled up: unregister intersection
786  result = !result;
787  }
788  } else {
789  // Previous edge touched the xray from below
790  if (e2.y > py) {
791  // Current edge crosses over xray: intersection is already registered
792  } else {
793  // Current edge just touched the xray and pulled down: unregister intersection
794  result = !result;
795  }
796  }
797  // Exit the xray-touch state
798  xray_touch = 0;
799  }
800  }
801 
802  // Redundancy: vertical yray down
803  // Main probe xray may hit multiple complex fragments which increases a chance of
804  // error. Perform a simple secondary check for edge intersections to see if point is
805  // outside.
806  if (!yray_intersects) { // Continue checking on yray until intersection is found
807  double yray = fmin(e2.y, e1.y) - 1.0;
808  if (yray <= py) { // Only check for yray intersection if point P is above the edge
809  yray_intersects = line_intersects_line(px, // yray shooting from point P down
810  py,
811  px,
812  yray,
813  e1.x, // polygon edge
814  e1.y,
815  e2.x,
816  e2.y);
817  }
818  }
819 
820  // Advance to the next vertex
821  e1 = e2;
822  }
823  if (!yray_intersects) {
824  // yray has zero intersections - point is outside the polygon
825  return false;
826  }
827  // Otherwise rely on the main probe
828  return result;
829 }
830 
831 // Returns true if simple polygon (no holes) contains a linestring
832 DEVICE
833 bool polygon_contains_linestring(int8_t* poly,
834  int32_t poly_num_coords,
835  int8_t* l,
836  int64_t lnum_coords,
837  int32_t ic1,
838  int32_t isr1,
839  int32_t ic2,
840  int32_t isr2,
841  int32_t osr) {
842  // Check that the first point is in the polygon
843  Point2D l1 = get_point(l, 0, ic2, isr2, osr);
844  if (!polygon_contains_point(poly, poly_num_coords, l1.x, l1.y, ic1, isr1, osr)) {
845  return false;
846  }
847 
848  // Go through line segments and check if there are no intersections with poly edges,
849  // i.e. linestring doesn't escape
850  for (int32_t i = 2; i < lnum_coords; i += 2) {
851  Point2D l2 = get_point(l, i, ic2, isr2, osr);
853  poly, poly_num_coords, l1.x, l1.y, l2.x, l2.y, ic1, isr1, osr)) {
854  return false;
855  }
856  l1 = l2;
857  }
858  return true;
859 }
860 
861 DEVICE ALWAYS_INLINE bool box_contains_point(const double* bounds,
862  const int64_t bounds_size,
863  const double px,
864  const double py) {
865  // TODO: mixed spatial references
866  return (tol_ge(px, bounds[0]) && tol_ge(py, bounds[1]) && tol_le(px, bounds[2]) &&
867  tol_le(py, bounds[3]));
868 }
869 
871  int64_t bounds_size,
872  double px,
873  double py) {
874  // TODO: mixed spatial references
875  return box_contains_point(bounds, bounds_size, px, py);
876 }
877 
878 DEVICE ALWAYS_INLINE bool box_contains_box(double* bounds1,
879  int64_t bounds1_size,
880  double* bounds2,
881  int64_t bounds2_size) {
882  // TODO: mixed spatial references
883  return (
885  bounds1, bounds1_size, bounds2[0], bounds2[1]) && // box1 <- box2: xmin, ymin
887  bounds1, bounds1_size, bounds2[2], bounds2[3])); // box1 <- box2: xmax, ymax
888 }
889 
891  int64_t bounds1_size,
892  double* bounds2,
893  int64_t bounds2_size) {
894  // TODO: mixed spatial references
895  return (
897  bounds1, bounds1_size, bounds2[0], bounds2[1]) || // box1 <- box2: xmin, ymin
899  bounds1, bounds1_size, bounds2[2], bounds2[3]) || // box1 <- box2: xmax, ymax
901  bounds1, bounds1_size, bounds2[0], bounds2[3]) || // box1 <- box2: xmin, ymax
903  bounds1, bounds1_size, bounds2[2], bounds2[1])); // box1 <- box2: xmax, ymin
904 }
905 
906 DEVICE ALWAYS_INLINE bool box_overlaps_box(double* bounds1,
907  int64_t bounds1_size,
908  double* bounds2,
909  int64_t bounds2_size) {
910  // TODO: tolerance
911  // TODO: mixed spatial references
912  if (bounds1[2] < bounds2[0] || // box1 is left of box2: box1.xmax < box2.xmin
913  bounds1[0] > bounds2[2] || // box1 is right of box2: box1.xmin > box2.xmax
914  bounds1[3] < bounds2[1] || // box1 is below box2: box1.ymax < box2.ymin
915  bounds1[1] > bounds2[3]) { // box1 is above box2: box1.ymin > box1.ymax
916  return false;
917  }
918  return true;
919 }
920 
922  int64_t p1size,
923  int32_t ic1,
924  int32_t isr1,
925  double* bounds2,
926  int64_t bounds2_size,
927  int32_t isr2,
928  int32_t osr,
929  double distance) {
930  // TODO: tolerance
931 
932  // Point has to be uncompressed and transformed to output SR.
933  // Bounding box has to be transformed to output SR.
934  Point2D p = get_point(p1, 0, ic1, isr1, osr);
935  Point2D const lb = transform_point<XY>({bounds2[0], bounds2[1]}, isr2, osr);
936  Point2D const rt = transform_point<XY>({bounds2[2], bounds2[3]}, isr2, osr);
937  if (p.x < lb.x - distance || // point is left of box2: px < box2.xmin - distance
938  p.x > rt.x + distance || // point is right of box2: px > box2.xmax + distance
939  p.y < lb.y - distance || // point is below box2: py < box2.ymin - distance
940  p.y > rt.y + distance) { // point is above box2: py > box2.ymax + distance
941  return false;
942  }
943  return true;
944 }
945 
946 DEVICE ALWAYS_INLINE bool box_dwithin_box(double* bounds1,
947  int64_t bounds1_size,
948  int32_t isr1,
949  double* bounds2,
950  int64_t bounds2_size,
951  int32_t isr2,
952  int32_t osr,
953  double distance) {
954  // TODO: tolerance
955 
956  // Bounds come in corresponding input spatial references.
957  // For example, here the first bounding box may come in 4326, second in 900913:
958  // ST_DWithin(ST_Transform(linestring4326, 900913), linestring900913, 10)
959  // Distance is given in osr spatial reference units, in this case 10 meters.
960  // Bounds should be converted to osr before calculations, if isr != osr.
961 
962  // TODO: revise all other functions that process bounds
963 
964  Point2D const lb1 = transform_point<XY>({bounds1[0], bounds1[1]}, isr1, osr);
965  Point2D const rt1 = transform_point<XY>({bounds1[2], bounds1[3]}, isr1, osr);
966  Point2D const lb2 = transform_point<XY>({bounds2[0], bounds2[1]}, isr2, osr);
967  Point2D const rt2 = transform_point<XY>({bounds2[2], bounds2[3]}, isr2, osr);
968  if (
969  // box1 is left of box2: box1.xmax + distance < box2.xmin
970  rt1.x + distance < lb2.x ||
971  // box1 is right of box2: box1.xmin - distance > box2.xmax
972  lb1.x - distance > rt2.x ||
973  // box1 is below box2: box1.ymax + distance < box2.ymin
974  rt1.y + distance < lb2.y ||
975  // box1 is above box2: box1.ymin - distance > box1.ymax
976  lb1.y - distance > rt2.y) {
977  return false;
978  }
979  return true;
980 }
981 
983  int64_t l1size,
984  int32_t ic1,
985  int32_t isr1,
986  double* bounds2,
987  int64_t bounds2_size,
988  int32_t isr2,
989  int32_t osr,
990  double distance) {
991  // TODO: tolerance
992 
993  // Bounds come in corresponding input spatial references.
994  // For example, here the first bounding box may come in 4326, second in 900913:
995  // ST_DWithin(ST_Transform(linestring4326, 900913), linestring900913, 10)
996  // Distance is given in osr spatial reference units, in this case 10 meters.
997  // Bounds should be converted to osr before calculations, if isr != osr.
998 
999  Point2D const lb = transform_point<XY>({bounds2[0], bounds2[1]}, isr2, osr);
1000  Point2D const rt = transform_point<XY>({bounds2[2], bounds2[3]}, isr2, osr);
1001  CoordData l1_relevant_section;
1002  // Interate through linestring segments.
1003  // Mark the start of the relevant section FIRST TIME WE ENTER the buffered box.
1004  // Set the size of the relevant section the LAST TIME WE GET OUT of the box.
1005  auto l1_num_coords = l1size / compression_unit_size(ic1);
1006  Point2D l11 = get_point(l1, 0, ic1, isr1, osr);
1007  for (int32_t i1 = 2; i1 < l1_num_coords; i1 += 2) {
1008  Point2D l12 = get_point(l1, i1, ic1, isr1, osr);
1009  // Check for overlap between the line box and the buffered box
1010  if (
1011  // line box is left of buffered box
1012  fmax(l11.x, l12.x) + distance < lb.x ||
1013  // line box is right of buffered box
1014  fmin(l11.x, l12.x) - distance > rt.x ||
1015  // line box is below buffered box
1016  fmax(l11.y, l12.y) + distance < lb.y ||
1017  // line box is above buffered box
1018  fmin(l11.y, l12.y) - distance > rt.y) {
1019  // No overlap
1020  if (l1_relevant_section.ptr && l1_relevant_section.size == 0) {
1021  // Can finalize relevant section size
1022  l1_relevant_section.size =
1023  l1 + i1 * compression_unit_size(ic1) - l1_relevant_section.ptr;
1024  }
1025  } else {
1026  // Overlap
1027  if (!l1_relevant_section.ptr) {
1028  // Start tracking relevant section
1029  l1_relevant_section.ptr = l1 + (i1 - 2) * compression_unit_size(ic1);
1030  }
1031  // Keep relevant section size unfinalized while there is overlap,
1032  // linestring may reenter the buffered box.
1033  l1_relevant_section.size = 0;
1034  }
1035  // Advance to the next line segment.
1036  l11.x = l12.x;
1037  l11.y = l12.y;
1038  }
1039  if (l1_relevant_section.ptr && l1_relevant_section.size == 0) {
1040  // If we did start tracking the relevant section (i.e. entered the buffered bbox)
1041  // and haven't finalized the size (i.e. stayed in the bbox until the end)
1042  // finalize now based on the last point.
1043  l1_relevant_section.size = l1size - (l1_relevant_section.ptr - l1);
1044  }
1045  if (l1_relevant_section.ptr &&
1046  (l1_relevant_section.size < 4 * compression_unit_size(ic1))) {
1047  // Haven't found a section with at least 1 segment: zoom out
1048  l1_relevant_section = {l1, l1size};
1049  }
1050 
1051  return l1_relevant_section;
1052 }
1053 
1055 double ST_X_Point(int8_t* p, int64_t psize, int32_t ic, int32_t isr, int32_t osr) {
1056  return coord<X>(p, 0, ic, isr, osr).x;
1057 }
1058 
1060 double ST_Y_Point(int8_t* p, int64_t psize, int32_t ic, int32_t isr, int32_t osr) {
1061  return coord<Y>(p, 0, ic, isr, osr).y;
1062 }
1063 
1065 double ST_XMin(int8_t* coords, int64_t size, int32_t ic, int32_t isr, int32_t osr) {
1066  auto num_coords = size / compression_unit_size(ic);
1067  double xmin = 0.0;
1068  for (int32_t i = 0; i < num_coords; i += 2) {
1069  double x = coord<X>(coords, i, ic, isr, osr).x;
1070  if (i == 0 || x < xmin) {
1071  xmin = x;
1072  }
1073  }
1074  return xmin;
1075 }
1076 
1078 double ST_YMin(int8_t* coords, int64_t size, int32_t ic, int32_t isr, int32_t osr) {
1079  auto num_coords = size / compression_unit_size(ic);
1080  double ymin = 0.0;
1081  for (int32_t i = 0; i < num_coords; i += 2) {
1082  double y = coord<Y>(coords, i, ic, isr, osr).y;
1083  if (i == 0 || y < ymin) {
1084  ymin = y;
1085  }
1086  }
1087  return ymin;
1088 }
1089 
1091 double ST_XMax(int8_t* coords, int64_t size, int32_t ic, int32_t isr, int32_t osr) {
1092  auto num_coords = size / compression_unit_size(ic);
1093  double xmax = 0.0;
1094  for (int32_t i = 0; i < num_coords; i += 2) {
1095  double x = coord<X>(coords, i, ic, isr, osr).x;
1096  if (i == 0 || x > xmax) {
1097  xmax = x;
1098  }
1099  }
1100  return xmax;
1101 }
1102 
1104 double ST_YMax(int8_t* coords, int64_t size, int32_t ic, int32_t isr, int32_t osr) {
1105  auto num_coords = size / compression_unit_size(ic);
1106  double ymax = 0.0;
1107  for (int32_t i = 0; i < num_coords; i += 2) {
1108  double y = coord<Y>(coords, i, ic, isr, osr).y;
1109  if (i == 0 || y > ymax) {
1110  ymax = y;
1111  }
1112  }
1113  return ymax;
1114 }
1115 
1117 double ST_XMin_Bounds(double* bounds, int64_t size, int32_t isr, int32_t osr) {
1118  return transform_point<X>({bounds[0], bounds[1]}, isr, osr).x;
1119 }
1120 
1122 double ST_YMin_Bounds(double* bounds, int64_t size, int32_t isr, int32_t osr) {
1123  return transform_point<Y>({bounds[0], bounds[1]}, isr, osr).y;
1124 }
1125 
1127 double ST_XMax_Bounds(double* bounds, int64_t size, int32_t isr, int32_t osr) {
1128  return transform_point<X>({bounds[2], bounds[3]}, isr, osr).x;
1129 }
1130 
1132 double ST_YMax_Bounds(double* bounds, int64_t size, int32_t isr, int32_t osr) {
1133  return transform_point<Y>({bounds[2], bounds[3]}, isr, osr).y;
1134 }
1135 
1136 //
1137 // ST_Length
1138 //
1139 
1141  int32_t lsize,
1142  int32_t ic,
1143  int32_t isr,
1144  int32_t osr,
1145  bool geodesic,
1146  bool check_closed) {
1147  auto l_num_coords = lsize / compression_unit_size(ic);
1148 
1149  double length = 0.0;
1150 
1151  Point2D l0 = get_point(l, 0, ic, isr, osr);
1152  Point2D l2 = l0;
1153  for (int32_t i = 2; i < l_num_coords; i += 2) {
1154  Point2D l1 = l2;
1155  l2 = get_point(l, i, ic, isr, osr);
1156  double ldist = geodesic ? distance_in_meters(l1.x, l1.y, l2.x, l2.y)
1157  : distance_point_point(l1.x, l1.y, l2.x, l2.y);
1158  length += ldist;
1159  }
1160  if (check_closed) {
1161  double ldist = geodesic ? distance_in_meters(l2.x, l2.y, l0.x, l0.y)
1162  : distance_point_point(l2.x, l2.y, l0.x, l0.y);
1163  length += ldist;
1164  }
1165  return length;
1166 }
1167 
1169 double ST_Length_LineString(int8_t* coords,
1170  int64_t coords_sz,
1171  int32_t ic,
1172  int32_t isr,
1173  int32_t osr) {
1174  return length_linestring(coords, coords_sz, ic, isr, osr, false, false);
1175 }
1176 
1178 double ST_Length_LineString_Geodesic(int8_t* coords,
1179  int64_t coords_sz,
1180  int32_t ic,
1181  int32_t isr,
1182  int32_t osr) {
1183  return length_linestring(coords, coords_sz, ic, isr, osr, true, false);
1184 }
1185 
1187 double ST_Length_MultiLineString(int8_t* coords,
1188  int64_t coords_sz,
1189  int8_t* linestring_sizes_in,
1190  int64_t linestring_sizes_sz,
1191  int32_t ic,
1192  int32_t isr,
1193  int32_t osr) {
1194  if (linestring_sizes_sz <= 0) {
1195  return 0.0;
1196  }
1197  double mls_length = 0.0;
1198 
1199  auto next_linestring_coords = coords;
1200 
1201  for (auto l = 0; l < linestring_sizes_sz; l++) {
1202  auto linestring_coords = next_linestring_coords;
1203  auto linestring_sizes = reinterpret_cast<int32_t*>(linestring_sizes_in);
1204  auto linestring_num_points = linestring_sizes[l];
1205  auto linestring_num_coords = 2 * linestring_num_points;
1206  auto linestring_coords_size = linestring_num_coords * compression_unit_size(ic);
1207  next_linestring_coords += linestring_coords_size;
1208  double ls_length = length_linestring(
1209  linestring_coords, linestring_coords_size, ic, isr, osr, false, false);
1210  mls_length += ls_length;
1211  }
1212 
1213  return mls_length;
1214 }
1215 
1216 //
1217 // ST_Perimeter
1218 //
1219 
1221 double ST_Perimeter_Polygon(int8_t* poly,
1222  int32_t polysize,
1223  int8_t* poly_ring_sizes,
1224  int32_t poly_num_rings,
1225  int32_t ic,
1226  int32_t isr,
1227  int32_t osr) {
1228  if (poly_num_rings <= 0) {
1229  return 0.0;
1230  }
1231 
1232  auto exterior_ring_num_coords = poly_ring_sizes[0] * 2;
1233  auto exterior_ring_coords_size = exterior_ring_num_coords * compression_unit_size(ic);
1234 
1235  return length_linestring(poly, exterior_ring_coords_size, ic, isr, osr, false, true);
1236 }
1237 
1239 double ST_Perimeter_Polygon_Geodesic(int8_t* poly,
1240  int32_t polysize,
1241  int8_t* poly_ring_sizes_in,
1242  int32_t poly_num_rings,
1243  int32_t ic,
1244  int32_t isr,
1245  int32_t osr) {
1246  if (poly_num_rings <= 0) {
1247  return 0.0;
1248  }
1249 
1250  auto poly_ring_sizes = reinterpret_cast<int32_t*>(poly_ring_sizes_in);
1251  auto exterior_ring_num_coords = poly_ring_sizes[0] * 2;
1252  auto exterior_ring_coords_size = exterior_ring_num_coords * compression_unit_size(ic);
1253 
1254  return length_linestring(poly, exterior_ring_coords_size, ic, isr, osr, true, true);
1255 }
1256 
1257 DEVICE ALWAYS_INLINE double perimeter_multipolygon(int8_t* mpoly_coords,
1258  int32_t mpoly_coords_size,
1259  int8_t* mpoly_ring_sizes_in,
1260  int32_t mpoly_num_rings,
1261  int8_t* mpoly_poly_sizes,
1262  int32_t mpoly_num_polys,
1263  int32_t ic,
1264  int32_t isr,
1265  int32_t osr,
1266  bool geodesic) {
1267  if (mpoly_num_polys <= 0 || mpoly_num_rings <= 0) {
1268  return 0.0;
1269  }
1270 
1271  double perimeter = 0.0;
1272 
1273  auto mpoly_ring_sizes = reinterpret_cast<int32_t*>(mpoly_ring_sizes_in);
1274 
1275  // Set specific poly pointers as we move through the coords/ringsizes/polyrings arrays.
1276  auto next_poly_coords = mpoly_coords;
1277  auto next_poly_ring_sizes = mpoly_ring_sizes;
1278 
1279  for (auto poly = 0; poly < mpoly_num_polys; poly++) {
1280  auto poly_coords = next_poly_coords;
1281  auto poly_ring_sizes = next_poly_ring_sizes;
1282  auto poly_num_rings = reinterpret_cast<int32_t*>(mpoly_poly_sizes)[poly];
1283  // Count number of coords in all of poly's rings, advance ring size pointer.
1284  int32_t poly_num_coords = 0;
1285  for (auto ring = 0; ring < poly_num_rings; ring++) {
1286  poly_num_coords += 2 * *next_poly_ring_sizes++;
1287  }
1288  auto poly_coords_size = poly_num_coords * compression_unit_size(ic);
1289  next_poly_coords += poly_coords_size;
1290 
1291  auto exterior_ring_num_coords = poly_ring_sizes[0] * 2;
1292  auto exterior_ring_coords_size = exterior_ring_num_coords * compression_unit_size(ic);
1293 
1294  perimeter += length_linestring(
1295  poly_coords, exterior_ring_coords_size, ic, isr, osr, geodesic, true);
1296  }
1297 
1298  return perimeter;
1299 }
1300 
1302 double ST_Perimeter_MultiPolygon(int8_t* mpoly_coords,
1303  int32_t mpoly_coords_size,
1304  int8_t* mpoly_ring_sizes,
1305  int32_t mpoly_num_rings,
1306  int8_t* mpoly_poly_sizes,
1307  int32_t mpoly_num_polys,
1308  int32_t ic,
1309  int32_t isr,
1310  int32_t osr) {
1311  return perimeter_multipolygon(mpoly_coords,
1312  mpoly_coords_size,
1313  mpoly_ring_sizes,
1314  mpoly_num_rings,
1315  mpoly_poly_sizes,
1316  mpoly_num_polys,
1317  ic,
1318  isr,
1319  osr,
1320  false);
1321 }
1322 
1324 double ST_Perimeter_MultiPolygon_Geodesic(int8_t* mpoly_coords,
1325  int32_t mpoly_coords_size,
1326  int8_t* mpoly_ring_sizes,
1327  int32_t mpoly_num_rings,
1328  int8_t* mpoly_poly_sizes,
1329  int32_t mpoly_num_polys,
1330  int32_t ic,
1331  int32_t isr,
1332  int32_t osr) {
1333  return perimeter_multipolygon(mpoly_coords,
1334  mpoly_coords_size,
1335  mpoly_ring_sizes,
1336  mpoly_num_rings,
1337  mpoly_poly_sizes,
1338  mpoly_num_polys,
1339  ic,
1340  isr,
1341  osr,
1342  true);
1343 }
1344 
1345 //
1346 // ST_Area
1347 //
1348 
1350  double y1,
1351  double x2,
1352  double y2,
1353  double x3,
1354  double y3) {
1355  return (x1 * y2 - x2 * y1 + x3 * y1 - x1 * y3 + x2 * y3 - x3 * y2) / 2.0;
1356 }
1357 
1358 DEVICE ALWAYS_INLINE double area_ring(int8_t* ring,
1359  int64_t ringsize,
1360  int32_t ic,
1361  int32_t isr,
1362  int32_t osr) {
1363  auto ring_num_coords = ringsize / compression_unit_size(ic);
1364 
1365  if (ring_num_coords < 6) {
1366  return 0.0;
1367  }
1368 
1369  double area = 0.0;
1370 
1371  Point2D p1 = get_point(ring, 0, ic, isr, osr);
1372  Point2D p2 = get_point(ring, 2, ic, isr, osr);
1373  for (int32_t i = 4; i < ring_num_coords; i += 2) {
1374  Point2D p3 = get_point(ring, i, ic, isr, osr);
1375  area += area_triangle(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
1376  p2 = p3;
1377  }
1378  return area;
1379 }
1380 
1381 DEVICE ALWAYS_INLINE double area_polygon(int8_t* poly_coords,
1382  int32_t poly_coords_size,
1383  int8_t* poly_ring_sizes_in,
1384  int32_t poly_num_rings,
1385  int32_t ic,
1386  int32_t isr,
1387  int32_t osr) {
1388  if (poly_num_rings <= 0) {
1389  return 0.0;
1390  }
1391 
1392  double area = 0.0;
1393  auto ring_coords = poly_coords;
1394  auto poly_ring_sizes = reinterpret_cast<int32_t*>(poly_ring_sizes_in);
1395 
1396  // Add up the areas of all rings.
1397  // External ring is CCW, open - positive area.
1398  // Internal rings (holes) are CW, open - negative areas.
1399  for (auto r = 0; r < poly_num_rings; r++) {
1400  auto ring_coords_size = poly_ring_sizes[r] * 2 * compression_unit_size(ic);
1401  area += area_ring(ring_coords, ring_coords_size, ic, isr, osr);
1402  // Advance to the next ring.
1403  ring_coords += ring_coords_size;
1404  }
1405  return area;
1406 }
1407 
1409 double ST_Area_Polygon(int8_t* poly_coords,
1410  int32_t poly_coords_size,
1411  int8_t* poly_ring_sizes,
1412  int32_t poly_num_rings,
1413  int32_t ic,
1414  int32_t isr,
1415  int32_t osr) {
1416  return area_polygon(
1417  poly_coords, poly_coords_size, poly_ring_sizes, poly_num_rings, ic, isr, osr);
1418 }
1419 
1421 double ST_Area_MultiPolygon(int8_t* mpoly_coords,
1422  int32_t mpoly_coords_size,
1423  int8_t* mpoly_ring_sizes,
1424  int32_t mpoly_num_rings,
1425  int8_t* mpoly_poly_sizes_in,
1426  int32_t mpoly_num_polys,
1427  int32_t ic,
1428  int32_t isr,
1429  int32_t osr) {
1430  if (mpoly_num_rings <= 0 || mpoly_num_polys <= 0) {
1431  return 0.0;
1432  }
1433 
1434  double area = 0.0;
1435 
1436  auto mpoly_poly_sizes = reinterpret_cast<int32_t*>(mpoly_poly_sizes_in);
1437 
1438  // Set specific poly pointers as we move through the coords/ringsizes/polyrings arrays.
1439  auto next_poly_coords = mpoly_coords;
1440  auto next_poly_ring_sizes = reinterpret_cast<int32_t*>(mpoly_ring_sizes);
1441 
1442  for (auto poly = 0; poly < mpoly_num_polys; poly++) {
1443  auto poly_coords = next_poly_coords;
1444  auto poly_ring_sizes = next_poly_ring_sizes;
1445  auto poly_num_rings = mpoly_poly_sizes[poly];
1446  // Count number of coords in all of poly's rings, advance ring size pointer.
1447  int32_t poly_num_coords = 0;
1448  for (auto ring = 0; ring < poly_num_rings; ring++) {
1449  poly_num_coords += 2 * *next_poly_ring_sizes++;
1450  }
1451  auto poly_coords_size = poly_num_coords * compression_unit_size(ic);
1452  next_poly_coords += poly_coords_size;
1453 
1454  area += area_polygon(poly_coords,
1455  poly_coords_size,
1456  reinterpret_cast<int8_t*>(poly_ring_sizes),
1457  poly_num_rings,
1458  ic,
1459  isr,
1460  osr);
1461  }
1462  return area;
1463 }
1464 
1465 //
1466 // ST_Centroid
1467 //
1468 
1469 // Point centroid
1470 // - Single point - drop, otherwise calculate average coordinates for all points
1471 // LineString centroid
1472 // - take midpoint of each line segment
1473 // - calculate average coordinates of all midpoints weighted by segment length
1474 // Polygon, MultiPolygon centroid, holes..
1475 // - weighted sum of centroids of triangles coming out of area decomposition
1476 //
1477 // On zero area fall back to linestring centroid
1478 // On zero length fall back to point centroid
1479 
1481 void ST_Centroid_Point(int8_t* p,
1482  int32_t psize,
1483  int32_t ic,
1484  int32_t isr,
1485  int32_t osr,
1486  double* point_centroid) {
1487  Point2D const centroid = get_point(p, 0, ic, isr, osr);
1488  point_centroid[0] = centroid.x;
1489  point_centroid[1] = centroid.y;
1490 }
1491 
1493 void ST_Centroid_MultiPoint(int8_t* mp,
1494  int32_t mpsize,
1495  int32_t ic,
1496  int32_t isr,
1497  int32_t osr,
1498  double* multipoint_centroid) {
1499  auto mp_num_coords = mpsize / compression_unit_size(ic);
1500  double x = 0.0;
1501  double y = 0.0;
1502  for (int32_t i = 0; i < mp_num_coords; i += 2) {
1503  Point2D mpp = get_point(mp, i, ic, isr, osr);
1504  x += mpp.x; // In case of overflows on large geometries,
1505  y += mpp.y; // move division into the loop
1506  }
1507  auto mp_num_points = mp_num_coords >> 1;
1508  multipoint_centroid[0] = x / mp_num_points;
1509  multipoint_centroid[1] = y / mp_num_points;
1510 }
1511 
1513  double y1,
1514  double x2,
1515  double y2,
1516  double* length,
1517  double* linestring_centroid_sum) {
1518  double ldist = distance_point_point(x1, y1, x2, y2);
1519  *length += ldist;
1520  double segment_midpoint_x = (x1 + x2) / 2.0;
1521  double segment_midpoint_y = (y1 + y2) / 2.0;
1522  linestring_centroid_sum[0] += ldist * segment_midpoint_x;
1523  linestring_centroid_sum[1] += ldist * segment_midpoint_y;
1524  return true;
1525 }
1526 
1528  int64_t lsize,
1529  int32_t ic,
1530  int32_t isr,
1531  int32_t osr,
1532  bool closed,
1533  double* total_length,
1534  double* linestring_centroid_sum,
1535  int64_t* num_points,
1536  double* point_centroid_sum) {
1537  auto l_num_coords = lsize / compression_unit_size(ic);
1538  double length = 0.0;
1539  Point2D const l0 = get_point(l, 0, ic, isr, osr);
1540  Point2D l2 = l0;
1541  for (int32_t i = 2; i < l_num_coords; i += 2) {
1542  Point2D const l1 = l2;
1543  l2 = get_point(l, i, ic, isr, osr);
1544  centroid_add_segment(l1.x, l1.y, l2.x, l2.y, &length, linestring_centroid_sum);
1545  }
1546  if (l_num_coords > 4 && closed) {
1547  // Also add the closing segment between the last and the first points
1548  centroid_add_segment(l2.x, l2.y, l0.x, l0.y, &length, linestring_centroid_sum);
1549  }
1550  *total_length += length;
1551  if (length == 0.0 && l_num_coords > 0) {
1552  *num_points += 1;
1553  point_centroid_sum[0] += l0.x;
1554  point_centroid_sum[1] += l0.y;
1555  }
1556  return true;
1557 }
1558 
1560 void ST_Centroid_LineString(int8_t* coords,
1561  int32_t coords_sz,
1562  int32_t ic,
1563  int32_t isr,
1564  int32_t osr,
1565  double* linestring_centroid) {
1566  double length = 0.0;
1567  double linestring_centroid_sum[2] = {0.0, 0.0};
1568  int64_t num_points = 0;
1569  double point_centroid_sum[2] = {0.0, 0.0};
1570  centroid_add_linestring(coords,
1571  coords_sz,
1572  ic,
1573  isr,
1574  osr,
1575  false, // not closed
1576  &length,
1577  &linestring_centroid_sum[0],
1578  &num_points,
1579  &point_centroid_sum[0]);
1580  if (length > 0) {
1581  linestring_centroid[0] = linestring_centroid_sum[0] / length;
1582  linestring_centroid[1] = linestring_centroid_sum[1] / length;
1583  } else if (num_points > 0) {
1584  linestring_centroid[0] = point_centroid_sum[0] / num_points;
1585  linestring_centroid[1] = point_centroid_sum[1] / num_points;
1586  }
1587 }
1588 
1590  double y1,
1591  double x2,
1592  double y2,
1593  double x3,
1594  double y3,
1595  double sign,
1596  double* total_area2,
1597  double* cg3) {
1598  double cx = x1 + x2 + x3;
1599  double cy = y1 + y2 + y3;
1600  double area2 = x1 * y2 - x2 * y1 + x3 * y1 - x1 * y3 + x2 * y3 - x3 * y2;
1601  cg3[0] += sign * area2 * cx;
1602  cg3[1] += sign * area2 * cy;
1603  *total_area2 += sign * area2;
1604  return true;
1605 }
1606 
1608  int64_t ringsize,
1609  int32_t ic,
1610  int32_t isr,
1611  int32_t osr,
1612  double sign,
1613  double* total_area2,
1614  double* cg3,
1615  double* total_length,
1616  double* linestring_centroid_sum,
1617  int64_t* num_points,
1618  double* point_centroid_sum) {
1619  auto ring_num_coords = ringsize / compression_unit_size(ic);
1620 
1621  if (ring_num_coords < 6) {
1622  return false;
1623  }
1624 
1625  Point2D p1 = get_point(ring, 0, ic, isr, osr);
1626  Point2D p2 = get_point(ring, 2, ic, isr, osr);
1627  for (int32_t i = 4; i < ring_num_coords; i += 2) {
1628  Point2D p3 = get_point(ring, i, ic, isr, osr);
1629  centroid_add_triangle(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, sign, total_area2, cg3);
1630  p2 = p3;
1631  }
1632 
1634  ringsize,
1635  ic,
1636  isr,
1637  osr,
1638  true, // closed
1639  total_length,
1640  linestring_centroid_sum,
1641  num_points,
1642  point_centroid_sum);
1643  return true;
1644 }
1645 
1646 DEVICE ALWAYS_INLINE bool centroid_add_polygon(int8_t* poly_coords,
1647  int64_t poly_coords_size,
1648  int32_t* poly_ring_sizes,
1649  int64_t poly_num_rings,
1650  int32_t ic,
1651  int32_t isr,
1652  int32_t osr,
1653  double* total_area2,
1654  double* cg3,
1655  double* total_length,
1656  double* linestring_centroid_sum,
1657  int64_t* num_points,
1658  double* point_centroid_sum) {
1659  if (poly_num_rings <= 0) {
1660  return false;
1661  }
1662 
1663  auto ring_coords = poly_coords;
1664 
1665  for (auto r = 0; r < poly_num_rings; r++) {
1666  auto ring_coords_size = poly_ring_sizes[r] * 2 * compression_unit_size(ic);
1667  // Shape - positive area, holes - negative areas
1668  double sign = (r == 0) ? 1.0 : -1.0;
1669  centroid_add_ring(ring_coords,
1670  ring_coords_size,
1671  ic,
1672  isr,
1673  osr,
1674  sign,
1675  total_area2,
1676  cg3,
1677  total_length,
1678  linestring_centroid_sum,
1679  num_points,
1680  point_centroid_sum);
1681  // Advance to the next ring.
1682  ring_coords += ring_coords_size;
1683  }
1684  return true;
1685 }
1686 
1688 void ST_Centroid_Polygon(int8_t* poly_coords,
1689  int32_t poly_coords_size,
1690  int32_t* poly_ring_sizes,
1691  int32_t poly_num_rings,
1692  int32_t ic,
1693  int32_t isr,
1694  int32_t osr,
1695  double* poly_centroid) {
1696  if (poly_num_rings <= 0) {
1697  poly_centroid[0] = 0.0;
1698  poly_centroid[1] = 0.0;
1699  }
1700  double total_area2 = 0.0;
1701  double cg3[2] = {0.0, 0.0};
1702  double total_length = 0.0;
1703  double linestring_centroid_sum[2] = {0.0, 0.0};
1704  int64_t num_points = 0;
1705  double point_centroid_sum[2] = {0.0, 0.0};
1706  centroid_add_polygon(poly_coords,
1707  poly_coords_size,
1708  poly_ring_sizes,
1709  poly_num_rings,
1710  ic,
1711  isr,
1712  osr,
1713  &total_area2,
1714  &cg3[0],
1715  &total_length,
1716  &linestring_centroid_sum[0],
1717  &num_points,
1718  &point_centroid_sum[0]);
1719 
1720  if (total_area2 != 0.0) {
1721  poly_centroid[0] = cg3[0] / 3 / total_area2;
1722  poly_centroid[1] = cg3[1] / 3 / total_area2;
1723  } else if (total_length > 0.0) {
1724  // zero-area polygon, fall back to linear centroid
1725  poly_centroid[0] = linestring_centroid_sum[0] / total_length;
1726  poly_centroid[1] = linestring_centroid_sum[1] / total_length;
1727  } else if (num_points > 0) {
1728  // zero-area zero-length polygon, fall further back to point centroid
1729  poly_centroid[0] = point_centroid_sum[0] / num_points;
1730  poly_centroid[1] = point_centroid_sum[1] / num_points;
1731  } else {
1732  Point2D centroid = get_point(poly_coords, 0, ic, isr, osr);
1733  poly_centroid[0] = centroid.x;
1734  poly_centroid[1] = centroid.y;
1735  }
1736 }
1737 
1739 void ST_Centroid_MultiPolygon(int8_t* mpoly_coords,
1740  int32_t mpoly_coords_size,
1741  int32_t* mpoly_ring_sizes,
1742  int32_t mpoly_num_rings,
1743  int32_t* mpoly_poly_sizes,
1744  int32_t mpoly_num_polys,
1745  int32_t ic,
1746  int32_t isr,
1747  int32_t osr,
1748  double* mpoly_centroid) {
1749  if (mpoly_num_rings <= 0 || mpoly_num_polys <= 0) {
1750  mpoly_centroid[0] = 0.0;
1751  mpoly_centroid[1] = 0.0;
1752  }
1753 
1754  double total_area2 = 0.0;
1755  double cg3[2] = {0.0, 0.0};
1756  double total_length = 0.0;
1757  double linestring_centroid_sum[2] = {0.0, 0.0};
1758  int64_t num_points = 0;
1759  double point_centroid_sum[2] = {0.0, 0.0};
1760 
1761  // Set specific poly pointers as we move through the coords/ringsizes/polyrings arrays.
1762  auto next_poly_coords = mpoly_coords;
1763  auto next_poly_ring_sizes = mpoly_ring_sizes;
1764 
1765  for (auto poly = 0; poly < mpoly_num_polys; poly++) {
1766  auto poly_coords = next_poly_coords;
1767  auto poly_ring_sizes = next_poly_ring_sizes;
1768  auto poly_num_rings = mpoly_poly_sizes[poly];
1769  // Count number of coords in all of poly's rings, advance ring size pointer.
1770  int32_t poly_num_coords = 0;
1771  for (auto ring = 0; ring < poly_num_rings; ring++) {
1772  poly_num_coords += 2 * *next_poly_ring_sizes++;
1773  }
1774  auto poly_coords_size = poly_num_coords * compression_unit_size(ic);
1775  next_poly_coords += poly_coords_size;
1776 
1777  centroid_add_polygon(poly_coords,
1778  poly_coords_size,
1779  poly_ring_sizes,
1780  poly_num_rings,
1781  ic,
1782  isr,
1783  osr,
1784  &total_area2,
1785  &cg3[0],
1786  &total_length,
1787  &linestring_centroid_sum[0],
1788  &num_points,
1789  &point_centroid_sum[0]);
1790  }
1791 
1792  if (total_area2 != 0.0) {
1793  mpoly_centroid[0] = cg3[0] / 3 / total_area2;
1794  mpoly_centroid[1] = cg3[1] / 3 / total_area2;
1795  } else if (total_length > 0.0) {
1796  // zero-area multipolygon, fall back to linear centroid
1797  mpoly_centroid[0] = linestring_centroid_sum[0] / total_length;
1798  mpoly_centroid[1] = linestring_centroid_sum[1] / total_length;
1799  } else if (num_points > 0) {
1800  // zero-area zero-length multipolygon, fall further back to point centroid
1801  mpoly_centroid[0] = point_centroid_sum[0] / num_points;
1802  mpoly_centroid[1] = point_centroid_sum[1] / num_points;
1803  } else {
1804  Point2D centroid = get_point(mpoly_coords, 0, ic, isr, osr);
1805  mpoly_centroid[0] = centroid.x;
1806  mpoly_centroid[1] = centroid.y;
1807  }
1808 }
1809 
1810 //
1811 // ST_Distance
1812 //
1813 
1815 double ST_Distance_Point_Point(int8_t* p1,
1816  int64_t p1size,
1817  int8_t* p2,
1818  int64_t p2size,
1819  int32_t ic1,
1820  int32_t isr1,
1821  int32_t ic2,
1822  int32_t isr2,
1823  int32_t osr) {
1824  Point2D const pt1 = get_point(p1, 0, ic1, isr1, osr);
1825  Point2D const pt2 = get_point(p2, 0, ic2, isr2, osr);
1826  return distance_point_point(pt1.x, pt1.y, pt2.x, pt2.y);
1827 }
1828 
1831  int64_t p1size,
1832  int8_t* p2,
1833  int64_t p2size,
1834  int32_t ic1,
1835  int32_t isr1,
1836  int32_t ic2,
1837  int32_t isr2,
1838  int32_t osr) {
1839  Point2D const pt1 = get_point(p1, 0, ic1, isr1, osr);
1840  Point2D const pt2 = get_point(p2, 0, ic2, isr2, osr);
1841  return distance_point_point_squared(pt1.x, pt1.y, pt2.x, pt2.y);
1842 }
1843 
1846  int64_t p1size,
1847  int8_t* p2,
1848  int64_t p2size,
1849  int32_t ic1,
1850  int32_t isr1,
1851  int32_t ic2,
1852  int32_t isr2,
1853  int32_t osr) {
1854  Point2D const pt1 = get_point(p1, 0, ic1, 4326, 4326);
1855  Point2D const pt2 = get_point(p2, 0, ic2, 4326, 4326);
1856  return distance_in_meters(pt1.x, pt1.y, pt2.x, pt2.y);
1857 }
1858 
1861  int64_t psize,
1862  int8_t* l,
1863  int64_t lsize,
1864  int32_t ic1,
1865  int32_t isr1,
1866  int32_t ic2,
1867  int32_t isr2,
1868  int32_t osr) {
1869  // Currently only statically indexed LineString is supported
1870  Point2D const pt = get_point(p, 0, ic1, 4326, 4326);
1871  const auto lpoints = lsize / (2 * compression_unit_size(ic2));
1872  Point2D const pl = get_point(l, 2 * (lpoints - 1), ic2, 4326, 4326);
1873  return distance_in_meters(pt.x, pt.y, pl.x, pl.y);
1874 }
1875 
1878  int64_t lsize,
1879  int8_t* p,
1880  int64_t psize,
1881  int32_t ic1,
1882  int32_t isr1,
1883  int32_t ic2,
1884  int32_t isr2,
1885  int32_t osr) {
1886  // Currently only statically indexed LineString is supported
1888  p, psize, l, lsize, ic2, isr2, ic1, isr1, osr);
1889 }
1890 
1893  int64_t psize,
1894  int8_t* mp,
1895  int64_t mpsize,
1896  int32_t ic1,
1897  int32_t isr1,
1898  int32_t ic2,
1899  int32_t isr2,
1900  int32_t osr,
1901  double threshold) {
1902  Point2D pt = get_point(p, 0, ic1, isr1, osr);
1903  auto mp_num_coords = mpsize / compression_unit_size(ic2);
1904  Point2D mpp = get_point(mp, 0, ic2, isr2, osr);
1905  double dist = distance_point_point(pt.x, pt.y, mpp.x, mpp.y);
1906  for (int32_t i = 2; i < mp_num_coords; i += 2) {
1907  mpp = get_point(mp, i, ic2, isr2, osr);
1908  double ldist = distance_point_point(pt.x, pt.y, mpp.x, mpp.y);
1909  if (dist > ldist) {
1910  dist = ldist;
1911  }
1912  if (dist <= threshold) {
1913  return dist;
1914  }
1915  }
1916  return dist;
1917 }
1918 
1921  int64_t psize,
1922  int8_t* mp,
1923  int64_t mpsize,
1924  int32_t ic1,
1925  int32_t isr1,
1926  int32_t ic2,
1927  int32_t isr2,
1928  int32_t osr,
1929  double threshold) {
1930  Point2D pt = get_point(p, 0, ic1, isr1, osr);
1931  auto mp_num_coords = mpsize / compression_unit_size(ic2);
1932  Point2D mpp = get_point(mp, 0, ic2, isr2, osr);
1933  double dist = distance_point_point_squared(pt.x, pt.y, mpp.x, mpp.y);
1934  for (int32_t i = 2; i < mp_num_coords; i += 2) {
1935  mpp = get_point(mp, i, ic2, isr2, osr);
1936  double ldist = distance_point_point_squared(pt.x, pt.y, mpp.x, mpp.y);
1937  if (dist > ldist) {
1938  dist = ldist;
1939  }
1940  if (dist <= threshold) {
1941  return dist;
1942  }
1943  }
1944  return dist;
1945 }
1946 
1948  int64_t psize,
1949  int8_t* l,
1950  int64_t lsize,
1951  int32_t ic1,
1952  int32_t isr1,
1953  int32_t ic2,
1954  int32_t isr2,
1955  int32_t osr,
1956  bool check_closed,
1957  double threshold) {
1958  Point2D pt = get_point(p, 0, ic1, isr1, osr);
1959 
1960  auto l_num_coords = lsize / compression_unit_size(ic2);
1961 
1962  Point2D l1 = get_point(l, 0, ic2, isr2, osr);
1963  Point2D l2 = get_point(l, 2, ic2, isr2, osr);
1964 
1965  double dist = distance_point_line(pt.x, pt.y, l1.x, l1.y, l2.x, l2.y);
1966  for (int32_t i = 4; i < l_num_coords; i += 2) {
1967  l1 = l2; // advance one point
1968  l2 = get_point(l, i, ic2, isr2, osr);
1969  double ldist = distance_point_line(pt.x, pt.y, l1.x, l1.y, l2.x, l2.y);
1970  if (dist > ldist) {
1971  dist = ldist;
1972  }
1973  if (dist <= threshold) {
1974  return dist;
1975  }
1976  }
1977  if (l_num_coords > 4 && check_closed) {
1978  // Also check distance to the closing edge between the first and the last points
1979  l1 = get_point(l, 0, ic2, isr2, osr);
1980  double ldist = distance_point_line(pt.x, pt.y, l1.x, l1.y, l2.x, l2.y);
1981  if (dist > ldist) {
1982  dist = ldist;
1983  }
1984  }
1985  return dist;
1986 }
1987 
1990  int64_t psize,
1991  int8_t* l,
1992  int64_t lsize,
1993  int32_t ic1,
1994  int32_t isr1,
1995  int32_t ic2,
1996  int32_t isr2,
1997  int32_t osr,
1998  double threshold) {
2000  p, psize, l, lsize, ic1, isr1, ic2, isr2, osr, true, threshold);
2001 }
2002 
2005  int64_t psize,
2006  int8_t* l,
2007  int64_t lsize,
2008  int32_t ic1,
2009  int32_t isr1,
2010  int32_t ic2,
2011  int32_t isr2,
2012  int32_t osr,
2013  double threshold) {
2015  p, psize, l, lsize, ic1, isr1, ic2, isr2, osr, false, threshold);
2016 }
2017 
2019  int64_t psize,
2020  int8_t* mls,
2021  int64_t mls_size,
2022  int32_t* mls_ls_sizes,
2023  int64_t mls_ls_num,
2024  int32_t ic1,
2025  int32_t isr1,
2026  int32_t ic2,
2027  int32_t isr2,
2028  int32_t osr,
2029  double threshold) {
2030  if (mls_ls_num <= 0) {
2031  return 0.0;
2032  }
2033  double min_distance = 0.0;
2034 
2035  auto next_linestring_coords = mls;
2036 
2037  for (auto l = 0; l < mls_ls_num; l++) {
2038  auto linestring_coords = next_linestring_coords;
2039  auto linestring_num_points = mls_ls_sizes[l];
2040  auto linestring_num_coords = 2 * linestring_num_points;
2041  auto linestring_coords_size = linestring_num_coords * compression_unit_size(ic2);
2042  next_linestring_coords += linestring_coords_size;
2043  double distance = distance_point_linestring(p,
2044  psize,
2045  linestring_coords,
2046  linestring_coords_size,
2047  ic1,
2048  isr1,
2049  ic2,
2050  isr2,
2051  osr,
2052  false,
2053  threshold);
2054  if (l == 0 || min_distance > distance) {
2055  min_distance = distance;
2056  if (tol_zero(min_distance)) {
2057  min_distance = 0.0;
2058  break;
2059  }
2060  if (min_distance <= threshold) {
2061  break;
2062  }
2063  }
2064  }
2065 
2066  return min_distance;
2067 }
2068 
2071  int64_t psize,
2072  int8_t* mls,
2073  int64_t mls_size,
2074  int32_t* mls_ls_sizes,
2075  int64_t mls_ls_num,
2076  int32_t ic1,
2077  int32_t isr1,
2078  int32_t ic2,
2079  int32_t isr2,
2080  int32_t osr,
2081  double threshold) {
2083  psize,
2084  mls,
2085  mls_size,
2086  mls_ls_sizes,
2087  mls_ls_num,
2088  ic1,
2089  isr1,
2090  ic2,
2091  isr2,
2092  osr,
2093  threshold);
2094 }
2095 
2097  int64_t psize,
2098  int8_t* poly,
2099  int64_t polysize,
2100  int32_t* poly_ring_sizes,
2101  int64_t poly_num_rings,
2102  int32_t ic1,
2103  int32_t isr1,
2104  int32_t ic2,
2105  int32_t isr2,
2106  int32_t osr,
2107  double threshold) {
2108  auto exterior_ring_num_coords = polysize / compression_unit_size(ic2);
2109  if (poly_num_rings > 0) {
2110  exterior_ring_num_coords = poly_ring_sizes[0] * 2;
2111  }
2112  auto exterior_ring_coords_size = exterior_ring_num_coords * compression_unit_size(ic2);
2113 
2114  Point2D pt = get_point(p, 0, ic1, isr1, osr);
2116  poly, exterior_ring_num_coords, pt.x, pt.y, ic2, isr2, osr)) {
2117  // Outside the exterior ring
2119  p, psize, poly, exterior_ring_coords_size, ic1, isr1, ic2, isr2, osr, threshold);
2120  }
2121  // Inside exterior ring
2122  // Advance to first interior ring
2123  poly += exterior_ring_coords_size;
2124  // Check if one of the polygon's holes contains that point
2125  for (auto r = 1; r < poly_num_rings; r++) {
2126  auto interior_ring_num_coords = poly_ring_sizes[r] * 2;
2127  auto interior_ring_coords_size =
2128  interior_ring_num_coords * compression_unit_size(ic2);
2130  poly, interior_ring_num_coords, pt.x, pt.y, ic2, isr2, osr)) {
2131  // Inside an interior ring
2133  psize,
2134  poly,
2135  interior_ring_coords_size,
2136  ic1,
2137  isr1,
2138  ic2,
2139  isr2,
2140  osr,
2141  threshold);
2142  }
2143  poly += interior_ring_coords_size;
2144  }
2145  return 0.0;
2146 }
2147 
2149  int64_t psize,
2150  int8_t* mpoly_coords,
2151  int64_t mpoly_coords_size,
2152  int32_t* mpoly_ring_sizes,
2153  int64_t mpoly_num_rings,
2154  int32_t* mpoly_poly_sizes,
2155  int64_t mpoly_num_polys,
2156  int32_t ic1,
2157  int32_t isr1,
2158  int32_t ic2,
2159  int32_t isr2,
2160  int32_t osr,
2161  double threshold) {
2162  if (mpoly_num_polys <= 0) {
2163  return 0.0;
2164  }
2165  double min_distance = 0.0;
2166 
2167  // Set specific poly pointers as we move through the coords/ringsizes/polyrings arrays.
2168  auto next_poly_coords = mpoly_coords;
2169  auto next_poly_ring_sizes = mpoly_ring_sizes;
2170 
2171  for (auto poly = 0; poly < mpoly_num_polys; poly++) {
2172  auto poly_coords = next_poly_coords;
2173  auto poly_ring_sizes = next_poly_ring_sizes;
2174  auto poly_num_rings = mpoly_poly_sizes[poly];
2175  // Count number of coords in all of poly's rings, advance ring size pointer.
2176  int32_t poly_num_coords = 0;
2177  for (auto ring = 0; ring < poly_num_rings; ring++) {
2178  poly_num_coords += 2 * *next_poly_ring_sizes++;
2179  }
2180  auto poly_coords_size = poly_num_coords * compression_unit_size(ic2);
2181  next_poly_coords += poly_coords_size;
2182  double distance = distance_point_polygon(p,
2183  psize,
2184  poly_coords,
2185  poly_coords_size,
2186  poly_ring_sizes,
2187  poly_num_rings,
2188  ic1,
2189  isr1,
2190  ic2,
2191  isr2,
2192  osr,
2193  threshold);
2194  if (poly == 0 || min_distance > distance) {
2195  min_distance = distance;
2196  if (tol_zero(min_distance)) {
2197  min_distance = 0.0;
2198  break;
2199  }
2200  if (min_distance <= threshold) {
2201  break;
2202  }
2203  }
2204  }
2205 
2206  return min_distance;
2207 }
2208 
2210 double ST_Distance_Point_Polygon(int8_t* p,
2211  int64_t psize,
2212  int8_t* poly,
2213  int64_t polysize,
2214  int32_t* poly_ring_sizes,
2215  int64_t poly_num_rings,
2216  int32_t ic1,
2217  int32_t isr1,
2218  int32_t ic2,
2219  int32_t isr2,
2220  int32_t osr,
2221  double threshold) {
2222  return distance_point_polygon(p,
2223  psize,
2224  poly,
2225  polysize,
2226  poly_ring_sizes,
2227  poly_num_rings,
2228  ic1,
2229  isr1,
2230  ic2,
2231  isr2,
2232  osr,
2233  threshold);
2234 }
2235 
2238  int64_t psize,
2239  int8_t* mpoly_coords,
2240  int64_t mpoly_coords_size,
2241  int32_t* mpoly_ring_sizes,
2242  int64_t mpoly_num_rings,
2243  int32_t* mpoly_poly_sizes,
2244  int64_t mpoly_num_polys,
2245  int32_t ic1,
2246  int32_t isr1,
2247  int32_t ic2,
2248  int32_t isr2,
2249  int32_t osr,
2250  double threshold) {
2251  return distance_point_multipolygon(p,
2252  psize,
2253  mpoly_coords,
2254  mpoly_coords_size,
2255  mpoly_ring_sizes,
2256  mpoly_num_rings,
2257  mpoly_poly_sizes,
2258  mpoly_num_polys,
2259  ic1,
2260  isr1,
2261  ic2,
2262  isr2,
2263  osr,
2264  threshold);
2265 }
2266 
2269  int64_t mpsize,
2270  int8_t* poly,
2271  int64_t polysize,
2272  int32_t* poly_ring_sizes,
2273  int64_t poly_num_rings,
2274  int32_t ic1,
2275  int32_t isr1,
2276  int32_t ic2,
2277  int32_t isr2,
2278  int32_t osr,
2279  double threshold) {
2280  auto mp_num_coords = mpsize / compression_unit_size(ic1);
2281  auto* p = mp;
2282  auto const psize = compression_unit_size(ic1) * 2;
2283  auto dist = distance_point_polygon(p,
2284  psize,
2285  poly,
2286  polysize,
2287  poly_ring_sizes,
2288  poly_num_rings,
2289  ic1,
2290  isr1,
2291  ic2,
2292  isr2,
2293  osr,
2294  threshold);
2295  p += psize;
2296  for (int32_t i = 2; i < mp_num_coords; i += 2) {
2297  auto ldist = distance_point_polygon(p,
2298  psize,
2299  poly,
2300  polysize,
2301  poly_ring_sizes,
2302  poly_num_rings,
2303  ic1,
2304  isr1,
2305  ic2,
2306  isr2,
2307  osr,
2308  threshold);
2309  p += psize;
2310  if (dist > ldist) {
2311  dist = ldist;
2312  }
2313  if (dist <= threshold) {
2314  return dist;
2315  }
2316  }
2317  return dist;
2318 }
2319 
2322  int64_t mpsize,
2323  int8_t* mpoly_coords,
2324  int64_t mpoly_coords_size,
2325  int32_t* mpoly_ring_sizes,
2326  int64_t mpoly_num_rings,
2327  int32_t* mpoly_poly_sizes,
2328  int64_t mpoly_num_polys,
2329  int32_t ic1,
2330  int32_t isr1,
2331  int32_t ic2,
2332  int32_t isr2,
2333  int32_t osr,
2334  double threshold) {
2335  auto mp_num_coords = mpsize / compression_unit_size(ic1);
2336  auto* p = mp;
2337  auto const psize = compression_unit_size(ic1) * 2;
2338  auto dist = distance_point_multipolygon(p,
2339  psize,
2340  mpoly_coords,
2341  mpoly_coords_size,
2342  mpoly_ring_sizes,
2343  mpoly_num_rings,
2344  mpoly_poly_sizes,
2345  mpoly_num_polys,
2346  ic1,
2347  isr1,
2348  ic2,
2349  isr2,
2350  osr,
2351  threshold);
2352  p += psize;
2353  for (int32_t i = 2; i < mp_num_coords; i += 2) {
2354  auto ldist = distance_point_multipolygon(p,
2355  psize,
2356  mpoly_coords,
2357  mpoly_coords_size,
2358  mpoly_ring_sizes,
2359  mpoly_num_rings,
2360  mpoly_poly_sizes,
2361  mpoly_num_polys,
2362  ic1,
2363  isr1,
2364  ic2,
2365  isr2,
2366  osr,
2367  threshold);
2368  p += psize;
2369  if (dist > ldist) {
2370  dist = ldist;
2371  }
2372  if (dist <= threshold) {
2373  return dist;
2374  }
2375  }
2376  return dist;
2377 }
2378 
2381  int64_t polysize,
2382  int32_t* poly_ring_sizes,
2383  int64_t poly_num_rings,
2384  int8_t* mp,
2385  int64_t mpsize,
2386  int32_t ic1,
2387  int32_t isr1,
2388  int32_t ic2,
2389  int32_t isr2,
2390  int32_t osr,
2391  double threshold) {
2393  mpsize,
2394  poly,
2395  polysize,
2396  poly_ring_sizes,
2397  poly_num_rings,
2398  ic2,
2399  isr2,
2400  ic1,
2401  isr1,
2402  osr,
2403  threshold);
2404 }
2405 
2407 double ST_Distance_MultiPolygon_MultiPoint(int8_t* mpoly_coords,
2408  int64_t mpoly_coords_size,
2409  int32_t* mpoly_ring_sizes,
2410  int64_t mpoly_num_rings,
2411  int32_t* mpoly_poly_sizes,
2412  int64_t mpoly_num_polys,
2413  int8_t* mp,
2414  int64_t mpsize,
2415  int32_t ic1,
2416  int32_t isr1,
2417  int32_t ic2,
2418  int32_t isr2,
2419  int32_t osr,
2420  double threshold) {
2422  mpsize,
2423  mpoly_coords,
2424  mpoly_coords_size,
2425  mpoly_ring_sizes,
2426  mpoly_num_rings,
2427  mpoly_poly_sizes,
2428  mpoly_num_polys,
2429  ic2,
2430  isr2,
2431  ic1,
2432  isr1,
2433  osr,
2434  threshold);
2435 }
2436 
2439  int64_t mpsize,
2440  int8_t* p,
2441  int64_t psize,
2442  int32_t ic1,
2443  int32_t isr1,
2444  int32_t ic2,
2445  int32_t isr2,
2446  int32_t osr,
2447  double threshold) {
2449  p, psize, mp, mpsize, ic2, isr2, ic1, isr1, osr, threshold);
2450 }
2451 
2454  int64_t mpsize,
2455  int8_t* p,
2456  int64_t psize,
2457  int32_t ic1,
2458  int32_t isr1,
2459  int32_t ic2,
2460  int32_t isr2,
2461  int32_t osr,
2462  double threshold) {
2464  p, psize, mp, mpsize, ic2, isr2, ic1, isr1, osr, threshold);
2465 }
2466 
2469  int64_t mp1size,
2470  int8_t* mp2,
2471  int64_t mp2size,
2472  int32_t ic1,
2473  int32_t isr1,
2474  int32_t ic2,
2475  int32_t isr2,
2476  int32_t osr,
2477  double threshold) {
2478  auto mp1_num_coords = mp1size / compression_unit_size(ic1);
2479  auto mp2_num_coords = mp2size / compression_unit_size(ic2);
2480  double dist = -1.0;
2481  for (int32_t i = 0; i < mp1_num_coords; i += 2) {
2482  Point2D mp1p = get_point(mp1, 0, ic1, isr1, osr);
2483  for (int32_t j = 0; j < mp2_num_coords; j += 2) {
2484  Point2D mp2p = get_point(mp2, 0, ic2, isr2, osr);
2485  double ldist = distance_point_point(mp1p.x, mp1p.y, mp2p.x, mp2p.y);
2486  if (dist > ldist || dist < 0.0) {
2487  dist = ldist;
2488  }
2489  if (dist <= threshold) {
2490  return dist;
2491  }
2492  }
2493  }
2494  return dist;
2495 }
2496 
2499  int64_t mp1size,
2500  int8_t* mp2,
2501  int64_t mp2size,
2502  int32_t ic1,
2503  int32_t isr1,
2504  int32_t ic2,
2505  int32_t isr2,
2506  int32_t osr,
2507  double threshold) {
2508  auto mp1_num_coords = mp1size / compression_unit_size(ic1);
2509  auto mp2_num_coords = mp2size / compression_unit_size(ic2);
2510  double dist = -1.0;
2511  for (int32_t i = 0; i < mp1_num_coords; i += 2) {
2512  Point2D mp1p = get_point(mp1, i, ic1, isr1, osr);
2513  for (int32_t j = 0; j < mp2_num_coords; j += 2) {
2514  Point2D mp2p = get_point(mp2, j, ic2, isr2, osr);
2515  double ldist = distance_point_point_squared(mp1p.x, mp1p.y, mp2p.x, mp2p.y);
2516  if (dist > ldist || dist < 0.0) {
2517  dist = ldist;
2518  }
2519  if (dist <= threshold) {
2520  return dist;
2521  }
2522  }
2523  }
2524  return dist;
2525 }
2526 
2529  int64_t mpsize,
2530  int8_t* l,
2531  int64_t lsize,
2532  int32_t ic1,
2533  int32_t isr1,
2534  int32_t ic2,
2535  int32_t isr2,
2536  int32_t osr,
2537  double threshold) {
2538  auto mp_num_coords = mpsize / compression_unit_size(ic1);
2539  auto* p = mp;
2540  auto const psize = compression_unit_size(ic1) * 2;
2541  auto dist = distance_point_linestring(
2542  p, psize, l, lsize, ic1, isr1, ic2, isr2, osr, true, threshold);
2543  p += psize;
2544  for (int32_t i = 2; i < mp_num_coords; i += 2) {
2545  auto ldist = distance_point_linestring(
2546  p, psize, l, lsize, ic1, isr1, ic2, isr2, osr, true, threshold);
2547  p += psize;
2548  if (dist > ldist) {
2549  dist = ldist;
2550  }
2551  if (dist <= threshold) {
2552  return dist;
2553  }
2554  }
2555  return dist;
2556 }
2557 
2560  int64_t mpsize,
2561  int8_t* mls,
2562  int64_t mls_size,
2563  int32_t* mls_ls_sizes,
2564  int64_t mls_ls_num,
2565  int32_t ic1,
2566  int32_t isr1,
2567  int32_t ic2,
2568  int32_t isr2,
2569  int32_t osr,
2570  double threshold) {
2571  auto mp_num_coords = mpsize / compression_unit_size(ic1);
2572  auto* p = mp;
2573  auto const psize = compression_unit_size(ic1) * 2;
2574  auto dist = distance_point_multilinestring(p,
2575  psize,
2576  mls,
2577  mls_size,
2578  mls_ls_sizes,
2579  mls_ls_num,
2580  ic1,
2581  isr1,
2582  ic2,
2583  isr2,
2584  osr,
2585  threshold);
2586  p += psize;
2587  for (int32_t i = 2; i < mp_num_coords; i += 2) {
2588  auto ldist = distance_point_multilinestring(p,
2589  psize,
2590  mls,
2591  mls_size,
2592  mls_ls_sizes,
2593  mls_ls_num,
2594  ic1,
2595  isr1,
2596  ic2,
2597  isr2,
2598  osr,
2599  threshold);
2600  p += psize;
2601  if (dist > ldist) {
2602  dist = ldist;
2603  }
2604  if (dist <= threshold) {
2605  return dist;
2606  }
2607  }
2608  return dist;
2609 }
2610 
2613  int64_t lsize,
2614  int8_t* p,
2615  int64_t psize,
2616  int32_t ic1,
2617  int32_t isr1,
2618  int32_t ic2,
2619  int32_t isr2,
2620  int32_t osr,
2621  double threshold) {
2623  p, psize, l, lsize, ic2, isr2, ic1, isr1, osr, threshold);
2624 }
2625 
2628  int64_t lsize,
2629  int8_t* mp,
2630  int64_t mpsize,
2631  int32_t ic1,
2632  int32_t isr1,
2633  int32_t ic2,
2634  int32_t isr2,
2635  int32_t osr,
2636  double threshold) {
2638  mp, mpsize, l, lsize, ic2, isr2, ic1, isr1, osr, threshold);
2639 }
2640 
2643  int64_t mls_size,
2644  int32_t* mls_ls_sizes,
2645  int64_t mls_ls_num,
2646  int8_t* mp,
2647  int64_t mpsize,
2648  int32_t ic1,
2649  int32_t isr1,
2650  int32_t ic2,
2651  int32_t isr2,
2652  int32_t osr,
2653  double threshold) {
2655  mpsize,
2656  mls,
2657  mls_size,
2658  mls_ls_sizes,
2659  mls_ls_num,
2660  ic2,
2661  isr2,
2662  ic1,
2663  isr1,
2664  osr,
2665  threshold);
2666 }
2667 
2670  int64_t l1size,
2671  int8_t* l2,
2672  int64_t l2size,
2673  int32_t ic1,
2674  int32_t isr1,
2675  int32_t ic2,
2676  int32_t isr2,
2677  int32_t osr,
2678  double threshold) {
2679  auto l1_num_coords = l1size / compression_unit_size(ic1);
2680  auto l2_num_coords = l2size / compression_unit_size(ic2);
2681 
2682  double threshold_squared = threshold * threshold;
2683  double dist_squared = 0.0;
2684  Point2D l11 = get_point(l1, 0, ic1, isr1, osr);
2685  for (int32_t i1 = 2; i1 < l1_num_coords; i1 += 2) {
2686  Point2D l12 = get_point(l1, i1, ic1, isr1, osr);
2687  Point2D l21 = get_point(l2, 0, ic2, isr2, osr);
2688  for (int32_t i2 = 2; i2 < l2_num_coords; i2 += 2) {
2689  Point2D l22 = get_point(l2, i2, ic2, isr2, osr);
2690 
2691  // double ldist_squared =
2692  // distance_line_line_squared(l11x, l11y, l12x, l12y, l21x, l21y, l22x, l22y);
2693  // TODO: fix distance_line_line_squared
2694  double ldist =
2695  distance_line_line(l11.x, l11.y, l12.x, l12.y, l21.x, l21.y, l22.x, l22.y);
2696  double ldist_squared = ldist * ldist;
2697 
2698  if (i1 == 2 && i2 == 2) {
2699  dist_squared = ldist_squared; // initialize dist with distance between the first
2700  // two segments
2701  } else if (dist_squared > ldist_squared) {
2702  dist_squared = ldist_squared;
2703  }
2704  if (tol_zero(dist_squared, TOLERANCE_DEFAULT_SQUARED)) {
2705  return 0.0; // Segments touch, short-circuit
2706  }
2707  if (dist_squared <= threshold_squared) {
2708  // If threashold_squared is defined and the calculated dist_squared dips under it,
2709  // short-circuit and return it
2710  return sqrt(dist_squared);
2711  }
2712 
2713  l21 = l22; // advance to the next point on l2
2714  }
2715 
2716  l11 = l12; // advance to the next point on l1
2717  }
2718  return sqrt(dist_squared);
2719 }
2720 
2723  int64_t lsize,
2724  int8_t* poly_coords,
2725  int64_t poly_coords_size,
2726  int32_t* poly_ring_sizes,
2727  int64_t poly_num_rings,
2728  int32_t ic1,
2729  int32_t isr1,
2730  int32_t ic2,
2731  int32_t isr2,
2732  int32_t osr,
2733  double threshold) {
2734  auto lnum_coords = lsize / compression_unit_size(ic1);
2735  auto psize = 2 * compression_unit_size(ic1);
2736  auto min_distance =
2737  ST_Distance_Point_Polygon(l, // pointer to start of linestring for first point
2738  psize,
2739  poly_coords,
2740  poly_coords_size,
2741  poly_ring_sizes,
2742  poly_num_rings,
2743  ic1,
2744  isr1,
2745  ic2,
2746  isr2,
2747  osr,
2748  threshold);
2749  if (tol_zero(min_distance)) {
2750  // Linestring's first point is inside the poly
2751  return 0.0;
2752  }
2753  if (min_distance <= threshold) {
2754  return min_distance;
2755  }
2756 
2757  // Otherwise, linestring's first point is outside the external ring or inside
2758  // an internal ring. Measure minimum distance between linestring segments and
2759  // poly rings. Crossing a ring zeroes the distance and causes an early return.
2760  auto poly_ring_coords = poly_coords;
2761  for (auto r = 0; r < poly_num_rings; r++) {
2762  int64_t poly_ring_num_coords = poly_ring_sizes[r] * 2;
2763 
2764  auto distance = distance_ring_linestring(poly_ring_coords,
2765  poly_ring_num_coords,
2766  l,
2767  lnum_coords,
2768  ic2,
2769  isr2,
2770  ic1,
2771  isr1,
2772  osr,
2773  threshold);
2774  if (min_distance > distance) {
2775  min_distance = distance;
2776  if (tol_zero(min_distance)) {
2777  return 0.0;
2778  }
2779  if (min_distance <= threshold) {
2780  return min_distance;
2781  }
2782  }
2783 
2784  poly_ring_coords += poly_ring_num_coords * compression_unit_size(ic2);
2785  }
2786 
2787  return min_distance;
2788 }
2789 
2792  int64_t lsize,
2793  int8_t* mpoly_coords,
2794  int64_t mpoly_coords_size,
2795  int32_t* mpoly_ring_sizes,
2796  int64_t mpoly_num_rings,
2797  int32_t* mpoly_poly_sizes,
2798  int64_t mpoly_num_polys,
2799  int32_t ic1,
2800  int32_t isr1,
2801  int32_t ic2,
2802  int32_t isr2,
2803  int32_t osr,
2804  double threshold) {
2805  // TODO: revisit implementation, cover all cases
2806  double min_distance = 0.0;
2807 
2808  // Set specific poly pointers as we move through the coords/ringsizes/polyrings arrays.
2809  auto next_poly_coords = mpoly_coords;
2810  auto next_poly_ring_sizes = mpoly_ring_sizes;
2811 
2812  for (auto poly = 0; poly < mpoly_num_polys; poly++) {
2813  auto poly_coords = next_poly_coords;
2814  auto poly_ring_sizes = next_poly_ring_sizes;
2815  auto poly_num_rings = mpoly_poly_sizes[poly];
2816  // Count number of coords in all of poly's rings, advance ring size pointer.
2817  int32_t poly_num_coords = 0;
2818  for (auto ring = 0; ring < poly_num_rings; ring++) {
2819  poly_num_coords += 2 * *next_poly_ring_sizes++;
2820  }
2821  auto poly_coords_size = poly_num_coords * compression_unit_size(ic2);
2822  next_poly_coords += poly_coords_size;
2823  double distance = ST_Distance_LineString_Polygon(l,
2824  lsize,
2825  poly_coords,
2826  poly_coords_size,
2827  poly_ring_sizes,
2828  poly_num_rings,
2829  ic1,
2830  isr1,
2831  ic2,
2832  isr2,
2833  osr,
2834  threshold);
2835  if (poly == 0 || min_distance > distance) {
2836  min_distance = distance;
2837  if (tol_zero(min_distance)) {
2838  min_distance = 0.0;
2839  break;
2840  }
2841  if (min_distance <= threshold) {
2842  return min_distance;
2843  }
2844  }
2845  }
2846 
2847  return min_distance;
2848 }
2849 
2852  int64_t mls_size,
2853  int32_t* mls_ls_sizes,
2854  int64_t mls_ls_num,
2855  int8_t* p,
2856  int64_t psize,
2857  int32_t ic1,
2858  int32_t isr1,
2859  int32_t ic2,
2860  int32_t isr2,
2861  int32_t osr,
2862  double threshold) {
2864  psize,
2865  mls,
2866  mls_size,
2867  mls_ls_sizes,
2868  mls_ls_num,
2869  ic2,
2870  isr2,
2871  ic1,
2872  isr1,
2873  osr,
2874  threshold);
2875 }
2876 
2878 double ST_Distance_Polygon_Point(int8_t* poly_coords,
2879  int64_t poly_coords_size,
2880  int32_t* poly_ring_sizes,
2881  int64_t poly_num_rings,
2882  int8_t* p,
2883  int64_t psize,
2884  int32_t ic1,
2885  int32_t isr1,
2886  int32_t ic2,
2887  int32_t isr2,
2888  int32_t osr,
2889  double threshold) {
2890  return ST_Distance_Point_Polygon(p,
2891  psize,
2892  poly_coords,
2893  poly_coords_size,
2894  poly_ring_sizes,
2895  poly_num_rings,
2896  ic2,
2897  isr2,
2898  ic1,
2899  isr1,
2900  osr,
2901  threshold);
2902 }
2903 
2905 double ST_Distance_Polygon_LineString(int8_t* poly_coords,
2906  int64_t poly_coords_size,
2907  int32_t* poly_ring_sizes,
2908  int64_t poly_num_rings,
2909  int8_t* l,
2910  int64_t lsize,
2911  int32_t ic1,
2912  int32_t isr1,
2913  int32_t ic2,
2914  int32_t isr2,
2915  int32_t osr,
2916  double threshold) {
2918  lsize,
2919  poly_coords,
2920  poly_coords_size,
2921  poly_ring_sizes,
2922  poly_num_rings,
2923  ic2,
2924  isr2,
2925  ic1,
2926  isr2,
2927  osr,
2928  threshold);
2929 }
2930 
2932 double ST_Distance_Polygon_Polygon(int8_t* poly1_coords,
2933  int64_t poly1_coords_size,
2934  int32_t* poly1_ring_sizes,
2935  int64_t poly1_num_rings,
2936  int8_t* poly2_coords,
2937  int64_t poly2_coords_size,
2938  int32_t* poly2_ring_sizes,
2939  int64_t poly2_num_rings,
2940  int32_t ic1,
2941  int32_t isr1,
2942  int32_t ic2,
2943  int32_t isr2,
2944  int32_t osr,
2945  double threshold) {
2946  // Check if poly1 contains the first point of poly2's shape, i.e. the external ring
2947  auto poly2_first_point_coords = poly2_coords;
2948  auto poly2_first_point_coords_size = compression_unit_size(ic2) * 2;
2949  auto min_distance = ST_Distance_Polygon_Point(poly1_coords,
2950  poly1_coords_size,
2951  poly1_ring_sizes,
2952  poly1_num_rings,
2953  poly2_first_point_coords,
2954  poly2_first_point_coords_size,
2955  ic1,
2956  isr1,
2957  ic2,
2958  isr2,
2959  osr,
2960  threshold);
2961  if (tol_zero(min_distance)) {
2962  // Polygons overlap
2963  return 0.0;
2964  }
2965  if (min_distance <= threshold) {
2966  return min_distance;
2967  }
2968 
2969  // Poly2's first point is either outside poly1's external ring or inside one of the
2970  // internal rings. Measure the smallest distance between a poly1 ring (external or
2971  // internal) and a poly2 ring (external or internal). If poly2 is completely outside
2972  // poly1, then the min distance would be between poly1's and poly2's external rings. If
2973  // poly2 is completely inside one of poly1 internal rings then the min distance would be
2974  // between that poly1 internal ring and poly2's external ring. If poly1 is completely
2975  // inside one of poly2 internal rings, min distance is between that internal ring and
2976  // poly1's external ring. In each case other rings don't get in the way. Any ring
2977  // intersection means zero distance - short-circuit and return.
2978 
2979  auto poly1_ring_coords = poly1_coords;
2980  for (auto r1 = 0; r1 < poly1_num_rings; r1++) {
2981  int64_t poly1_ring_num_coords = poly1_ring_sizes[r1] * 2;
2982 
2983  auto poly2_ring_coords = poly2_coords;
2984  for (auto r2 = 0; r2 < poly2_num_rings; r2++) {
2985  int64_t poly2_ring_num_coords = poly2_ring_sizes[r2] * 2;
2986 
2987  auto distance = distance_ring_ring(poly1_ring_coords,
2988  poly1_ring_num_coords,
2989  poly2_ring_coords,
2990  poly2_ring_num_coords,
2991  ic1,
2992  isr1,
2993  ic2,
2994  isr2,
2995  osr,
2996  threshold);
2997  if (min_distance > distance) {
2998  min_distance = distance;
2999  if (tol_zero(min_distance)) {
3000  return 0.0;
3001  }
3002  if (min_distance <= threshold) {
3003  return min_distance;
3004  }
3005  }
3006 
3007  poly2_ring_coords += poly2_ring_num_coords * compression_unit_size(ic2);
3008  }
3009 
3010  poly1_ring_coords += poly1_ring_num_coords * compression_unit_size(ic1);
3011  }
3012 
3013  return min_distance;
3014 }
3015 
3017 double ST_Distance_Polygon_MultiPolygon(int8_t* poly1_coords,
3018  int64_t poly1_coords_size,
3019  int32_t* poly1_ring_sizes,
3020  int64_t poly1_num_rings,
3021  int8_t* mpoly_coords,
3022  int64_t mpoly_coords_size,
3023  int32_t* mpoly_ring_sizes,
3024  int64_t mpoly_num_rings,
3025  int32_t* mpoly_poly_sizes,
3026  int64_t mpoly_num_polys,
3027  int32_t ic1,
3028  int32_t isr1,
3029  int32_t ic2,
3030  int32_t isr2,
3031  int32_t osr,
3032  double threshold) {
3033  double min_distance = 0.0;
3034 
3035  // Set specific poly pointers as we move through the coords/ringsizes/polyrings arrays.
3036  auto next_poly_coords = mpoly_coords;
3037  auto next_poly_ring_sizes = mpoly_ring_sizes;
3038 
3039  for (auto poly = 0; poly < mpoly_num_polys; poly++) {
3040  auto poly_coords = next_poly_coords;
3041  auto poly_ring_sizes = next_poly_ring_sizes;
3042  auto poly_num_rings = mpoly_poly_sizes[poly];
3043  // Count number of coords in all of poly's rings, advance ring size pointer.
3044  int32_t poly_num_coords = 0;
3045  for (auto ring = 0; ring < poly_num_rings; ring++) {
3046  poly_num_coords += 2 * *next_poly_ring_sizes++;
3047  }
3048  auto poly_coords_size = poly_num_coords * compression_unit_size(ic2);
3049  next_poly_coords += poly_coords_size;
3050  double distance = ST_Distance_Polygon_Polygon(poly1_coords,
3051  poly1_coords_size,
3052  poly1_ring_sizes,
3053  poly1_num_rings,
3054  poly_coords,
3055  poly_coords_size,
3056  poly_ring_sizes,
3057  poly_num_rings,
3058  ic1,
3059  isr1,
3060  ic2,
3061  isr2,
3062  osr,
3063  threshold);
3064  if (poly == 0 || min_distance > distance) {
3065  min_distance = distance;
3066  if (tol_zero(min_distance)) {
3067  min_distance = 0.0;
3068  break;
3069  }
3070  if (min_distance <= threshold) {
3071  break;
3072  }
3073  }
3074  }
3075 
3076  return min_distance;
3077 }
3078 
3080 double ST_Distance_MultiPolygon_Point(int8_t* mpoly_coords,
3081  int64_t mpoly_coords_size,
3082  int32_t* mpoly_ring_sizes,
3083  int64_t mpoly_num_rings,
3084  int32_t* mpoly_poly_sizes,
3085  int64_t mpoly_num_polys,
3086  int8_t* p,
3087  int64_t psize,
3088  int32_t ic1,
3089  int32_t isr1,
3090  int32_t ic2,
3091  int32_t isr2,
3092  int32_t osr,
3093  double threshold) {
3095  psize,
3096  mpoly_coords,
3097  mpoly_coords_size,
3098  mpoly_ring_sizes,
3099  mpoly_num_rings,
3100  mpoly_poly_sizes,
3101  mpoly_num_polys,
3102  ic2,
3103  isr2,
3104  ic1,
3105  isr1,
3106  osr,
3107  threshold);
3108 }
3109 
3111 double ST_Distance_MultiPolygon_LineString(int8_t* mpoly_coords,
3112  int64_t mpoly_coords_size,
3113  int32_t* mpoly_ring_sizes,
3114  int64_t mpoly_num_rings,
3115  int32_t* mpoly_poly_sizes,
3116  int64_t mpoly_num_polys,
3117  int8_t* l,
3118  int64_t lsize,
3119  int32_t ic1,
3120  int32_t isr1,
3121  int32_t ic2,
3122  int32_t isr2,
3123  int32_t osr,
3124  double threshold) {
3126  lsize,
3127  mpoly_coords,
3128  mpoly_coords_size,
3129  mpoly_ring_sizes,
3130  mpoly_num_rings,
3131  mpoly_poly_sizes,
3132  mpoly_num_polys,
3133  ic2,
3134  isr2,
3135  ic1,
3136  isr1,
3137  osr,
3138  threshold);
3139 }
3140 
3142 double ST_Distance_MultiPolygon_Polygon(int8_t* mpoly_coords,
3143  int64_t mpoly_coords_size,
3144  int32_t* mpoly_ring_sizes,
3145  int64_t mpoly_num_rings,
3146  int32_t* mpoly_poly_sizes,
3147  int64_t mpoly_num_polys,
3148  int8_t* poly1_coords,
3149  int64_t poly1_coords_size,
3150  int32_t* poly1_ring_sizes,
3151  int64_t poly1_num_rings,
3152  int32_t ic1,
3153  int32_t isr1,
3154  int32_t ic2,
3155  int32_t isr2,
3156  int32_t osr,
3157  double threshold) {
3158  return ST_Distance_Polygon_MultiPolygon(poly1_coords,
3159  poly1_coords_size,
3160  poly1_ring_sizes,
3161  poly1_num_rings,
3162  mpoly_coords,
3163  mpoly_coords_size,
3164  mpoly_ring_sizes,
3165  mpoly_num_rings,
3166  mpoly_poly_sizes,
3167  mpoly_num_polys,
3168  ic2,
3169  isr2,
3170  ic1,
3171  isr1,
3172  osr,
3173  threshold);
3174 }
3175 
3177 double ST_Distance_MultiPolygon_MultiPolygon(int8_t* mpoly1_coords,
3178  int64_t mpoly1_coords_size,
3179  int32_t* mpoly1_ring_sizes,
3180  int64_t mpoly1_num_rings,
3181  int32_t* mpoly1_poly_sizes,
3182  int64_t mpoly1_num_polys,
3183  int8_t* mpoly2_coords,
3184  int64_t mpoly2_coords_size,
3185  int32_t* mpoly2_ring_sizes,
3186  int64_t mpoly2_num_rings,
3187  int32_t* mpoly2_poly_sizes,
3188  int64_t mpoly2_num_polys,
3189  int32_t ic1,
3190  int32_t isr1,
3191  int32_t ic2,
3192  int32_t isr2,
3193  int32_t osr,
3194  double threshold) {
3195  double min_distance = 0.0;
3196 
3197  // Set specific poly pointers as we move through mpoly1's coords/ringsizes/polyrings
3198  // arrays.
3199  auto next_poly_coords = mpoly1_coords;
3200  auto next_poly_ring_sizes = mpoly1_ring_sizes;
3201 
3202  for (auto poly = 0; poly < mpoly1_num_polys; poly++) {
3203  auto poly_coords = next_poly_coords;
3204  auto poly_ring_sizes = next_poly_ring_sizes;
3205  auto poly_num_rings = mpoly1_poly_sizes[poly];
3206  // Count number of coords in all of poly's rings, advance ring size pointer.
3207  int32_t poly_num_coords = 0;
3208  for (auto ring = 0; ring < poly_num_rings; ring++) {
3209  poly_num_coords += 2 * *next_poly_ring_sizes++;
3210  }
3211  auto poly_coords_size = poly_num_coords * compression_unit_size(ic1);
3212  next_poly_coords += poly_coords_size;
3213  double distance = ST_Distance_Polygon_MultiPolygon(poly_coords,
3214  poly_coords_size,
3215  poly_ring_sizes,
3216  poly_num_rings,
3217  mpoly2_coords,
3218  mpoly2_coords_size,
3219  mpoly2_ring_sizes,
3220  mpoly2_num_rings,
3221  mpoly2_poly_sizes,
3222  mpoly2_num_polys,
3223  ic1,
3224  isr1,
3225  ic2,
3226  isr2,
3227  osr,
3228  threshold);
3229  if (poly == 0 || min_distance > distance) {
3230  min_distance = distance;
3231  if (tol_zero(min_distance)) {
3232  min_distance = 0.0;
3233  break;
3234  }
3235  if (min_distance <= threshold) {
3236  break;
3237  }
3238  }
3239  }
3240 
3241  return min_distance;
3242 }
3243 
3246  int64_t mls1size,
3247  int32_t* mls1_ls_sizes,
3248  int64_t mls1_ls_num,
3249  int8_t* mls2,
3250  int64_t mls2size,
3251  int32_t* mls2_ls_sizes,
3252  int64_t mls2_ls_num,
3253  int32_t ic1,
3254  int32_t isr1,
3255  int32_t ic2,
3256  int32_t isr2,
3257  int32_t osr,
3258  double threshold) {
3259  return 0.0;
3260 }
3261 
3262 //
3263 // ST_DWithin
3264 //
3265 
3267 bool ST_DWithin_Point_Point(int8_t* p1,
3268  int64_t p1size,
3269  int8_t* p2,
3270  int64_t p2size,
3271  int32_t ic1,
3272  int32_t isr1,
3273  int32_t ic2,
3274  int32_t isr2,
3275  int32_t osr,
3276  double distance_within) {
3278  p1, p1size, p2, p2size, ic1, isr1, ic2, isr2, osr) <=
3279  distance_within * distance_within;
3280 }
3281 
3284  int64_t p1size,
3285  int8_t* p2,
3286  int64_t p2size,
3287  int32_t ic1,
3288  int32_t isr1,
3289  int32_t ic2,
3290  int32_t isr2,
3291  int32_t osr,
3292  double distance_within) {
3293  auto dist_meters =
3294  ST_Distance_Point_Point_Geodesic(p1, p1size, p2, p2size, ic1, isr1, ic2, isr2, osr);
3295  return (dist_meters <= distance_within);
3296 }
3297 
3300  int64_t p1size,
3301  int8_t* l2,
3302  int64_t l2size,
3303  double* l2bounds,
3304  int64_t l2bounds_size,
3305  int32_t ic1,
3306  int32_t isr1,
3307  int32_t ic2,
3308  int32_t isr2,
3309  int32_t osr,
3310  double distance_within) {
3311  if (l2bounds) {
3312  // Bounding boxes need to be transformed to output SR before proximity check
3313  if (!point_dwithin_box(
3314  p1, p1size, ic1, isr1, l2bounds, l2bounds_size, isr2, osr, distance_within)) {
3315  return false;
3316  }
3317  }
3318 
3319  // May need to adjust the threshold by TOLERANCE_DEFAULT
3320  const double threshold = distance_within;
3322  p1, p1size, l2, l2size, ic1, isr1, ic2, isr2, osr, threshold) <=
3323  distance_within;
3324 }
3325 
3328  int64_t psize,
3329  int8_t* poly_coords,
3330  int64_t poly_coords_size,
3331  int32_t* poly_ring_sizes,
3332  int64_t poly_num_rings,
3333  double* poly_bounds,
3334  int64_t poly_bounds_size,
3335  int32_t ic1,
3336  int32_t isr1,
3337  int32_t ic2,
3338  int32_t isr2,
3339  int32_t osr,
3340  double distance_within) {
3341  if (poly_bounds) {
3342  if (!point_dwithin_box(p,
3343  psize,
3344  ic1,
3345  isr1,
3346  poly_bounds,
3347  poly_bounds_size,
3348  isr2,
3349  osr,
3350  distance_within)) {
3351  return false;
3352  }
3353  }
3354 
3355  // May need to adjust the threshold by TOLERANCE_DEFAULT
3356  const double threshold = distance_within;
3357  return ST_Distance_Point_Polygon(p,
3358  psize,
3359  poly_coords,
3360  poly_coords_size,
3361  poly_ring_sizes,
3362  poly_num_rings,
3363  ic1,
3364  isr1,
3365  ic2,
3366  isr2,
3367  osr,
3368  threshold) <= distance_within;
3369 }
3370 
3373  int64_t psize,
3374  int8_t* mpoly_coords,
3375  int64_t mpoly_coords_size,
3376  int32_t* mpoly_ring_sizes,
3377  int64_t mpoly_num_rings,
3378  int32_t* mpoly_poly_sizes,
3379  int64_t mpoly_num_polys,
3380  double* mpoly_bounds,
3381  int64_t mpoly_bounds_size,
3382  int32_t ic1,
3383  int32_t isr1,
3384  int32_t ic2,
3385  int32_t isr2,
3386  int32_t osr,
3387  double distance_within) {
3388  if (mpoly_bounds) {
3389  if (!point_dwithin_box(p,
3390  psize,
3391  ic1,
3392  isr1,
3393  mpoly_bounds,
3394  mpoly_bounds_size,
3395  isr2,
3396  osr,
3397  distance_within)) {
3398  return false;
3399  }
3400  }
3401 
3402  // May need to adjust the threshold by TOLERANCE_DEFAULT
3403  const double threshold = distance_within;
3405  psize,
3406  mpoly_coords,
3407  mpoly_coords_size,
3408  mpoly_ring_sizes,
3409  mpoly_num_rings,
3410  mpoly_poly_sizes,
3411  mpoly_num_polys,
3412  ic1,
3413  isr1,
3414  ic2,
3415  isr2,
3416  osr,
3417  threshold) <= distance_within;
3418 }
3419 
3422  int64_t l1size,
3423  double* l1bounds,
3424  int64_t l1bounds_size,
3425  int8_t* l2,
3426  int64_t l2size,
3427  double* l2bounds,
3428  int64_t l2bounds_size,
3429  int32_t ic1,
3430  int32_t isr1,
3431  int32_t ic2,
3432  int32_t isr2,
3433  int32_t osr,
3434  double distance_within) {
3435  if (l1bounds && l2bounds) {
3436  // Bounding boxes need to be transformed to output SR before proximity check
3437  if (!box_dwithin_box(l1bounds,
3438  l1bounds_size,
3439  isr1,
3440  l2bounds,
3441  l2bounds_size,
3442  isr2,
3443  osr,
3444  distance_within)) {
3445  return false;
3446  }
3447  }
3448 
3449  // May need to adjust the threshold by TOLERANCE_DEFAULT
3450  const double threshold = distance_within;
3452  l1, l1size, l2, l2size, ic1, isr1, ic2, isr2, osr, threshold) <=
3453  distance_within;
3454 }
3455 
3458  int64_t l1size,
3459  double* l1bounds,
3460  int64_t l1bounds_size,
3461  int8_t* poly_coords,
3462  int64_t poly_coords_size,
3463  int32_t* poly_ring_sizes,
3464  int64_t poly_num_rings,
3465  double* poly_bounds,
3466  int64_t poly_bounds_size,
3467  int32_t ic1,
3468  int32_t isr1,
3469  int32_t ic2,
3470  int32_t isr2,
3471  int32_t osr,
3472  double distance_within) {
3473  if (l1bounds && poly_bounds) {
3474  // Bounding boxes need to be transformed to output SR before proximity check
3475  if (!box_dwithin_box(l1bounds,
3476  l1bounds_size,
3477  isr1,
3478  poly_bounds,
3479  poly_bounds_size,
3480  isr2,
3481  osr,
3482  distance_within)) {
3483  return false;
3484  }
3485  }
3486 
3487  // First, assume the entire linestring is relevant.
3488  CoordData l1_relevant_section{l1, l1size};
3489  // Mitigation for very long linestrings (5+ segments: think highways, powerlines)
3490  if (poly_bounds && l1size > 12 * compression_unit_size(ic1)) {
3491  // Before diving into distance calculations, try to trim the linestring just to
3492  // segments whose bounding boxes overlap the threshold-buffered poly bounding box.
3493  l1_relevant_section = trim_linestring_to_buffered_box(
3494  l1, l1size, ic1, isr1, poly_bounds, poly_bounds_size, isr2, osr, distance_within);
3495  if (!l1_relevant_section.ptr) {
3496  // The big short-circuit: if not a single segment's bounding box overlaped
3497  // with buffered poly bounding box, then it means that the entire linestring
3498  // doesn't come close enough to the polygon to be within distance.
3499  // The global bounding boxes for the input geometries may overlap but the linestring
3500  // never gets close enough to the poly to require an actual distance calculation.
3501  return false;
3502  }
3503  }
3504 
3505  // May need to adjust the threshold by TOLERANCE_DEFAULT
3506  const double threshold = distance_within;
3507  return ST_Distance_LineString_Polygon(l1_relevant_section.ptr,
3508  l1_relevant_section.size,
3509  poly_coords,
3510  poly_coords_size,
3511  poly_ring_sizes,
3512  poly_num_rings,
3513  ic1,
3514  isr1,
3515  ic2,
3516  isr2,
3517  osr,
3518  threshold) <= distance_within;
3519 }
3520 
3523  int64_t l1size,
3524  double* l1bounds,
3525  int64_t l1bounds_size,
3526  int8_t* mpoly_coords,
3527  int64_t mpoly_coords_size,
3528  int32_t* mpoly_ring_sizes,
3529  int64_t mpoly_num_rings,
3530  int32_t* mpoly_poly_sizes,
3531  int64_t mpoly_num_polys,
3532  double* mpoly_bounds,
3533  int64_t mpoly_bounds_size,
3534  int32_t ic1,
3535  int32_t isr1,
3536  int32_t ic2,
3537  int32_t isr2,
3538  int32_t osr,
3539  double distance_within) {
3540  if (l1bounds && mpoly_bounds) {
3541  // Bounding boxes need to be transformed to output SR before proximity check
3542  if (!box_dwithin_box(l1bounds,
3543  l1bounds_size,
3544  isr1,
3545  mpoly_bounds,
3546  mpoly_bounds_size,
3547  isr2,
3548  osr,
3549  distance_within)) {
3550  return false;
3551  }
3552  }
3553 
3554  // First, assume the entire linestring is relevant.
3555  CoordData l1_relevant_section{l1, l1size};
3556  // Mitigation for very long linestrings (5+ segments: think highways, powerlines)
3557  if (mpoly_bounds && l1size > 12 * compression_unit_size(ic1)) {
3558  // Before diving into distance calculations, try to trim the linestring just to
3559  // segments whose bounding boxes overlap the threshold-buffered mpoly bounding box.
3560  l1_relevant_section = trim_linestring_to_buffered_box(l1,
3561  l1size,
3562  ic1,
3563  isr1,
3564  mpoly_bounds,
3565  mpoly_bounds_size,
3566  isr2,
3567  osr,
3568  distance_within);
3569  if (!l1_relevant_section.ptr) {
3570  // The big short-circuit: if not a single segment's bounding box overlaped
3571  // with buffered mpoly bounding box, then it means that the entire linestring
3572  // doesn't come close enough to the multipolygon to be within distance.
3573  // The global bounding boxes for the input geometries may overlap but the linestring
3574  // never gets close enough to the mpoly to require an actual distance calculation.
3575  return false;
3576  }
3577  }
3578 
3579  // Run distance calculation but only on the linestring section that is relevant.
3580  // May need to adjust the threshold by TOLERANCE_DEFAULT
3581  const double threshold = distance_within;
3582  return ST_Distance_LineString_MultiPolygon(l1_relevant_section.ptr,
3583  l1_relevant_section.size,
3584  mpoly_coords,
3585  mpoly_coords_size,
3586  mpoly_ring_sizes,
3587  mpoly_num_rings,
3588  mpoly_poly_sizes,
3589  mpoly_num_polys,
3590  ic1,
3591  isr1,
3592  ic2,
3593  isr2,
3594  osr,
3595  threshold) <= distance_within;
3596 }
3597 
3599 bool ST_DWithin_Polygon_Polygon(int8_t* poly1_coords,
3600  int64_t poly1_coords_size,
3601  int32_t* poly1_ring_sizes,
3602  int64_t poly1_num_rings,
3603  double* poly1_bounds,
3604  int64_t poly1_bounds_size,
3605  int8_t* poly2_coords,
3606  int64_t poly2_coords_size,
3607  int32_t* poly2_ring_sizes,
3608  int64_t poly2_num_rings,
3609  double* poly2_bounds,
3610  int64_t poly2_bounds_size,
3611  int32_t ic1,
3612  int32_t isr1,
3613  int32_t ic2,
3614  int32_t isr2,
3615  int32_t osr,
3616  double distance_within) {
3617  if (poly1_bounds && poly2_bounds) {
3618  // Bounding boxes need to be transformed to output SR before proximity check
3619  if (!box_dwithin_box(poly1_bounds,
3620  poly1_bounds_size,
3621  isr1,
3622  poly2_bounds,
3623  poly2_bounds_size,
3624  isr2,
3625  osr,
3626  distance_within)) {
3627  return false;
3628  }
3629  }
3630 
3631  // May need to adjust the threshold by TOLERANCE_DEFAULT
3632  const double threshold = distance_within;
3633  return ST_Distance_Polygon_Polygon(poly1_coords,
3634  poly1_coords_size,
3635  poly1_ring_sizes,
3636  poly1_num_rings,
3637  poly2_coords,
3638  poly2_coords_size,
3639  poly2_ring_sizes,
3640  poly2_num_rings,
3641  ic1,
3642  isr1,
3643  ic2,
3644  isr2,
3645  osr,
3646  threshold) <= distance_within;
3647 }
3648 
3650 bool ST_DWithin_Polygon_MultiPolygon(int8_t* poly_coords,
3651  int64_t poly_coords_size,
3652  int32_t* poly_ring_sizes,
3653  int64_t poly_num_rings,
3654  double* poly_bounds,
3655  int64_t poly_bounds_size,
3656  int8_t* mpoly_coords,
3657  int64_t mpoly_coords_size,
3658  int32_t* mpoly_ring_sizes,
3659  int64_t mpoly_num_rings,
3660  int32_t* mpoly_poly_sizes,
3661  int64_t mpoly_num_polys,
3662  double* mpoly_bounds,
3663  int64_t mpoly_bounds_size,
3664  int32_t ic1,
3665  int32_t isr1,
3666  int32_t ic2,
3667  int32_t isr2,
3668  int32_t osr,
3669  double distance_within) {
3670  if (poly_bounds && mpoly_bounds) {
3671  // Bounding boxes need to be transformed to output SR before proximity check
3672  if (!box_dwithin_box(poly_bounds,
3673  poly_bounds_size,
3674  isr1,
3675  mpoly_bounds,
3676  mpoly_bounds_size,
3677  isr2,
3678  osr,
3679  distance_within)) {
3680  return false;
3681  }
3682  }
3683 
3684  // May need to adjust the threshold by TOLERANCE_DEFAULT
3685  const double threshold = distance_within;
3686  return ST_Distance_Polygon_MultiPolygon(poly_coords,
3687  poly_coords_size,
3688  poly_ring_sizes,
3689  poly_num_rings,
3690  mpoly_coords,
3691  mpoly_coords_size,
3692  mpoly_ring_sizes,
3693  mpoly_num_rings,
3694  mpoly_poly_sizes,
3695  mpoly_num_polys,
3696  ic1,
3697  isr1,
3698  ic2,
3699  isr2,
3700  osr,
3701  threshold) <= distance_within;
3702 }
3703 
3705 bool ST_DWithin_MultiPolygon_MultiPolygon(int8_t* mpoly1_coords,
3706  int64_t mpoly1_coords_size,
3707  int32_t* mpoly1_ring_sizes,
3708  int64_t mpoly1_num_rings,
3709  int32_t* mpoly1_poly_sizes,
3710  int64_t mpoly1_num_polys,
3711  double* mpoly1_bounds,
3712  int64_t mpoly1_bounds_size,
3713  int8_t* mpoly2_coords,
3714  int64_t mpoly2_coords_size,
3715  int32_t* mpoly2_ring_sizes,
3716  int64_t mpoly2_num_rings,
3717  int32_t* mpoly2_poly_sizes,
3718  int64_t mpoly2_num_polys,
3719  double* mpoly2_bounds,
3720  int64_t mpoly2_bounds_size,
3721  int32_t ic1,
3722  int32_t isr1,
3723  int32_t ic2,
3724  int32_t isr2,
3725  int32_t osr,
3726  double distance_within) {
3727  if (mpoly1_bounds && mpoly2_bounds) {
3728  // Bounding boxes need to be transformed to output SR before proximity check
3729  if (!box_dwithin_box(mpoly1_bounds,
3730  mpoly1_bounds_size,
3731  isr1,
3732  mpoly2_bounds,
3733  mpoly2_bounds_size,
3734  isr2,
3735  osr,
3736  distance_within)) {
3737  return false;
3738  }
3739  }
3740 
3741  // May need to adjust the threshold by TOLERANCE_DEFAULT
3742  const double threshold = distance_within;
3743  return ST_Distance_MultiPolygon_MultiPolygon(mpoly1_coords,
3744  mpoly1_coords_size,
3745  mpoly1_ring_sizes,
3746  mpoly1_num_rings,
3747  mpoly1_poly_sizes,
3748  mpoly1_num_polys,
3749  mpoly2_coords,
3750  mpoly2_coords_size,
3751  mpoly2_ring_sizes,
3752  mpoly2_num_rings,
3753  mpoly2_poly_sizes,
3754  mpoly2_num_polys,
3755  ic1,
3756  isr1,
3757  ic2,
3758  isr2,
3759  osr,
3760  threshold) <= distance_within;
3761 }
3762 
3763 //
3764 // ST_MaxDistance
3765 //
3766 
3767 // Max cartesian distance between a point and a line segment
3768 DEVICE
3769 double max_distance_point_line(double px,
3770  double py,
3771  double l1x,
3772  double l1y,
3773  double l2x,
3774  double l2y) {
3775  // TODO: switch to squared distances
3776  double length1 = distance_point_point(px, py, l1x, l1y);
3777  double length2 = distance_point_point(px, py, l2x, l2y);
3778  if (length1 > length2) {
3779  return length1;
3780  }
3781  return length2;
3782 }
3783 
3785  int64_t psize,
3786  int8_t* l,
3787  int64_t lsize,
3788  int32_t ic1,
3789  int32_t isr1,
3790  int32_t ic2,
3791  int32_t isr2,
3792  int32_t osr,
3793  bool check_closed) {
3794  // TODO: switch to squared distances
3795  Point2D pt = get_point(p, 0, ic1, isr1, osr);
3796 
3797  auto l_num_coords = lsize / compression_unit_size(ic2);
3798 
3799  Point2D l1 = get_point(l, 0, ic2, isr2, osr);
3800  Point2D l2 = get_point(l, 2, ic2, isr2, osr);
3801 
3802  double max_dist = max_distance_point_line(pt.x, pt.y, l1.x, l1.y, l2.x, l2.y);
3803  for (int32_t i = 4; i < l_num_coords; i += 2) {
3804  l1 = l2; // advance one point
3805  l2 = get_point(l, i, ic2, isr2, osr);
3806  double ldist = max_distance_point_line(pt.x, pt.y, l1.x, l1.y, l2.x, l2.y);
3807  if (max_dist < ldist) {
3808  max_dist = ldist;
3809  }
3810  }
3811  if (l_num_coords > 4 && check_closed) {
3812  // Also check distance to the closing edge between the first and the last points
3813  l1 = get_point(l, 0, ic2, isr2, osr);
3814  double ldist = max_distance_point_line(pt.x, pt.y, l1.x, l1.y, l2.x, l2.y);
3815  if (max_dist < ldist) {
3816  max_dist = ldist;
3817  }
3818  }
3819  return max_dist;
3820 }
3821 
3824  int64_t psize,
3825  int8_t* l,
3826  int64_t lsize,
3827  int32_t ic1,
3828  int32_t isr1,
3829  int32_t ic2,
3830  int32_t isr2,
3831  int32_t osr) {
3833  p, psize, l, lsize, ic1, isr1, ic2, isr2, osr, false);
3834 }
3835 
3838  int64_t lsize,
3839  int8_t* p,
3840  int64_t psize,
3841  int32_t ic1,
3842  int32_t isr1,
3843  int32_t ic2,
3844  int32_t isr2,
3845  int32_t osr) {
3847  p, psize, l, lsize, ic2, isr2, ic1, isr1, osr, false);
3848 }
3849 
3850 // TODO: add ST_MaxDistance_LineString_LineString (with short-circuit threshold)
3851 
3852 //
3853 // ST_Contains
3854 //
3855 
3857 bool ST_Contains_Point_Point(int8_t* p1,
3858  int64_t p1size,
3859  int8_t* p2,
3860  int64_t p2size,
3861  int32_t ic1,
3862  int32_t isr1,
3863  int32_t ic2,
3864  int32_t isr2,
3865  int32_t osr) {
3866  Point2D const pt1 = get_point(p1, 0, ic1, isr1, osr);
3867  Point2D const pt2 = get_point(p2, 0, ic2, isr2, osr);
3868  double tolerance = tol(ic1, ic2);
3869  return tol_eq(pt1.x, pt2.x, tolerance) && tol_eq(pt1.y, pt2.y, tolerance);
3870 }
3871 
3874  int64_t psize,
3875  int8_t* l,
3876  int64_t lsize,
3877  double* lbounds,
3878  int64_t lbounds_size,
3879  int32_t ic1,
3880  int32_t isr1,
3881  int32_t ic2,
3882  int32_t isr2,
3883  int32_t osr) {
3884  Point2D const pt = get_point(p, 0, ic1, isr1, osr);
3885 
3886  if (lbounds) {
3887  if (tol_eq(pt.x, lbounds[0]) && tol_eq(pt.y, lbounds[1]) &&
3888  tol_eq(pt.x, lbounds[2]) && tol_eq(pt.y, lbounds[3])) {
3889  return true;
3890  }
3891  }
3892 
3893  auto l_num_coords = lsize / compression_unit_size(ic2);
3894  for (int i = 0; i < l_num_coords; i += 2) {
3895  Point2D pl = get_point(l, i, ic2, isr2, osr);
3896  if (tol_eq(pt.x, pl.x) && tol_eq(pt.y, pl.y)) {
3897  continue;
3898  }
3899  return false;
3900  }
3901  return true;
3902 }
3903 
3906  int64_t psize,
3907  int8_t* poly_coords,
3908  int64_t poly_coords_size,
3909  int32_t* poly_ring_sizes,
3910  int64_t poly_num_rings,
3911  double* poly_bounds,
3912  int64_t poly_bounds_size,
3913  int32_t ic1,
3914  int32_t isr1,
3915  int32_t ic2,
3916  int32_t isr2,
3917  int32_t osr) {
3918  auto exterior_ring_num_coords = poly_coords_size / compression_unit_size(ic2);
3919  if (poly_num_rings > 0) {
3920  exterior_ring_num_coords = poly_ring_sizes[0] * 2;
3921  }
3922  auto exterior_ring_coords_size = exterior_ring_num_coords * compression_unit_size(ic2);
3923 
3925  psize,
3926  poly_coords,
3927  exterior_ring_coords_size,
3928  poly_bounds,
3929  poly_bounds_size,
3930  ic1,
3931  isr1,
3932  ic2,
3933  isr2,
3934  osr);
3935 }
3936 
3939  int64_t lsize,
3940  double* lbounds,
3941  int64_t lbounds_size,
3942  int8_t* p,
3943  int64_t psize,
3944  int32_t ic1,
3945  int32_t isr1,
3946  int32_t ic2,
3947  int32_t isr2,
3948  int32_t osr) {
3949  return tol_zero(
3950  ST_Distance_Point_LineString(p, psize, l, lsize, ic2, isr2, ic1, isr1, osr, 0.0));
3951 }
3952 
3955  int64_t lsize,
3956  double* lbounds,
3957  int64_t lbounds_size,
3958  int8_t* poly_coords,
3959  int64_t poly_coords_size,
3960  int32_t* poly_ring_sizes,
3961  int64_t poly_num_rings,
3962  double* poly_bounds,
3963  int64_t poly_bounds_size,
3964  int32_t ic1,
3965  int32_t isr1,
3966  int32_t ic2,
3967  int32_t isr2,
3968  int32_t osr) {
3969  // TODO
3970  return false;
3971 }
3972 
3973 template <typename T, EdgeBehavior TEdgeBehavior>
3974 DEVICE ALWAYS_INLINE bool Contains_Polygon_Point_Impl(const int8_t* poly_coords,
3975  const int64_t poly_coords_size,
3976  const int32_t* poly_ring_sizes,
3977  const int64_t poly_num_rings,
3978  const double* poly_bounds,
3979  const int64_t poly_bounds_size,
3980  const int8_t* p,
3981  const int64_t psize,
3982  const int32_t ic1,
3983  const int32_t isr1,
3984  const int32_t ic2,
3985  const int32_t isr2,
3986  const int32_t osr) {
3987  if (poly_bounds) {
3988  // TODO: codegen
3989  Point2D const pt = get_point(p, 0, ic2, isr2, osr);
3990  if (!box_contains_point(poly_bounds, poly_bounds_size, pt.x, pt.y)) {
3991  DEBUG_STMT(printf("Bounding box does not contain point, exiting.\n"));
3992  return false;
3993  }
3994  }
3995 
3996  auto get_x_coord = [=]() -> T {
3997  if constexpr (std::is_floating_point<T>::value) {
3998  return get_point(p, 0, ic2, isr2, osr).x;
3999  } else {
4000  return compressed_coord(p, 0);
4001  }
4002  return T{}; // https://stackoverflow.com/a/64561686/2700898
4003  };
4004 
4005  auto get_y_coord = [=]() -> T {
4006  if constexpr (std::is_floating_point<T>::value) {
4007  return get_point(p, 0, ic2, isr2, osr).y;
4008  } else {
4009  return compressed_coord(p, 1);
4010  }
4011  return T{}; // https://stackoverflow.com/a/64561686/2700898
4012  };
4013 
4014  const T px = get_x_coord();
4015  const T py = get_y_coord();
4016  DEBUG_STMT(printf("pt: %f, %f\n", (double)px, (double)py));
4017 
4018  const auto poly_num_coords = poly_coords_size / compression_unit_size(ic1);
4019  auto exterior_ring_num_coords =
4020  poly_num_rings > 0 ? poly_ring_sizes[0] * 2 : poly_num_coords;
4021 
4022  auto poly = poly_coords;
4023  if (point_in_polygon_winding_number<T, TEdgeBehavior>(
4024  poly, exterior_ring_num_coords, px, py, ic1, isr1, osr)) {
4025  // Inside exterior ring
4026  poly += exterior_ring_num_coords * compression_unit_size(ic1);
4027  // Check that none of the polygon's holes contain that point
4028  for (auto r = 1; r < poly_num_rings; r++) {
4029  const int64_t interior_ring_num_coords = poly_ring_sizes[r] * 2;
4030  if (point_in_polygon_winding_number<T, TEdgeBehavior>(
4031  poly, interior_ring_num_coords, px, py, ic1, isr1, osr)) {
4032  return false;
4033  }
4034  poly += interior_ring_num_coords * compression_unit_size(ic1);
4035  }
4036  return true;
4037  }
4038  return false;
4039 }
4040 
4041 EXTENSION_NOINLINE bool ST_Contains_Polygon_Point(const int8_t* poly_coords,
4042  const int64_t poly_coords_size,
4043  const int32_t* poly_ring_sizes,
4044  const int64_t poly_num_rings,
4045  const double* poly_bounds,
4046  const int64_t poly_bounds_size,
4047  const int8_t* p,
4048  const int64_t psize,
4049  const int32_t ic1,
4050  const int32_t isr1,
4051  const int32_t ic2,
4052  const int32_t isr2,
4053  const int32_t osr) {
4054  return Contains_Polygon_Point_Impl<double, EdgeBehavior::kExcludePointOnEdge>(
4055  poly_coords,
4056  poly_coords_size,
4057  poly_ring_sizes,
4058  poly_num_rings,
4059  poly_bounds,
4060  poly_bounds_size,
4061  p,
4062  psize,
4063  ic1,
4064  isr1,
4065  ic2,
4066  isr2,
4067  osr);
4068 }
4069 
4070 EXTENSION_NOINLINE bool ST_cContains_Polygon_Point(const int8_t* poly_coords,
4071  const int64_t poly_coords_size,
4072  const int32_t* poly_ring_sizes,
4073  const int64_t poly_num_rings,
4074  const double* poly_bounds,
4075  const int64_t poly_bounds_size,
4076  const int8_t* p,
4077  const int64_t psize,
4078  const int32_t ic1,
4079  const int32_t isr1,
4080  const int32_t ic2,
4081  const int32_t isr2,
4082  const int32_t osr) {
4083  return Contains_Polygon_Point_Impl<int64_t, EdgeBehavior::kExcludePointOnEdge>(
4084  poly_coords,
4085  poly_coords_size,
4086  poly_ring_sizes,
4087  poly_num_rings,
4088  poly_bounds,
4089  poly_bounds_size,
4090  p,
4091  psize,
4092  ic1,
4093  isr1,
4094  ic2,
4095  isr2,
4096  osr);
4097 }
4098 
4100 bool ST_Contains_Polygon_LineString(int8_t* poly_coords,
4101  int64_t poly_coords_size,
4102  int32_t* poly_ring_sizes,
4103  int64_t poly_num_rings,
4104  double* poly_bounds,
4105  int64_t poly_bounds_size,
4106  int8_t* l,
4107  int64_t lsize,
4108  double* lbounds,
4109  int64_t lbounds_size,
4110  int32_t ic1,
4111  int32_t isr1,
4112  int32_t ic2,
4113  int32_t isr2,
4114  int32_t osr) {
4115  if (poly_num_rings > 1) {
4116  return false; // TODO: support polygons with interior rings
4117  }
4118 
4119  // Bail out if poly bounding box doesn't contain linestring bounding box
4120  if (poly_bounds && lbounds) {
4121  if (!box_contains_box(poly_bounds, poly_bounds_size, lbounds, lbounds_size)) {
4122  return false;
4123  }
4124  }
4125 
4126  const auto poly_num_coords = poly_coords_size / compression_unit_size(ic1);
4127  const auto lnum_coords = lsize / compression_unit_size(ic2);
4128 
4130  poly_coords, poly_num_coords, l, lnum_coords, ic1, isr1, ic2, isr2, osr);
4131 }
4132 
4134 bool ST_Contains_Polygon_Polygon(int8_t* poly1_coords,
4135  int64_t poly1_coords_size,
4136  int32_t* poly1_ring_sizes,
4137  int64_t poly1_num_rings,
4138  double* poly1_bounds,
4139  int64_t poly1_bounds_size,
4140  int8_t* poly2_coords,
4141  int64_t poly2_coords_size,
4142  int32_t* poly2_ring_sizes,
4143  int64_t poly2_num_rings,
4144  double* poly2_bounds,
4145  int64_t poly2_bounds_size,
4146  int32_t ic1,
4147  int32_t isr1,
4148  int32_t ic2,
4149  int32_t isr2,
4150  int32_t osr) {
4151  // TODO: needs to be extended, cover more cases
4152  // Right now only checking if simple poly1 (no holes) contains poly2's exterior shape
4153  if (poly1_num_rings > 1) {
4154  return false; // TODO: support polygons with interior rings
4155  }
4156 
4157  if (poly1_bounds && poly2_bounds) {
4158  if (!box_contains_box(
4159  poly1_bounds, poly1_bounds_size, poly2_bounds, poly2_bounds_size)) {
4160  return false;
4161  }
4162  }
4163 
4164  int64_t poly2_exterior_ring_coords_size = poly2_coords_size;
4165  if (poly2_num_rings > 0) {
4166  poly2_exterior_ring_coords_size =
4167  2 * poly2_ring_sizes[0] * compression_unit_size(ic2);
4168  }
4169  return ST_Contains_Polygon_LineString(poly1_coords,
4170  poly1_coords_size,
4171  poly1_ring_sizes,
4172  poly1_num_rings,
4173  poly1_bounds,
4174  poly1_bounds_size,
4175  poly2_coords,
4176  poly2_exterior_ring_coords_size,
4177  poly2_bounds,
4178  poly2_bounds_size,
4179  ic1,
4180  isr1,
4181  ic2,
4182  isr2,
4183  osr);
4184 }
4185 
4186 template <typename T, EdgeBehavior TEdgeBehavior>
4188  const int8_t* mpoly_coords,
4189  const int64_t mpoly_coords_size,
4190  const int32_t* mpoly_ring_sizes,
4191  const int64_t mpoly_num_rings,
4192  const int32_t* mpoly_poly_sizes,
4193  const int64_t mpoly_num_polys,
4194  const double* mpoly_bounds,
4195  const int64_t mpoly_bounds_size,
4196  const int8_t* p,
4197  const int64_t psize,
4198  const int32_t ic1,
4199  const int32_t isr1,
4200  const int32_t ic2,
4201  const int32_t isr2,
4202  const int32_t osr) {
4203  if (mpoly_num_polys <= 0) {
4204  return false;
4205  }
4206 
4207  // TODO: mpoly_bounds could contain individual bounding boxes too:
4208  // first two points - box for the entire multipolygon, then a pair for each polygon
4209  if (mpoly_bounds) {
4210  Point2D const pt = get_point(p, 0, ic2, isr2, osr);
4211  if (!box_contains_point(mpoly_bounds, mpoly_bounds_size, pt.x, pt.y)) {
4212  return false;
4213  }
4214  }
4215 
4216  // Set specific poly pointers as we move through the coords/ringsizes/polyrings
4217  // arrays.
4218  auto next_poly_coords = mpoly_coords;
4219  auto next_poly_ring_sizes = mpoly_ring_sizes;
4220 
4221  for (auto poly = 0; poly < mpoly_num_polys; poly++) {
4222  const auto poly_coords = next_poly_coords;
4223  const auto poly_ring_sizes = next_poly_ring_sizes;
4224  const auto poly_num_rings = mpoly_poly_sizes[poly];
4225  // Count number of coords in all of poly's rings, advance ring size pointer.
4226  int32_t poly_num_coords = 0;
4227  for (auto ring = 0; ring < poly_num_rings; ring++) {
4228  poly_num_coords += 2 * *next_poly_ring_sizes++;
4229  }
4230  const auto poly_coords_size = poly_num_coords * compression_unit_size(ic1);
4231  next_poly_coords += poly_coords_size;
4232  // TODO: pass individual bounding boxes for each polygon
4233  if (Contains_Polygon_Point_Impl<T, TEdgeBehavior>(poly_coords,
4234  poly_coords_size,
4235  poly_ring_sizes,
4236  poly_num_rings,
4237  nullptr,
4238  0,
4239  p,
4240  psize,
4241  ic1,
4242  isr1,
4243  ic2,
4244  isr2,
4245  osr)) {
4246  return true;
4247  }
4248  }
4249 
4250  return false;
4251 }
4252 
4254 bool ST_Contains_MultiPolygon_Point(int8_t* mpoly_coords,
4255  int64_t mpoly_coords_size,
4256  int32_t* mpoly_ring_sizes,
4257  int64_t mpoly_num_rings,
4258  int32_t* mpoly_poly_sizes,
4259  int64_t mpoly_num_polys,
4260  double* mpoly_bounds,
4261  int64_t mpoly_bounds_size,
4262  int8_t* p,
4263  int64_t psize,
4264  int32_t ic1,
4265  int32_t isr1,
4266  int32_t ic2,
4267  int32_t isr2,
4268  int32_t osr) {
4269  return Contains_MultiPolygon_Point_Impl<double, EdgeBehavior::kExcludePointOnEdge>(
4270  mpoly_coords,
4271  mpoly_coords_size,
4272  mpoly_ring_sizes,
4273  mpoly_num_rings,
4274  mpoly_poly_sizes,
4275  mpoly_num_polys,
4276  mpoly_bounds,
4277  mpoly_bounds_size,
4278  p,
4279  psize,
4280  ic1,
4281  isr1,
4282  ic2,
4283  isr2,
4284  osr);
4285 }
4286 
4288  int64_t mpoly_coords_size,
4289  int32_t* mpoly_ring_sizes,
4290  int64_t mpoly_num_rings,
4291  int32_t* mpoly_poly_sizes,
4292  int64_t mpoly_num_polys,
4293  double* mpoly_bounds,
4294  int64_t mpoly_bounds_size,
4295  int8_t* p,
4296  int64_t psize,
4297  int32_t ic1,
4298  int32_t isr1,
4299  int32_t ic2,
4300  int32_t isr2,
4301  int32_t osr) {
4302  return Contains_MultiPolygon_Point_Impl<int64_t, EdgeBehavior::kExcludePointOnEdge>(
4303  mpoly_coords,
4304  mpoly_coords_size,
4305  mpoly_ring_sizes,
4306  mpoly_num_rings,
4307  mpoly_poly_sizes,
4308  mpoly_num_polys,
4309  mpoly_bounds,
4310  mpoly_bounds_size,
4311  p,
4312  psize,
4313  ic1,
4314  isr1,
4315  ic2,
4316  isr2,
4317  osr);
4318 }
4319 
4321 bool ST_Contains_MultiPolygon_LineString(int8_t* mpoly_coords,
4322  int64_t mpoly_coords_size,
4323  int32_t* mpoly_ring_sizes,
4324  int64_t mpoly_num_rings,
4325  int32_t* mpoly_poly_sizes,
4326  int64_t mpoly_num_polys,
4327  double* mpoly_bounds,
4328  int64_t mpoly_bounds_size,
4329  int8_t* l,
4330  int64_t lsize,
4331  double* lbounds,
4332  int64_t lbounds_size,
4333  int32_t ic1,
4334  int32_t isr1,
4335  int32_t ic2,
4336  int32_t isr2,
4337  int32_t osr) {
4338  if (mpoly_num_polys <= 0) {
4339  return false;
4340  }
4341 
4342  if (mpoly_bounds && lbounds) {
4343  if (!box_contains_box(mpoly_bounds, mpoly_bounds_size, lbounds, lbounds_size)) {
4344  return false;
4345  }
4346  }
4347 
4348  // Set specific poly pointers as we move through the coords/ringsizes/polyrings arrays.
4349  auto next_poly_coords = mpoly_coords;
4350  auto next_poly_ring_sizes = mpoly_ring_sizes;
4351 
4352  for (auto poly = 0; poly < mpoly_num_polys; poly++) {
4353  auto poly_coords = next_poly_coords;
4354  auto poly_ring_sizes = next_poly_ring_sizes;
4355  auto poly_num_rings = mpoly_poly_sizes[poly];
4356  // Count number of coords in all of poly's rings, advance ring size pointer.
4357  int32_t poly_num_coords = 0;
4358  for (auto ring = 0; ring < poly_num_rings; ring++) {
4359  poly_num_coords += 2 * *next_poly_ring_sizes++;
4360  }
4361  auto poly_coords_size = poly_num_coords * compression_unit_size(ic1);
4362  next_poly_coords += poly_coords_size;
4363 
4364  if (ST_Contains_Polygon_LineString(poly_coords,
4365  poly_coords_size,
4366  poly_ring_sizes,
4367  poly_num_rings,
4368  nullptr,
4369  0,
4370  l,
4371  lsize,
4372  nullptr,
4373  0,
4374  ic1,
4375  isr1,
4376  ic2,
4377  isr2,
4378  osr)) {
4379  return true;
4380  }
4381  }
4382 
4383  return false;
4384 }
4385 
4386 //
4387 // ST_Intersects
4388 //
4389 
4392  int64_t p1size,
4393  int8_t* p2,
4394  int64_t p2size,
4395  int32_t ic1,
4396  int32_t isr1,
4397  int32_t ic2,
4398  int32_t isr2,
4399  int32_t osr) {
4400  return tol_zero(
4401  ST_Distance_Point_Point(p1, p1size, p2, p2size, ic1, isr1, ic2, isr2, osr));
4402 }
4403 
4406  int64_t psize,
4407  int8_t* l,
4408  int64_t lsize,
4409  double* lbounds,
4410  int64_t lbounds_size,
4411  int32_t ic1,
4412  int32_t isr1,
4413  int32_t ic2,
4414  int32_t isr2,
4415  int32_t osr) {
4416  if (lbounds) {
4417  Point2D const pt = get_point(p, 0, ic1, isr1, osr);
4418  if (!box_contains_point(lbounds, lbounds_size, pt.x, pt.y)) {
4419  return false;
4420  }
4421  }
4422  return tol_zero(
4423  ST_Distance_Point_LineString(p, psize, l, lsize, ic1, isr1, ic2, isr2, osr, 0.0));
4424 }
4425 
4428  int64_t psize,
4429  int8_t* poly,
4430  int64_t polysize,
4431  int32_t* poly_ring_sizes,
4432  int64_t poly_num_rings,
4433  double* poly_bounds,
4434  int64_t poly_bounds_size,
4435  int32_t ic1,
4436  int32_t isr1,
4437  int32_t ic2,
4438  int32_t isr2,
4439  int32_t osr) {
4440  return Contains_Polygon_Point_Impl<double, EdgeBehavior::kIncludePointOnEdge>(
4441  poly,
4442  polysize,
4443  poly_ring_sizes,
4444  poly_num_rings,
4445  poly_bounds,
4446  poly_bounds_size,
4447  p,
4448  psize,
4449  ic2,
4450  isr2,
4451  ic1,
4452  isr1,
4453  osr);
4454 }
4455 
4458  int64_t psize,
4459  int8_t* mpoly_coords,
4460  int64_t mpoly_coords_size,
4461  int32_t* mpoly_ring_sizes,
4462  int64_t mpoly_num_rings,
4463  int32_t* mpoly_poly_sizes,
4464  int64_t mpoly_num_polys,
4465  double* mpoly_bounds,
4466  int64_t mpoly_bounds_size,
4467  int32_t ic1,
4468  int32_t isr1,
4469  int32_t ic2,
4470  int32_t isr2,
4471  int32_t osr) {
4472  return Contains_MultiPolygon_Point_Impl<double, EdgeBehavior::kIncludePointOnEdge>(
4473  mpoly_coords,
4474  mpoly_coords_size,
4475  mpoly_ring_sizes,
4476  mpoly_num_rings,
4477  mpoly_poly_sizes,
4478  mpoly_num_polys,
4479  mpoly_bounds,
4480  mpoly_bounds_size,
4481  p,
4482  psize,
4483  ic1,
4484  isr1,
4485  ic2,
4486  isr2,
4487  osr);
4488 }
4489 
4492  int64_t lsize,
4493  double* lbounds,
4494  int64_t lbounds_size,
4495  int8_t* p,
4496  int64_t psize,
4497  int32_t ic1,
4498  int32_t isr1,
4499  int32_t ic2,
4500  int32_t isr2,
4501  int32_t osr) {
4503  p, psize, l, lsize, lbounds, lbounds_size, ic2, isr2, ic1, isr1, osr);
4504 }
4505 
4508  int64_t l1size,
4509  double* l1bounds,
4510  int64_t l1bounds_size,
4511  int8_t* l2,
4512  int64_t l2size,
4513  double* l2bounds,
4514  int64_t l2bounds_size,
4515  int32_t ic1,
4516  int32_t isr1,
4517  int32_t ic2,
4518  int32_t isr2,
4519  int32_t osr) {
4520  if (l1bounds && l2bounds) {
4521  if (!box_overlaps_box(l1bounds, l1bounds_size, l2bounds, l2bounds_size)) {
4522  return false;
4523  }
4524  }
4525 
4527  l1, l1size, l2, l2size, ic1, isr1, ic2, isr2, osr, 0.0));
4528 }
4529 
4532  int64_t lsize,
4533  double* lbounds,
4534  int64_t lbounds_size,
4535  int8_t* poly,
4536  int64_t polysize,
4537  int32_t* poly_ring_sizes,
4538  int64_t poly_num_rings,
4539  double* poly_bounds,
4540  int64_t poly_bounds_size,
4541  int32_t ic1,
4542  int32_t isr1,
4543  int32_t ic2,
4544  int32_t isr2,
4545  int32_t osr) {
4546  if (lbounds && poly_bounds) {
4547  if (!box_overlaps_box(lbounds, lbounds_size, poly_bounds, poly_bounds_size)) {
4548  return false;
4549  }
4550  }
4551 
4552  // Check for spatial intersection.
4553  // One way to do that would be to start with linestring's first point, if it's inside
4554  // the polygon - it means intersection. Otherwise follow the linestring, segment by
4555  // segment, checking for intersections with polygon rings, bail as soon as we cross into
4556  // the polygon.
4557 
4558  // Or, alternatively, just measure the distance:
4560  lsize,
4561  poly,
4562  polysize,
4563  poly_ring_sizes,
4564  poly_num_rings,
4565  ic1,
4566  isr1,
4567  ic2,
4568  isr2,
4569  osr,
4570  0.0));
4571 }
4572 
4575  int64_t lsize,
4576  double* lbounds,
4577  int64_t lbounds_size,
4578  int8_t* mpoly_coords,
4579  int64_t mpoly_coords_size,
4580  int32_t* mpoly_ring_sizes,
4581  int64_t mpoly_num_rings,
4582  int32_t* mpoly_poly_sizes,
4583  int64_t mpoly_num_polys,
4584  double* mpoly_bounds,
4585  int64_t mpoly_bounds_size,
4586  int32_t ic1,
4587  int32_t isr1,
4588  int32_t ic2,
4589  int32_t isr2,
4590  int32_t osr) {
4591  if (lbounds && mpoly_bounds) {
4592  if (!box_overlaps_box(lbounds, lbounds_size, mpoly_bounds, mpoly_bounds_size)) {
4593  return false;
4594  }
4595  }
4596 
4597  // Check for spatial intersection.
4598  // One way to do that would be to start with linestring's first point, if it's inside
4599  // any of the polygons - it means intersection. Otherwise follow the linestring, segment
4600  // by segment, checking for intersections with polygon shapes/holes, bail as soon as we
4601  // cross into a polygon.
4602 
4603  // Or, alternatively, just measure the distance:
4605  lsize,
4606  mpoly_coords,
4607  mpoly_coords_size,
4608  mpoly_ring_sizes,
4609  mpoly_num_rings,
4610  mpoly_poly_sizes,
4611  mpoly_num_polys,
4612  ic1,
4613  isr1,
4614  ic2,
4615  isr2,
4616  osr,
4617  0.0));
4618 }
4619 
4622  int64_t polysize,
4623  int32_t* poly_ring_sizes,
4624  int64_t poly_num_rings,
4625  double* poly_bounds,
4626  int64_t poly_bounds_size,
4627  int8_t* p,
4628  int64_t psize,
4629  int32_t ic1,
4630  int32_t isr1,
4631  int32_t ic2,
4632  int32_t isr2,
4633  int32_t osr) {
4634  return Contains_Polygon_Point_Impl<double, EdgeBehavior::kIncludePointOnEdge>(
4635  poly,
4636  polysize,
4637  poly_ring_sizes,
4638  poly_num_rings,
4639  poly_bounds,
4640  poly_bounds_size,
4641  p,
4642  psize,
4643  ic1,
4644  isr1,
4645  ic2,
4646  isr2,
4647  osr);
4648 }
4649 
4652  int64_t polysize,
4653  int32_t* poly_ring_sizes,
4654  int64_t poly_num_rings,
4655  double* poly_bounds,
4656  int64_t poly_bounds_size,
4657  int8_t* p,
4658  int64_t psize,
4659  int32_t ic1,
4660  int32_t isr1,
4661  int32_t ic2,
4662  int32_t isr2,
4663  int32_t osr) {
4664  return Contains_Polygon_Point_Impl<int64_t, EdgeBehavior::kIncludePointOnEdge>(
4665  poly,
4666  polysize,
4667  poly_ring_sizes,
4668  poly_num_rings,
4669  poly_bounds,
4670  poly_bounds_size,
4671  p,
4672  psize,
4673  ic1,
4674  isr1,
4675  ic2,
4676  isr2,
4677  osr);
4678 }
4679 
4682  int64_t polysize,
4683  int32_t* poly_ring_sizes,
4684  int64_t poly_num_rings,
4685  double* poly_bounds,
4686  int64_t poly_bounds_size,
4687  int8_t* l,
4688  int64_t lsize,
4689  double* lbounds,
4690  int64_t lbounds_size,
4691  int32_t ic1,
4692  int32_t isr1,
4693  int32_t ic2,
4694  int32_t isr2,
4695  int32_t osr) {
4697  lsize,
4698  lbounds,
4699  lbounds_size,
4700  poly,
4701  polysize,
4702  poly_ring_sizes,
4703  poly_num_rings,
4704  poly_bounds,
4705  poly_bounds_size,
4706  ic2,
4707  isr2,
4708  ic1,
4709  isr1,
4710  osr);
4711 }
4712 
4714 bool ST_Intersects_Polygon_Polygon(int8_t* poly1_coords,
4715  int64_t poly1_coords_size,
4716  int32_t* poly1_ring_sizes,
4717  int64_t poly1_num_rings,
4718  double* poly1_bounds,
4719  int64_t poly1_bounds_size,
4720  int8_t* poly2_coords,
4721  int64_t poly2_coords_size,
4722  int32_t* poly2_ring_sizes,
4723  int64_t poly2_num_rings,
4724  double* poly2_bounds,
4725  int64_t poly2_bounds_size,
4726  int32_t ic1,
4727  int32_t isr1,
4728  int32_t ic2,
4729  int32_t isr2,
4730  int32_t osr) {
4731  if (poly1_bounds && poly2_bounds) {
4732  if (!box_overlaps_box(
4733  poly1_bounds, poly1_bounds_size, poly2_bounds, poly2_bounds_size)) {
4734  return false;
4735  }
4736  }
4737 
4738  return tol_zero(ST_Distance_Polygon_Polygon(poly1_coords,
4739  poly1_coords_size,
4740  poly1_ring_sizes,
4741  poly1_num_rings,
4742  poly2_coords,
4743  poly2_coords_size,
4744  poly2_ring_sizes,
4745  poly2_num_rings,
4746  ic1,
4747  isr1,
4748  ic2,
4749  isr2,
4750  osr,
4751  0.0));
4752 }
4753 
4755 bool ST_Intersects_Polygon_MultiPolygon(int8_t* poly_coords,
4756  int64_t poly_coords_size,
4757  int32_t* poly_ring_sizes,
4758  int64_t poly_num_rings,
4759  double* poly_bounds,
4760  int64_t poly_bounds_size,
4761  int8_t* mpoly_coords,
4762  int64_t mpoly_coords_size,
4763  int32_t* mpoly_ring_sizes,
4764  int64_t mpoly_num_rings,
4765  int32_t* mpoly_poly_sizes,
4766  int64_t mpoly_num_polys,
4767  double* mpoly_bounds,
4768  int64_t mpoly_bounds_size,
4769  int32_t ic1,
4770  int32_t isr1,
4771  int32_t ic2,
4772  int32_t isr2,
4773  int32_t osr) {
4774  if (poly_bounds && mpoly_bounds) {
4775  if (!box_overlaps_box(
4776  poly_bounds, poly_bounds_size, mpoly_bounds, mpoly_bounds_size)) {
4777  return false;
4778  }
4779  }
4780 
4781  return tol_zero(ST_Distance_Polygon_MultiPolygon(poly_coords,
4782  poly_coords_size,
4783  poly_ring_sizes,
4784  poly_num_rings,
4785  mpoly_coords,
4786  mpoly_coords_size,
4787  mpoly_ring_sizes,
4788  mpoly_num_rings,
4789  mpoly_poly_sizes,
4790  mpoly_num_polys,
4791  ic1,
4792  isr1,
4793  ic2,
4794  isr2,
4795  osr,
4796  0.0));
4797 }
4798 
4800 bool ST_Intersects_MultiPolygon_Point(int8_t* mpoly_coords,
4801  int64_t mpoly_coords_size,
4802  int32_t* mpoly_ring_sizes,
4803  int64_t mpoly_num_rings,
4804  int32_t* mpoly_poly_sizes,
4805  int64_t mpoly_num_polys,
4806  double* mpoly_bounds,
4807  int64_t mpoly_bounds_size,
4808  int8_t* p,
4809  int64_t psize,
4810  int32_t ic1,
4811  int32_t isr1,
4812  int32_t ic2,
4813  int32_t isr2,
4814  int32_t osr) {
4815  return Contains_MultiPolygon_Point_Impl<double, EdgeBehavior::kIncludePointOnEdge>(
4816  mpoly_coords,
4817  mpoly_coords_size,
4818  mpoly_ring_sizes,
4819  mpoly_num_rings,
4820  mpoly_poly_sizes,
4821  mpoly_num_polys,
4822  mpoly_bounds,
4823  mpoly_bounds_size,
4824  p,
4825  psize,
4826  ic1,
4827  isr1,
4828  ic2,
4829  isr2,
4830  osr);
4831 }
4832 
4834 bool ST_cIntersects_MultiPolygon_Point(int8_t* mpoly_coords,
4835  int64_t mpoly_coords_size,
4836  int32_t* mpoly_ring_sizes,
4837  int64_t mpoly_num_rings,
4838  int32_t* mpoly_poly_sizes,
4839  int64_t mpoly_num_polys,
4840  double* mpoly_bounds,
4841  int64_t mpoly_bounds_size,
4842  int8_t* p,
4843  int64_t psize,
4844  int32_t ic1,
4845  int32_t isr1,
4846  int32_t ic2,
4847  int32_t isr2,
4848  int32_t osr) {
4849  return Contains_MultiPolygon_Point_Impl<int64_t, EdgeBehavior::kIncludePointOnEdge>(
4850  mpoly_coords,
4851  mpoly_coords_size,
4852  mpoly_ring_sizes,
4853  mpoly_num_rings,
4854  mpoly_poly_sizes,
4855  mpoly_num_polys,
4856  mpoly_bounds,
4857  mpoly_bounds_size,
4858  p,
4859  psize,
4860  ic1,
4861  isr1,
4862  ic2,
4863  isr2,
4864  osr);
4865 }
4866 
4868 bool ST_Intersects_MultiPolygon_LineString(int8_t* mpoly_coords,
4869  int64_t mpoly_coords_size,
4870  int32_t* mpoly_ring_sizes,
4871  int64_t mpoly_num_rings,
4872  int32_t* mpoly_poly_sizes,
4873  int64_t mpoly_num_polys,
4874  double* mpoly_bounds,
4875  int64_t mpoly_bounds_size,
4876  int8_t* l,
4877  int64_t lsize,
4878  double* lbounds,
4879  int64_t lbounds_size,
4880  int32_t ic1,
4881  int32_t isr1,
4882  int32_t ic2,
4883  int32_t isr2,
4884  int32_t osr) {
4886  lsize,
4887  lbounds,
4888  lbounds_size,
4889  mpoly_coords,
4890  mpoly_coords_size,
4891  mpoly_ring_sizes,
4892  mpoly_num_rings,
4893  mpoly_poly_sizes,
4894  mpoly_num_polys,
4895  mpoly_bounds,
4896  mpoly_bounds_size,
4897  ic2,
4898  isr2,
4899  ic1,
4900  isr1,
4901  osr);
4902 }
4903 
4905 bool ST_Intersects_MultiPolygon_Polygon(int8_t* mpoly_coords,
4906  int64_t mpoly_coords_size,
4907  int32_t* mpoly_ring_sizes,
4908  int64_t mpoly_num_rings,
4909  int32_t* mpoly_poly_sizes,
4910  int64_t mpoly_num_polys,
4911  double* mpoly_bounds,
4912  int64_t mpoly_bounds_size,
4913  int8_t* poly_coords,
4914  int64_t poly_coords_size,
4915  int32_t* poly_ring_sizes,
4916  int64_t poly_num_rings,
4917  double* poly_bounds,
4918  int64_t poly_bounds_size,
4919  int32_t ic1,
4920  int32_t isr1,
4921  int32_t ic2,
4922  int32_t isr2,
4923  int32_t osr) {
4924  return ST_Intersects_Polygon_MultiPolygon(poly_coords,
4925  poly_coords_size,
4926  poly_ring_sizes,
4927  poly_num_rings,
4928  poly_bounds,
4929  poly_bounds_size,
4930  mpoly_coords,
4931  mpoly_coords_size,
4932  mpoly_ring_sizes,
4933  mpoly_num_rings,
4934  mpoly_poly_sizes,
4935  mpoly_num_polys,
4936  mpoly_bounds,
4937  mpoly_bounds_size,
4938  ic2,
4939  isr2,
4940  ic1,
4941  isr1,
4942  osr);
4943 }
4944 
4946 bool ST_Intersects_MultiPolygon_MultiPolygon(int8_t* mpoly1_coords,
4947  int64_t mpoly1_coords_size,
4948  int32_t* mpoly1_ring_sizes,
4949  int64_t mpoly1_num_rings,
4950  int32_t* mpoly1_poly_sizes,
4951  int64_t mpoly1_num_polys,
4952  double* mpoly1_bounds,
4953  int64_t mpoly1_bounds_size,
4954  int8_t* mpoly2_coords,
4955  int64_t mpoly2_coords_size,
4956  int32_t* mpoly2_ring_sizes,
4957  int64_t mpoly2_num_rings,
4958  int32_t* mpoly2_poly_sizes,
4959  int64_t mpoly2_num_polys,
4960  double* mpoly2_bounds,
4961  int64_t mpoly2_bounds_size,
4962  int32_t ic1,
4963  int32_t isr1,
4964  int32_t ic2,
4965  int32_t isr2,
4966  int32_t osr) {
4967  if (mpoly1_bounds && mpoly2_bounds) {
4968  if (!box_overlaps_box(
4969  mpoly1_bounds, mpoly1_bounds_size, mpoly2_bounds, mpoly2_bounds_size)) {
4970  return false;
4971  }
4972  }
4973 
4974  return tol_zero(ST_Distance_MultiPolygon_MultiPolygon(mpoly1_coords,
4975  mpoly1_coords_size,
4976  mpoly1_ring_sizes,
4977  mpoly1_num_rings,
4978  mpoly1_poly_sizes,
4979  mpoly1_num_polys,
4980  mpoly2_coords,
4981  mpoly2_coords_size,
4982  mpoly2_ring_sizes,
4983  mpoly2_num_rings,
4984  mpoly2_poly_sizes,
4985  mpoly2_num_polys,
4986  ic1,
4987  isr1,
4988  ic2,
4989  isr2,
4990  osr,
4991  0.0));
4992 }
4993 
4995 int64_t HeavyDB_Geo_PolyBoundsPtr(double* bounds, int64_t size) {
4996  return reinterpret_cast<int64_t>(bounds);
4997 }
4998 
4999 // TODO Update for UTM. This assumes x and y are independent, which is not true for UTM.
5001 double convert_meters_to_pixel_width(const double meters,
5002  int8_t* p,
5003  const int64_t psize,
5004  const int32_t ic,
5005  const int32_t isr,
5006  const int32_t osr,
5007  const double min_lon,
5008  const double max_lon,
5009  const int32_t img_width,
5010  const double min_width) {
5011  const double const1 = 0.017453292519943295769236907684886;
5012  const double const2 = 6372797.560856;
5013  const auto lon = decompress_coord<X>(p, 0, ic);
5014  const auto lat = decompress_coord<Y>(p, 0, ic);
5015  double t1 = sinf(meters / (2.0 * const2));
5016  double t2 = cosf(const1 * lat);
5017  const double newlon = lon - (2.0 * asinf(t1 / t2)) / const1;
5018  t1 = transform_point<X>({lon, {}}, isr, osr).x;
5019  t2 = transform_point<X>({newlon, {}}, isr, osr).x;
5020  const double min_domain_x = transform_point<X>({min_lon, {}}, isr, osr).x;
5021  const double max_domain_x = transform_point<X>({max_lon, {}}, isr, osr).x;
5022  const double domain_diff = max_domain_x - min_domain_x;
5023  t1 = ((t1 - min_domain_x) / domain_diff) * static_cast<double>(img_width);
5024  t2 = ((t2 - min_domain_x) / domain_diff) * static_cast<double>(img_width);
5025 
5026  // TODO(croot): need to account for edge cases, such as getting close to the poles.
5027  const double sz = fabs(t1 - t2);
5028  return (sz < min_width ? min_width : sz);
5029 }
5030 
5031 // TODO Update for UTM. This assumes x and y are independent, which is not true for UTM.
5033 double convert_meters_to_pixel_height(const double meters,
5034  int8_t* p,
5035  const int64_t psize,
5036  const int32_t ic,
5037  const int32_t isr,
5038  const int32_t osr,
5039  const double min_lat,
5040  const double max_lat,
5041  const int32_t img_height,
5042  const double min_height) {
5043  const double const1 = 0.017453292519943295769236907684886;
5044  const double const2 = 6372797.560856;
5045  const auto lat = decompress_coord<Y>(p, 0, ic);
5046  const double latdiff = meters / (const1 * const2);
5047  const double newlat =
5048  (lat < 0) ? lat + latdiff : lat - latdiff; // assumes a lat range of [-90, 90]
5049  double t1 = transform_point<Y>({{}, lat}, isr, osr).y;
5050  double t2 = transform_point<Y>({{}, newlat}, isr, osr).y;
5051  const double min_domain_y = transform_point<Y>({{}, min_lat}, isr, osr).y;
5052  const double max_domain_y = transform_point<Y>({{}, max_lat}, isr, osr).y;
5053  const double domain_diff = max_domain_y - min_domain_y;
5054  t1 = ((t1 - min_domain_y) / domain_diff) * static_cast<double>(img_height);
5055  t2 = ((t2 - min_domain_y) / domain_diff) * static_cast<double>(img_height);
5056 
5057  // TODO(croot): need to account for edge cases, such as getting close to the poles.
5058  const double sz = fabs(t1 - t2);
5059  return (sz < min_height ? min_height : sz);
5060 }
5061 
5063  const int64_t psize,
5064  const int32_t ic,
5065  const double min_lon,
5066  const double max_lon,
5067  const double min_lat,
5068  const double max_lat) {
5069  const auto lon = decompress_coord<X>(p, 0, ic);
5070  const auto lat = decompress_coord<Y>(p, 0, ic);
5071  return !(lon < min_lon || lon > max_lon || lat < min_lat || lat > max_lat);
5072 }
5073 
5075  const int64_t psize,
5076  const int32_t ic,
5077  const double meters,
5078  const double min_lon,
5079  const double max_lon,
5080  const double min_lat,
5081  const double max_lat) {
5082  const double const1 = 0.017453292519943295769236907684886;
5083  const double const2 = 6372797.560856;
5084  const auto lon = decompress_coord<X>(p, 0, ic);
5085  const auto lat = decompress_coord<Y>(p, 0, ic);
5086  const double latdiff = meters / (const1 * const2);
5087  const double t1 = sinf(meters / (2.0 * const2));
5088  const double t2 = cosf(const1 * lat);
5089  const double londiff = (2.0 * asinf(t1 / t2)) / const1;
5090  return !(lon + londiff < min_lon || lon - londiff > max_lon ||
5091  lat + latdiff < min_lat || lat - latdiff > max_lat);
5092 }
5093 
5094 #ifndef __CUDACC__
5095 
5097  int8_t* ptr = p.ptr;
5098  int32_t lsize = p.getSize();
5099  int32_t ic = p.getCompression();
5100  int32_t isr = p.getInputSrid();
5101  int32_t osr = p.getOutputSrid();
5102 
5103  double x = ST_X_Point(ptr, lsize, ic, isr, osr);
5104  double y = ST_Y_Point(ptr, lsize, ic, isr, osr);
5105  auto point = Geospatial::GeoPoint(std::vector<double>{x, y});
5106  return point;
5107 }
5108 
5110  int8_t* ptr = mp.ptr;
5111  int32_t lsize = mp.getSize();
5112  int32_t ic = mp.getCompression();
5113  int32_t isr = mp.getInputSrid();
5114  int32_t osr = mp.getOutputSrid();
5115 
5116  std::vector<double> coords =
5118  auto multipoint = Geospatial::GeoMultiPoint(coords);
5119  multipoint.transform(isr, osr);
5120  return multipoint;
5121 }
5122 
5124  int8_t* ptr = l.ptr;
5125  int32_t lsize = l.getSize();
5126  int32_t ic = l.getCompression();
5127  int32_t isr = l.getInputSrid();
5128  int32_t osr = l.getOutputSrid();
5129 
5130  std::vector<double> coords =
5132  auto linestring = Geospatial::GeoLineString(coords);
5133  linestring.transform(isr, osr);
5134  return linestring;
5135 }
5136 
5138  int8_t* ptr = ml.ptr;
5139  int32_t ml_coords_size = ml.getCoordsSize();
5140  int32_t* linestring_sizes = reinterpret_cast<int32_t*>(ml.getLineStringSizes());
5141  int32_t num_linestrings = ml.getNumLineStrings();
5142  int32_t ic = ml.getCompression();
5143  int32_t isr = ml.getInputSrid();
5144  int32_t osr = ml.getOutputSrid();
5145 
5146  std::vector<double> coords =
5147  *Geospatial::decompress_coords<double, int32_t>(ic, ptr, ml_coords_size);
5148 
5149  std::vector<int32_t> v_linestring_sizes(linestring_sizes,
5150  linestring_sizes + num_linestrings);
5151 
5152  auto multilinestring = Geospatial::GeoMultiLineString(coords, v_linestring_sizes);
5153  multilinestring.transform(isr, osr);
5154  return multilinestring;
5155 }
5156 
5158  int8_t* poly_coords = p.ptr_coords;
5159  int32_t poly_coords_size = p.getCoordsSize();
5160  int32_t* poly_ring_sizes = reinterpret_cast<int32_t*>(p.getRingSizes());
5161  int32_t poly_num_rings = p.getNumRings();
5162  int32_t ic = p.getCompression();
5163  int32_t isr = p.getInputSrid();
5164  int32_t osr = p.getOutputSrid();
5165 
5166  std::vector<double> coords =
5167  *Geospatial::decompress_coords<double, int32_t>(ic, poly_coords, poly_coords_size);
5168 
5169  std::vector<int32_t> ring_sizes(poly_ring_sizes, poly_ring_sizes + poly_num_rings);
5170  auto polygon = Geospatial::GeoPolygon(coords, ring_sizes);
5171  polygon.transform(isr, osr);
5172  return polygon;
5173 }
5174 
5176  int8_t* poly_coords = mp.ptr_coords;
5177  int32_t poly_coords_size = mp.getCoordsSize();
5178  int32_t* poly_ring_sizes = reinterpret_cast<int32_t*>(mp.getRingSizes());
5179  int32_t poly_num_rings = mp.getNumRings();
5180  int32_t* poly_sizes = reinterpret_cast<int32_t*>(mp.getPolygonSizes());
5181  int32_t num_polys = mp.getNumPolygons();
5182  int32_t ic = mp.getCompression();
5183  int32_t isr = mp.getInputSrid();
5184  int32_t osr = mp.getOutputSrid();
5185 
5186  std::vector<double> coords =
5187  *Geospatial::decompress_coords<double, int32_t>(ic, poly_coords, poly_coords_size);
5188 
5189  std::vector<int32_t> ring_sizes(poly_ring_sizes, poly_ring_sizes + poly_num_rings);
5190  std::vector<int32_t> poly_rings(poly_sizes, poly_sizes + num_polys);
5191 
5192  auto multipolygon = Geospatial::GeoMultiPolygon(coords, ring_sizes, poly_rings);
5193  multipolygon.transform(isr, osr);
5194  return multipolygon;
5195 }
5196 
5197 /*
5198  Return the Well-Known Text (WKT) representation of the geometry/geography
5199  without SRID metadata.
5200 
5201  Reference
5202  ---------
5203  https://postgis.net/docs/ST_AsText.html
5204 */
5206  GeoPoint& p) {
5208  std::string wkt = point.getWktString();
5209  return TextEncodingNone(mgr, wkt);
5210 }
5211 
5215  std::string wkt = multipoint.getWktString();
5216  return TextEncodingNone(mgr, wkt);
5217 }
5218 
5222  std::string wkt = linestring.getWktString();
5223  return TextEncodingNone(mgr, wkt);
5224 }
5225 
5229  std::string wkt = multilinestring.getWktString();
5230  return TextEncodingNone(mgr, wkt);
5231 }
5232 
5234  GeoPolygon& p) {
5236  std::string wkt = polygon.getWktString();
5237  return TextEncodingNone(mgr, wkt);
5238 }
5239 
5243  std::string wkt = multipolygon.getWktString();
5244  return TextEncodingNone(mgr, wkt);
5245 }
5246 
5247 /*
5248  Alias for ST_AsText
5249 
5250  Reference
5251  ---------
5252  https://docs.snowflake.com/en/sql-reference/functions/st_aswkt
5253 */
5254 
5256  GeoPoint& p) {
5257  return ST_AsText__GeoPoint__cpu_(mgr, p);
5258 }
5259 
5261  GeoMultiPoint& p) {
5262  return ST_AsText__GeoMultiPoint__cpu_(mgr, p);
5263 }
5264 
5266  GeoLineString& p) {
5267  return ST_AsText__GeoLineString__cpu_(mgr, p);
5268 }
5269 
5272  return ST_AsText__GeoMultiLineString__cpu_(mgr, p);
5273 }
5274 
5276  GeoPolygon& p) {
5277  return ST_AsText__GeoPolygon__cpu_(mgr, p);
5278 }
5279 
5282  return ST_AsText__GeoMultiPolygon__cpu_(mgr, p);
5283 }
5284 
5285 /*
5286  Return the OGC/ISO Well-Known Binary (WKB) representation of the
5287  geometry/geography without SRID meta data.
5288 
5289  Reference
5290  ---------
5291  https://postgis.net/docs/ST_AsBinary.html
5292  https://libgeos.org/specifications/wkb/
5293 */
5294 
5295 template <typename T>
5296 ALWAYS_INLINE std::string __wkb_to_str(T& geometry) {
5297  std::vector<uint8_t> bytes;
5298 
5299  bool ok = geometry.getWkb(bytes);
5300  if (!ok) {
5301  return std::string();
5302  }
5303 
5304  std::ostringstream ss;
5305  for (auto b : bytes) {
5306  ss << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(b);
5307  }
5308  return ss.str();
5309 }
5310 
5312  GeoPoint& p) {
5314  std::string wkb = __wkb_to_str(point);
5315  return TextEncodingNone(mgr, wkb);
5316 }
5317 
5321  std::string wkb = __wkb_to_str(multipoint);
5322  return TextEncodingNone(mgr, wkb);
5323 }
5324 
5328  std::string wkb = __wkb_to_str(linestring);
5329  return TextEncodingNone(mgr, wkb);
5330 }
5331 
5335  std::string wkb = __wkb_to_str(multilinestring);
5336  return TextEncodingNone(mgr, wkb);
5337 }
5338 
5340  GeoPolygon& p) {
5342  std::string wkb = __wkb_to_str(polygon);
5343  return TextEncodingNone(mgr, wkb);
5344 }
5345 
5349  std::string wkb = __wkb_to_str(multipolygon);
5350  return TextEncodingNone(mgr, wkb);
5351 }
5352 
5353 /*
5354  Alias for ST_AsBinary
5355 
5356  Reference
5357  ---------
5358  https://docs.snowflake.com/en/sql-reference/functions/st_aswkb
5359 */
5360 
5362  GeoPoint& p) {
5363  return ST_AsBinary__GeoPoint__cpu_(mgr, p);
5364 }
5365 
5367  GeoMultiPoint& p) {
5368  return ST_AsBinary__GeoMultiPoint__cpu_(mgr, p);
5369 }
5370 
5372  GeoLineString& p) {
5373  return ST_AsBinary__GeoLineString__cpu_(mgr, p);
5374 }
5375 
5379 }
5380 
5382  GeoPolygon& p) {
5383  return ST_AsBinary__GeoPolygon__cpu_(mgr, p);
5384 }
5385 
5388  return ST_AsBinary__GeoMultiPolygon__cpu_(mgr, p);
5389 }
5390 
5391 #endif // #ifndef __CUDACC__
EXTENSION_NOINLINE double ST_Perimeter_MultiPolygon(int8_t *mpoly_coords, int32_t mpoly_coords_size, int8_t *mpoly_ring_sizes, int32_t mpoly_num_rings, int8_t *mpoly_poly_sizes, int32_t mpoly_num_polys, int32_t ic, int32_t isr, int32_t osr)
EXTENSION_NOINLINE double convert_meters_to_pixel_width(const double meters, int8_t *p, const int64_t psize, const int32_t ic, const int32_t isr, const int32_t osr, const double min_lon, const double max_lon, const int32_t img_width, const double min_width)
EXTENSION_INLINE bool ST_Intersects_Point_Polygon(int8_t *p, int64_t psize, int8_t *poly, int64_t polysize, int32_t *poly_ring_sizes, int64_t poly_num_rings, double *poly_bounds, int64_t poly_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE double ST_Distance_MultiPoint_MultiPoint_Squared(int8_t *mp1, int64_t mp1size, int8_t *mp2, int64_t mp2size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_INLINE double ST_Distance_MultiPolygon_MultiPoint(int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, int8_t *mp, int64_t mpsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
DEVICE ALWAYS_INLINE double distance_point_multilinestring(int8_t *p, int64_t psize, int8_t *mls, int64_t mls_size, int32_t *mls_ls_sizes, int64_t mls_ls_num, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
DEVICE ALWAYS_INLINE double length_linestring(int8_t *l, int32_t lsize, int32_t ic, int32_t isr, int32_t osr, bool geodesic, bool check_closed)
DEVICE int64_t getSize() const
Definition: heavydbTypes.h:954
EXTENSION_NOINLINE double ST_Distance_LineString_LineString(int8_t *l1, int64_t l1size, int8_t *l2, int64_t l2size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_NOINLINE double ST_Distance_Point_Point(int8_t *p1, int64_t p1size, int8_t *p2, int64_t p2size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_INLINE int64_t HeavyDB_Geo_PolyBoundsPtr(double *bounds, int64_t size)
EXTENSION_INLINE double ST_Distance_MultiPoint_Polygon(int8_t *mp, int64_t mpsize, int8_t *poly, int64_t polysize, int32_t *poly_ring_sizes, int64_t poly_num_rings, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_INLINE double ST_Distance_LineString_Point_Geodesic(int8_t *l, int64_t lsize, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE double ST_X_Point(int8_t *p, int64_t psize, int32_t ic, int32_t isr, int32_t osr)
DEVICE ALWAYS_INLINE bool on_segment(double px, double py, double qx, double qy, double rx, double ry)
DEVICE int32_t getCoordsSize() const
DEVICE ALWAYS_INLINE Point2D conv_utm_4326(const Point2D point, const int32_t utm_srid)
Geospatial::GeoMultiLineString to_Geospatial_GeoMultiLineString(GeoMultiLineString &ml)
DEVICE ALWAYS_INLINE double area_polygon(int8_t *poly_coords, int32_t poly_coords_size, int8_t *poly_ring_sizes_in, int32_t poly_num_rings, int32_t ic, int32_t isr, int32_t osr)
EXTENSION_INLINE bool ST_DWithin_MultiPolygon_MultiPolygon(int8_t *mpoly1_coords, int64_t mpoly1_coords_size, int32_t *mpoly1_ring_sizes, int64_t mpoly1_num_rings, int32_t *mpoly1_poly_sizes, int64_t mpoly1_num_polys, double *mpoly1_bounds, int64_t mpoly1_bounds_size, int8_t *mpoly2_coords, int64_t mpoly2_coords_size, int32_t *mpoly2_ring_sizes, int64_t mpoly2_num_rings, int32_t *mpoly2_poly_sizes, int64_t mpoly2_num_polys, double *mpoly2_bounds, int64_t mpoly2_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double distance_within)
EXTENSION_INLINE double ST_Distance_MultiPoint_MultiPolygon(int8_t *mp, int64_t mpsize, int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_INLINE double ST_Distance_MultiPoint_Point_Squared(int8_t *mp, int64_t mpsize, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_INLINE bool ST_Intersects_MultiPolygon_Polygon(int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, double *mpoly_bounds, int64_t mpoly_bounds_size, int8_t *poly_coords, int64_t poly_coords_size, int32_t *poly_ring_sizes, int64_t poly_num_rings, double *poly_bounds, int64_t poly_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
DEVICE ALWAYS_INLINE bool box_dwithin_box(double *bounds1, int64_t bounds1_size, int32_t isr1, double *bounds2, int64_t bounds2_size, int32_t isr2, int32_t osr, double distance)
EXTENSION_NOINLINE TextEncodingNone ST_AsWkb__GeoPoint__cpu_(RowFunctionManager &mgr, GeoPoint &p)
EXTENSION_NOINLINE bool ST_Contains_Point_Point(int8_t *p1, int64_t p1size, int8_t *p2, int64_t p2size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE TextEncodingNone ST_AsText__GeoMultiLineString__cpu_(RowFunctionManager &mgr, GeoMultiLineString &ml)
EXTENSION_NOINLINE TextEncodingNone ST_AsWkb__GeoLineString__cpu_(RowFunctionManager &mgr, GeoLineString &p)
#define EXTENSION_NOINLINE
Definition: heavydbTypes.h:58
EXTENSION_NOINLINE double ST_Distance_Point_LineString_Geodesic(int8_t *p, int64_t psize, int8_t *l, int64_t lsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
DEVICE double decompress_latitude_coord_geoint32(const int32_t compressed)
DEVICE ALWAYS_INLINE bool centroid_add_triangle(double x1, double y1, double x2, double y2, double x3, double y3, double sign, double *total_area2, double *cg3)
Geospatial::GeoLineString to_Geospatial_GeoLineString(GeoLineString &l)
EXTENSION_NOINLINE double ST_XMax(int8_t *coords, int64_t size, int32_t ic, int32_t isr, int32_t osr)
DEVICE ALWAYS_INLINE double max_distance_point_linestring(int8_t *p, int64_t psize, int8_t *l, int64_t lsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, bool check_closed)
DEVICE int32_t getInputSrid() const
Definition: heavydbTypes.h:958
EXTENSION_NOINLINE bool ST_Intersects_LineString_MultiPolygon(int8_t *l, int64_t lsize, double *lbounds, int64_t lbounds_size, int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, double *mpoly_bounds, int64_t mpoly_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE TextEncodingNone ST_AsWkb__GeoMultiLineString__cpu_(RowFunctionManager &mgr, GeoMultiLineString &p)
EXTENSION_NOINLINE TextEncodingNone ST_AsWkb__GeoMultiPolygon__cpu_(RowFunctionManager &mgr, GeoMultiPolygon &p)
EXTENSION_NOINLINE double ST_Distance_Point_LineString(int8_t *p, int64_t psize, int8_t *l, int64_t lsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_INLINE bool ST_DWithin_Point_Polygon(int8_t *p, int64_t psize, int8_t *poly_coords, int64_t poly_coords_size, int32_t *poly_ring_sizes, int64_t poly_num_rings, double *poly_bounds, int64_t poly_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double distance_within)
DEVICE ALWAYS_INLINE double calculateY() const
Definition: Utm.h:195
EXTENSION_NOINLINE bool ST_Intersects_LineString_Polygon(int8_t *l, int64_t lsize, double *lbounds, int64_t lbounds_size, int8_t *poly, int64_t polysize, int32_t *poly_ring_sizes, int64_t poly_num_rings, double *poly_bounds, int64_t poly_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
DEVICE ALWAYS_INLINE double perimeter_multipolygon(int8_t *mpoly_coords, int32_t mpoly_coords_size, int8_t *mpoly_ring_sizes_in, int32_t mpoly_num_rings, int8_t *mpoly_poly_sizes, int32_t mpoly_num_polys, int32_t ic, int32_t isr, int32_t osr, bool geodesic)
Simplified core of GeoJSON Polygon coordinates definition.
EXTENSION_NOINLINE double ST_Distance_Point_MultiPolygon(int8_t *p, int64_t psize, int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_NOINLINE bool ST_Intersects_Polygon_Polygon(int8_t *poly1_coords, int64_t poly1_coords_size, int32_t *poly1_ring_sizes, int64_t poly1_num_rings, double *poly1_bounds, int64_t poly1_bounds_size, int8_t *poly2_coords, int64_t poly2_coords_size, int32_t *poly2_ring_sizes, int64_t poly2_num_rings, double *poly2_bounds, int64_t poly2_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE bool is_point_size_in_view(int8_t *p, const int64_t psize, const int32_t ic, const double meters, const double min_lon, const double max_lon, const double min_lat, const double max_lat)
DEVICE double distance_point_line(double px, double py, double l1x, double l1y, double l2x, double l2y)
EXTENSION_NOINLINE double ST_Distance_MultiLineString_MultiLineString(int8_t *mls1, int64_t mls1size, int32_t *mls1_ls_sizes, int64_t mls1_ls_num, int8_t *mls2, int64_t mls2size, int32_t *mls2_ls_sizes, int64_t mls2_ls_num, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
DEVICE int32_t getSize() const
Definition: heavydbTypes.h:990
EXTENSION_INLINE double ST_YMin_Bounds(double *bounds, int64_t size, int32_t isr, int32_t osr)
Geospatial::GeoMultiPoint to_Geospatial_GeoMultiPoint(GeoMultiPoint &mp)
DEVICE int32_t getNumLineStrings() const
EXTENSION_NOINLINE TextEncodingNone ST_AsText__GeoPolygon__cpu_(RowFunctionManager &mgr, GeoPolygon &p)
EXTENSION_NOINLINE double ST_YMax(int8_t *coords, int64_t size, int32_t ic, int32_t isr, int32_t osr)
DEVICE ALWAYS_INLINE int32_t compressed_coord(const int8_t *data, const int32_t index)
EXTENSION_INLINE double ST_XMin_Bounds(double *bounds, int64_t size, int32_t isr, int32_t osr)
EXTENSION_NOINLINE bool ST_cContains_Polygon_Point(const int8_t *poly_coords, const int64_t poly_coords_size, const int32_t *poly_ring_sizes, const int64_t poly_num_rings, const double *poly_bounds, const int64_t poly_bounds_size, const int8_t *p, const int64_t psize, const int32_t ic1, const int32_t isr1, const int32_t ic2, const int32_t isr2, const int32_t osr)
DEVICE ALWAYS_INLINE T is_left(const T lx0, const T ly0, const T lx1, const T ly1, const T px, const T py)
DEVICE ALWAYS_INLINE bool Contains_MultiPolygon_Point_Impl(const int8_t *mpoly_coords, const int64_t mpoly_coords_size, const int32_t *mpoly_ring_sizes, const int64_t mpoly_num_rings, const int32_t *mpoly_poly_sizes, const int64_t mpoly_num_polys, const double *mpoly_bounds, const int64_t mpoly_bounds_size, const int8_t *p, const int64_t psize, const int32_t ic1, const int32_t isr1, const int32_t ic2, const int32_t isr2, const int32_t osr)
DEVICE ALWAYS_INLINE double area_triangle(double x1, double y1, double x2, double y2, double x3, double y3)
EXTENSION_INLINE bool ST_DWithin_Polygon_Polygon(int8_t *poly1_coords, int64_t poly1_coords_size, int32_t *poly1_ring_sizes, int64_t poly1_num_rings, double *poly1_bounds, int64_t poly1_bounds_size, int8_t *poly2_coords, int64_t poly2_coords_size, int32_t *poly2_ring_sizes, int64_t poly2_num_rings, double *poly2_bounds, int64_t poly2_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double distance_within)
EXTENSION_NOINLINE double ST_XMin(int8_t *coords, int64_t size, int32_t ic, int32_t isr, int32_t osr)
DEVICE int32_t getOutputSrid() const
Definition: heavydbTypes.h:996
EXTENSION_NOINLINE TextEncodingNone ST_AsWkt__GeoMultiLineString__cpu_(RowFunctionManager &mgr, GeoMultiLineString &p)
EXTENSION_INLINE double ST_Distance_MultiPoint_MultiLineString(int8_t *mp, int64_t mpsize, int8_t *mls, int64_t mls_size, int32_t *mls_ls_sizes, int64_t mls_ls_num, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_INLINE bool ST_Intersects_Polygon_Point(int8_t *poly, int64_t polysize, int32_t *poly_ring_sizes, int64_t poly_num_rings, double *poly_bounds, int64_t poly_bounds_size, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE double ST_Distance_Point_Polygon(int8_t *p, int64_t psize, int8_t *poly, int64_t polysize, int32_t *poly_ring_sizes, int64_t poly_num_rings, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_NOINLINE double ST_Distance_Point_Point_Squared(int8_t *p1, int64_t p1size, int8_t *p2, int64_t p2size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
DEVICE int32_t getCompression() const
Definition: heavydbTypes.h:956
Geospatial::GeoPoint to_Geospatial_GeoPoint(GeoPoint &p)
EXTENSION_INLINE bool ST_DWithin_Point_Point(int8_t *p1, int64_t p1size, int8_t *p2, int64_t p2size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double distance_within)
EXTENSION_NOINLINE double ST_Y_Point(int8_t *p, int64_t psize, int32_t ic, int32_t isr, int32_t osr)
EXTENSION_NOINLINE double ST_Distance_Point_MultiPoint_Squared(int8_t *p, int64_t psize, int8_t *mp, int64_t mpsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
DEVICE ALWAYS_INLINE Point2D coord(const int8_t *data, const int32_t x_index, const int32_t ic, const int32_t isr, const int32_t osr)
EXTENSION_NOINLINE TextEncodingNone ST_AsWkb__GeoMultiPoint__cpu_(RowFunctionManager &mgr, GeoMultiPoint &p)
EXTENSION_NOINLINE double convert_meters_to_pixel_height(const double meters, int8_t *p, const int64_t psize, const int32_t ic, const int32_t isr, const int32_t osr, const double min_lat, const double max_lat, const int32_t img_height, const double min_height)
#define TOLERANCE_GEOINT32
DEVICE int8_t * getLineStringSizes()
std::string to_string(char const *&&v)
DEVICE ALWAYS_INLINE CoordData trim_linestring_to_buffered_box(int8_t *l1, int64_t l1size, int32_t ic1, int32_t isr1, double *bounds2, int64_t bounds2_size, int32_t isr2, int32_t osr, double distance)
DEVICE double max_distance_point_line(double px, double py, double l1x, double l1y, double l2x, double l2y)
EXTENSION_NOINLINE bool Point_Overlaps_Box(double *bounds, int64_t bounds_size, double px, double py)
EXTENSION_INLINE double ST_Distance_Polygon_MultiPoint(int8_t *poly, int64_t polysize, int32_t *poly_ring_sizes, int64_t poly_num_rings, int8_t *mp, int64_t mpsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_NOINLINE void ST_Centroid_MultiPoint(int8_t *mp, int32_t mpsize, int32_t ic, int32_t isr, int32_t osr, double *multipoint_centroid)
Simplified core of GeoJSON MultiPolygon coordinates definition.
#define DEVICE
EXTENSION_INLINE double ST_Distance_MultiLineString_Point(int8_t *mls, int64_t mls_size, int32_t *mls_ls_sizes, int64_t mls_ls_num, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_INLINE bool ST_cIntersects_MultiPolygon_Point(int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, double *mpoly_bounds, int64_t mpoly_bounds_size, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
DEVICE ALWAYS_INLINE Point2D conv_4326_900913(const Point2D point)
DEVICE ALWAYS_INLINE double distance_point_polygon(int8_t *p, int64_t psize, int8_t *poly, int64_t polysize, int32_t *poly_ring_sizes, int64_t poly_num_rings, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_NOINLINE double ST_Distance_Polygon_MultiPolygon(int8_t *poly1_coords, int64_t poly1_coords_size, int32_t *poly1_ring_sizes, int64_t poly1_num_rings, int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_NOINLINE void ST_Centroid_Polygon(int8_t *poly_coords, int32_t poly_coords_size, int32_t *poly_ring_sizes, int32_t poly_num_rings, int32_t ic, int32_t isr, int32_t osr, double *poly_centroid)
EXTENSION_NOINLINE TextEncodingNone ST_AsBinary__GeoMultiPolygon__cpu_(RowFunctionManager &mgr, GeoMultiPolygon &mp)
EXTENSION_NOINLINE double ST_Distance_Polygon_Polygon(int8_t *poly1_coords, int64_t poly1_coords_size, int32_t *poly1_ring_sizes, int64_t poly1_num_rings, int8_t *poly2_coords, int64_t poly2_coords_size, int32_t *poly2_ring_sizes, int64_t poly2_num_rings, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_NOINLINE TextEncodingNone ST_AsText__GeoPoint__cpu_(RowFunctionManager &mgr, GeoPoint &p)
EXTENSION_NOINLINE bool ST_Intersects_Point_LineString(int8_t *p, int64_t psize, int8_t *l, int64_t lsize, double *lbounds, int64_t lbounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
#define EXTENSION_INLINE
Definition: heavydbTypes.h:57
EXTENSION_INLINE double ST_Distance_MultiPolygon_Point(int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_NOINLINE double ST_MaxDistance_Point_LineString(int8_t *p, int64_t psize, int8_t *l, int64_t lsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE bool ST_Contains_Polygon_Point(const int8_t *poly_coords, const int64_t poly_coords_size, const int32_t *poly_ring_sizes, const int64_t poly_num_rings, const double *poly_bounds, const int64_t poly_bounds_size, const int8_t *p, const int64_t psize, const int32_t ic1, const int32_t isr1, const int32_t ic2, const int32_t isr2, const int32_t osr)
DEVICE ALWAYS_INLINE int16_t orientation(double px, double py, double qx, double qy, double rx, double ry)
EXTENSION_NOINLINE TextEncodingNone ST_AsWkt__GeoLineString__cpu_(RowFunctionManager &mgr, GeoLineString &p)
DEVICE double distance_line_line_squared(double l11x, double l11y, double l12x, double l12y, double l21x, double l21y, double l22x, double l22y)
EXTENSION_NOINLINE TextEncodingNone ST_AsWkt__GeoMultiPoint__cpu_(RowFunctionManager &mgr, GeoMultiPoint &p)
EXTENSION_INLINE double ST_Distance_MultiPolygon_LineString(int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, int8_t *l, int64_t lsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_NOINLINE double ST_YMin(int8_t *coords, int64_t size, int32_t ic, int32_t isr, int32_t osr)
EXTENSION_NOINLINE double ST_Distance_Point_MultiPoint(int8_t *p, int64_t psize, int8_t *mp, int64_t mpsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
DEVICE ALWAYS_INLINE double area_ring(int8_t *ring, int64_t ringsize, int32_t ic, int32_t isr, int32_t osr)
EXTENSION_INLINE bool ST_DWithin_Polygon_MultiPolygon(int8_t *poly_coords, int64_t poly_coords_size, int32_t *poly_ring_sizes, int64_t poly_num_rings, double *poly_bounds, int64_t poly_bounds_size, int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, double *mpoly_bounds, int64_t mpoly_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double distance_within)
EXTENSION_INLINE double ST_Distance_LineString_Point(int8_t *l, int64_t lsize, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_INLINE bool ST_Contains_LineString_Point(int8_t *l, int64_t lsize, double *lbounds, int64_t lbounds_size, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE bool ST_cContains_MultiPolygon_Point(int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, double *mpoly_bounds, int64_t mpoly_bounds_size, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE TextEncodingNone ST_AsWkt__GeoPoint__cpu_(RowFunctionManager &mgr, GeoPoint &p)
EXTENSION_NOINLINE TextEncodingNone ST_AsBinary__GeoLineString__cpu_(RowFunctionManager &mgr, GeoLineString &l)
DEVICE ALWAYS_INLINE bool box_overlaps_box(double *bounds1, int64_t bounds1_size, double *bounds2, int64_t bounds2_size)
DEVICE bool is_utm_srid(unsigned const srid)
Definition: Utm.h:113
#define DEBUG_STMT(x)
DEVICE int32_t getInputSrid() const
DEVICE int32_t getCompression() const
EXTENSION_NOINLINE void ST_Centroid_Point(int8_t *p, int32_t psize, int32_t ic, int32_t isr, int32_t osr, double *point_centroid)
EXTENSION_NOINLINE void ST_Centroid_MultiPolygon(int8_t *mpoly_coords, int32_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int32_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int32_t mpoly_num_polys, int32_t ic, int32_t isr, int32_t osr, double *mpoly_centroid)
EXTENSION_INLINE bool ST_Intersects_Point_MultiPolygon(int8_t *p, int64_t psize, int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, double *mpoly_bounds, int64_t mpoly_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_INLINE double ST_Distance_MultiPolygon_Polygon(int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, int8_t *poly1_coords, int64_t poly1_coords_size, int32_t *poly1_ring_sizes, int64_t poly1_num_rings, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
DEVICE bool linestring_intersects_line(int8_t *l, int32_t lnum_coords, double l1x, double l1y, double l2x, double l2y, int32_t ic1, int32_t isr1, int32_t osr)
DEVICE int32_t getSize() const
Definition: heavydbTypes.h:972
#define TOLERANCE_DEFAULT
DEVICE ALWAYS_INLINE bool x_and_y_are_dependent(const int32_t isr, const int32_t osr)
EXTENSION_NOINLINE TextEncodingNone ST_AsText__GeoMultiPoint__cpu_(RowFunctionManager &mgr, GeoMultiPoint &mp)
EXTENSION_NOINLINE double ST_Distance_LineString_Polygon(int8_t *l, int64_t lsize, int8_t *poly_coords, int64_t poly_coords_size, int32_t *poly_ring_sizes, int64_t poly_num_rings, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
DEVICE bool line_intersects_line(double l11x, double l11y, double l12x, double l12y, double l21x, double l21y, double l22x, double l22y)
EXTENSION_NOINLINE bool ST_Contains_Polygon_LineString(int8_t *poly_coords, int64_t poly_coords_size, int32_t *poly_ring_sizes, int64_t poly_num_rings, double *poly_bounds, int64_t poly_bounds_size, int8_t *l, int64_t lsize, double *lbounds, int64_t lbounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
DEVICE ALWAYS_INLINE Point2D conv_4326_utm(const Point2D point, const int32_t utm_srid)
EXTENSION_NOINLINE double ST_Length_MultiLineString(int8_t *coords, int64_t coords_sz, int8_t *linestring_sizes_in, int64_t linestring_sizes_sz, int32_t ic, int32_t isr, int32_t osr)
EXTENSION_NOINLINE bool ST_Intersects_Polygon_MultiPolygon(int8_t *poly_coords, int64_t poly_coords_size, int32_t *poly_ring_sizes, int64_t poly_num_rings, double *poly_bounds, int64_t poly_bounds_size, int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, double *mpoly_bounds, int64_t mpoly_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE double ST_Distance_LineString_MultiPolygon(int8_t *l, int64_t lsize, int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_NOINLINE double ST_MaxDistance_LineString_Point(int8_t *l, int64_t lsize, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
DEVICE ALWAYS_INLINE bool tol_zero_template(const T x, const T tolerance=TOLERANCE_DEFAULT)
EXTENSION_NOINLINE bool is_point_in_view(int8_t *p, const int64_t psize, const int32_t ic, const double min_lon, const double max_lon, const double min_lat, const double max_lat)
EXTENSION_INLINE double ST_Distance_LineString_MultiPoint(int8_t *l, int64_t lsize, int8_t *mp, int64_t mpsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_INLINE bool ST_Intersects_Polygon_LineString(int8_t *poly, int64_t polysize, int32_t *poly_ring_sizes, int64_t poly_num_rings, double *poly_bounds, int64_t poly_bounds_size, int8_t *l, int64_t lsize, double *lbounds, int64_t lbounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
#define UNLIKELY(x)
Definition: likely.h:25
DEVICE ALWAYS_INLINE double calculateY() const
Definition: Utm.h:263
EXTENSION_INLINE bool ST_DWithin_Point_LineString(int8_t *p1, int64_t p1size, int8_t *l2, int64_t l2size, double *l2bounds, int64_t l2bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double distance_within)
EXTENSION_NOINLINE bool ST_Contains_MultiPolygon_LineString(int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, double *mpoly_bounds, int64_t mpoly_bounds_size, int8_t *l, int64_t lsize, double *lbounds, int64_t lbounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
DEVICE int32_t getCompression() const
Definition: heavydbTypes.h:974
DEVICE ALWAYS_INLINE double calculateX() const
Definition: Utm.h:170
DEVICE ALWAYS_INLINE bool centroid_add_polygon(int8_t *poly_coords, int64_t poly_coords_size, int32_t *poly_ring_sizes, int64_t poly_num_rings, int32_t ic, int32_t isr, int32_t osr, double *total_area2, double *cg3, double *total_length, double *linestring_centroid_sum, int64_t *num_points, double *point_centroid_sum)
EXTENSION_NOINLINE TextEncodingNone ST_AsBinary__GeoPoint__cpu_(RowFunctionManager &mgr, GeoPoint &p)
Convert to/from WGS84 (long,lat) and UTM (x,y) given utm zone srid.
EXTENSION_NOINLINE TextEncodingNone ST_AsWkt__GeoMultiPolygon__cpu_(RowFunctionManager &mgr, GeoMultiPolygon &p)
DEVICE int32_t getOutputSrid() const
Definition: heavydbTypes.h:978
EXTENSION_NOINLINE bool ST_Contains_Point_Polygon(int8_t *p, int64_t psize, int8_t *poly_coords, int64_t poly_coords_size, int32_t *poly_ring_sizes, int64_t poly_num_rings, double *poly_bounds, int64_t poly_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE double ST_Distance_Point_Point_Geodesic(int8_t *p1, int64_t p1size, int8_t *p2, int64_t p2size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
DEVICE ALWAYS_INLINE bool box_contains_point(const double *bounds, const int64_t bounds_size, const double px, const double py)
EXTENSION_NOINLINE TextEncodingNone ST_AsText__GeoMultiPolygon__cpu_(RowFunctionManager &mgr, GeoMultiPolygon &mp)
DEVICE double distance_ring_ring(int8_t *ring1, int32_t ring1_num_coords, int8_t *ring2, int32_t ring2_num_coords, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_NOINLINE double ST_Length_LineString(int8_t *coords, int64_t coords_sz, int32_t ic, int32_t isr, int32_t osr)
DEVICE double decompress_longitude_coord_geoint32(const int32_t compressed)
DEVICE ALWAYS_INLINE Point2D transform_point(const Point2D point, const int32_t isr, const int32_t osr)
EXTENSION_INLINE bool ST_Intersects_Point_Point(int8_t *p1, int64_t p1size, int8_t *p2, int64_t p2size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE double ST_Perimeter_MultiPolygon_Geodesic(int8_t *mpoly_coords, int32_t mpoly_coords_size, int8_t *mpoly_ring_sizes, int32_t mpoly_num_rings, int8_t *mpoly_poly_sizes, int32_t mpoly_num_polys, int32_t ic, int32_t isr, int32_t osr)
DEVICE ALWAYS_INLINE bool tol_le(const double x, const double y, const double tolerance=TOLERANCE_DEFAULT)
std::shared_ptr< std::vector< double > > decompress_coords< double, int32_t >(const int32_t &ic, const int8_t *coords, const size_t coords_sz)
DEVICE ALWAYS_INLINE bool centroid_add_segment(double x1, double y1, double x2, double y2, double *length, double *linestring_centroid_sum)
EXTENSION_INLINE bool ST_DWithin_LineString_LineString(int8_t *l1, int64_t l1size, double *l1bounds, int64_t l1bounds_size, int8_t *l2, int64_t l2size, double *l2bounds, int64_t l2bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double distance_within)
DEVICE int32_t getInputSrid() const
Definition: heavydbTypes.h:976
DEVICE ALWAYS_INLINE bool tol_zero(const double x, const double tolerance=TOLERANCE_DEFAULT)
DEVICE ALWAYS_INLINE bool centroid_add_linestring(int8_t *l, int64_t lsize, int32_t ic, int32_t isr, int32_t osr, bool closed, double *total_length, double *linestring_centroid_sum, int64_t *num_points, double *point_centroid_sum)
EXTENSION_NOINLINE bool ST_Intersects_LineString_Linestring(int8_t *l1, int64_t l1size, double *l1bounds, int64_t l1bounds_size, int8_t *l2, int64_t l2size, double *l2bounds, int64_t l2bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
ALWAYS_INLINE std::string __wkb_to_str(T &geometry)
DEVICE ALWAYS_INLINE double distance_point_point_squared(double p1x, double p1y, double p2x, double p2y)
DEVICE ALWAYS_INLINE double distance_point_linestring(int8_t *p, int64_t psize, int8_t *l, int64_t lsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, bool check_closed, double threshold)
EXTENSION_NOINLINE double ST_Area_MultiPolygon(int8_t *mpoly_coords, int32_t mpoly_coords_size, int8_t *mpoly_ring_sizes, int32_t mpoly_num_rings, int8_t *mpoly_poly_sizes_in, int32_t mpoly_num_polys, int32_t ic, int32_t isr, int32_t osr)
DEVICE bool linestring_intersects_linestring(int8_t *l, int32_t lnum_coords, double l1x, double l1y, double l2x, double l2y, int32_t ic1, int32_t isr1, int32_t osr)
EXTENSION_NOINLINE TextEncodingNone ST_AsBinary__GeoMultiPoint__cpu_(RowFunctionManager &mgr, GeoMultiPoint &mp)
EXTENSION_INLINE bool ST_Intersects_MultiPolygon_MultiPolygon(int8_t *mpoly1_coords, int64_t mpoly1_coords_size, int32_t *mpoly1_ring_sizes, int64_t mpoly1_num_rings, int32_t *mpoly1_poly_sizes, int64_t mpoly1_num_polys, double *mpoly1_bounds, int64_t mpoly1_bounds_size, int8_t *mpoly2_coords, int64_t mpoly2_coords_size, int32_t *mpoly2_ring_sizes, int64_t mpoly2_num_rings, int32_t *mpoly2_poly_sizes, int64_t mpoly2_num_polys, double *mpoly2_bounds, int64_t mpoly2_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
DEVICE int32_t getCompression() const
Definition: heavydbTypes.h:992
EXTENSION_NOINLINE double ST_Perimeter_Polygon(int8_t *poly, int32_t polysize, int8_t *poly_ring_sizes, int32_t poly_num_rings, int32_t ic, int32_t isr, int32_t osr)
EXTENSION_INLINE bool ST_Intersects_MultiPolygon_LineString(int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, double *mpoly_bounds, int64_t mpoly_bounds_size, int8_t *l, int64_t lsize, double *lbounds, int64_t lbounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE double distance_in_meters(const double fromlon, const double fromlat, const double tolon, const double tolat)
Computes the distance, in meters, between two WGS-84 positions.
EXTENSION_NOINLINE double ST_Length_LineString_Geodesic(int8_t *coords, int64_t coords_sz, int32_t ic, int32_t isr, int32_t osr)
DEVICE ALWAYS_INLINE double calculateX() const
Definition: Utm.h:255
DEVICE ALWAYS_INLINE double distance_point_multipolygon(int8_t *p, int64_t psize, int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
Geospatial::GeoPolygon to_Geospatial_GeoPolygon(GeoPolygon &p)
DEVICE ALWAYS_INLINE bool tol_ge(const double x, const double y, const double tolerance=TOLERANCE_DEFAULT)
DEVICE ALWAYS_INLINE bool polygon_contains_point(const int8_t *poly, const int32_t poly_num_coords, const double px, const double py, const int32_t ic1, const int32_t isr1, const int32_t osr)
DEVICE ALWAYS_INLINE int32_t compression_unit_size(const int32_t ic)
EXTENSION_NOINLINE TextEncodingNone ST_AsBinary__GeoPolygon__cpu_(RowFunctionManager &mgr, GeoPolygon &p)
EXTENSION_NOINLINE TextEncodingNone ST_AsBinary__GeoMultiLineString__cpu_(RowFunctionManager &mgr, GeoMultiLineString &ml)
std::string getWktString() const
Definition: Types.cpp:165
DEVICE ALWAYS_INLINE Point2D get_point(const int8_t *data, const int32_t x_index, const int32_t ic, const int32_t isr, const int32_t osr)
EXTENSION_INLINE bool ST_cIntersects_Polygon_Point(int8_t *poly, int64_t polysize, int32_t *poly_ring_sizes, int64_t poly_num_rings, double *poly_bounds, int64_t poly_bounds_size, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
#define TOLERANCE_DEFAULT_SQUARED
EXTENSION_INLINE bool ST_Intersects_LineString_Point(int8_t *l, int64_t lsize, double *lbounds, int64_t lbounds_size, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE TextEncodingNone ST_AsText__GeoLineString__cpu_(RowFunctionManager &mgr, GeoLineString &l)
EXTENSION_NOINLINE double ST_Distance_MultiPolygon_MultiPolygon(int8_t *mpoly1_coords, int64_t mpoly1_coords_size, int32_t *mpoly1_ring_sizes, int64_t mpoly1_num_rings, int32_t *mpoly1_poly_sizes, int64_t mpoly1_num_polys, int8_t *mpoly2_coords, int64_t mpoly2_coords_size, int32_t *mpoly2_ring_sizes, int64_t mpoly2_num_rings, int32_t *mpoly2_poly_sizes, int64_t mpoly2_num_polys, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_NOINLINE double ST_Distance_Point_ClosedLineString(int8_t *p, int64_t psize, int8_t *l, int64_t lsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_NOINLINE double ST_Area_Polygon(int8_t *poly_coords, int32_t poly_coords_size, int8_t *poly_ring_sizes, int32_t poly_num_rings, int32_t ic, int32_t isr, int32_t osr)
EXTENSION_NOINLINE bool ST_Contains_Polygon_Polygon(int8_t *poly1_coords, int64_t poly1_coords_size, int32_t *poly1_ring_sizes, int64_t poly1_num_rings, double *poly1_bounds, int64_t poly1_bounds_size, int8_t *poly2_coords, int64_t poly2_coords_size, int32_t *poly2_ring_sizes, int64_t poly2_num_rings, double *poly2_bounds, int64_t poly2_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE TextEncodingNone ST_AsWkb__GeoPolygon__cpu_(RowFunctionManager &mgr, GeoPolygon &p)
DEVICE ALWAYS_INLINE bool point_in_polygon_winding_number(const int8_t *poly, const int32_t poly_num_coords, const T px, const T py, const int32_t ic1, const int32_t isr1, const int32_t osr)
EXTENSION_NOINLINE TextEncodingNone ST_AsWkt__GeoPolygon__cpu_(RowFunctionManager &mgr, GeoPolygon &p)
EXTENSION_INLINE double ST_Distance_Polygon_Point(int8_t *poly_coords, int64_t poly_coords_size, int32_t *poly_ring_sizes, int64_t poly_num_rings, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
DEVICE double distance_point_line_squared(double px, double py, double l1x, double l1y, double l2x, double l2y)
#define COMPRESSION_GEOINT32
EXTENSION_NOINLINE double ST_Perimeter_Polygon_Geodesic(int8_t *poly, int32_t polysize, int8_t *poly_ring_sizes_in, int32_t poly_num_rings, int32_t ic, int32_t isr, int32_t osr)
DEVICE int32_t getInputSrid() const
Definition: heavydbTypes.h:994
DEVICE ALWAYS_INLINE double tol(int32_t ic)
EXTENSION_INLINE bool ST_DWithin_LineString_Polygon(int8_t *l1, int64_t l1size, double *l1bounds, int64_t l1bounds_size, int8_t *poly_coords, int64_t poly_coords_size, int32_t *poly_ring_sizes, int64_t poly_num_rings, double *poly_bounds, int64_t poly_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double distance_within)
DEVICE double distance_line_line(double l11x, double l11y, double l12x, double l12y, double l21x, double l21y, double l22x, double l22y)
DEVICE bool polygon_contains_linestring(int8_t *poly, int32_t poly_num_coords, int8_t *l, int64_t lnum_coords, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE bool ST_Contains_LineString_Polygon(int8_t *l, int64_t lsize, double *lbounds, int64_t lbounds_size, int8_t *poly_coords, int64_t poly_coords_size, int32_t *poly_ring_sizes, int64_t poly_num_rings, double *poly_bounds, int64_t poly_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
DEVICE ALWAYS_INLINE bool Contains_Polygon_Point_Impl(const int8_t *poly_coords, const int64_t poly_coords_size, const int32_t *poly_ring_sizes, const int64_t poly_num_rings, const double *poly_bounds, const int64_t poly_bounds_size, const int8_t *p, const int64_t psize, const int32_t ic1, const int32_t isr1, const int32_t ic2, const int32_t isr2, const int32_t osr)
EXTENSION_NOINLINE bool ST_Contains_MultiPolygon_Point(int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, double *mpoly_bounds, int64_t mpoly_bounds_size, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_INLINE bool ST_Intersects_MultiPolygon_Point(int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, double *mpoly_bounds, int64_t mpoly_bounds_size, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
DEVICE bool ring_intersects_line(int8_t *ring, int32_t ring_num_coords, double l1x, double l1y, double l2x, double l2y, int32_t ic1, int32_t isr1, int32_t osr)
DEVICE double distance_ring_linestring(int8_t *ring, int32_t ring_num_coords, int8_t *l, int32_t lnum_coords, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
#define ALWAYS_INLINE
EXTENSION_INLINE double ST_Distance_MultiPoint_LineString(int8_t *mp, int64_t mpsize, int8_t *l, int64_t lsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
DEVICE int32_t getOutputSrid() const
EXTENSION_NOINLINE double conv_4326_900913_y(const double y)
EXTENSION_INLINE bool ST_DWithin_Point_Point_Geodesic(int8_t *p1, int64_t p1size, int8_t *p2, int64_t p2size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double distance_within)
EXTENSION_NOINLINE double conv_4326_900913_x(const double x)
DEVICE ALWAYS_INLINE bool tol_eq(const double x, const double y, const double tolerance=TOLERANCE_DEFAULT)
DEVICE ALWAYS_INLINE bool box_contains_box_vertex(double *bounds1, int64_t bounds1_size, double *bounds2, int64_t bounds2_size)
EXTENSION_INLINE double ST_Distance_Polygon_LineString(int8_t *poly_coords, int64_t poly_coords_size, int32_t *poly_ring_sizes, int64_t poly_num_rings, int8_t *l, int64_t lsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
DEVICE ALWAYS_INLINE bool box_contains_box(double *bounds1, int64_t bounds1_size, double *bounds2, int64_t bounds2_size)
DEVICE ALWAYS_INLINE bool point_dwithin_box(int8_t *p1, int64_t p1size, int32_t ic1, int32_t isr1, double *bounds2, int64_t bounds2_size, int32_t isr2, int32_t osr, double distance)
EXTENSION_INLINE double ST_YMax_Bounds(double *bounds, int64_t size, int32_t isr, int32_t osr)
EXTENSION_NOINLINE void ST_Centroid_LineString(int8_t *coords, int32_t coords_sz, int32_t ic, int32_t isr, int32_t osr, double *linestring_centroid)
EXTENSION_INLINE double ST_XMax_Bounds(double *bounds, int64_t size, int32_t isr, int32_t osr)
DEVICE ALWAYS_INLINE double decompress_coord(const int8_t *data, const int32_t x_index, const int32_t ic)
Geospatial::GeoMultiPolygon to_Geospatial_GeoMultiPolygon(GeoMultiPolygon &mp)
EXTENSION_NOINLINE double ST_Distance_Point_MultiLineString(int8_t *p, int64_t psize, int8_t *mls, int64_t mls_size, int32_t *mls_ls_sizes, int64_t mls_ls_num, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_INLINE bool ST_DWithin_LineString_MultiPolygon(int8_t *l1, int64_t l1size, double *l1bounds, int64_t l1bounds_size, int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, double *mpoly_bounds, int64_t mpoly_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double distance_within)
DEVICE int32_t getOutputSrid() const
Definition: heavydbTypes.h:960
EXTENSION_INLINE bool ST_DWithin_Point_MultiPolygon(int8_t *p, int64_t psize, int8_t *mpoly_coords, int64_t mpoly_coords_size, int32_t *mpoly_ring_sizes, int64_t mpoly_num_rings, int32_t *mpoly_poly_sizes, int64_t mpoly_num_polys, double *mpoly_bounds, int64_t mpoly_bounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double distance_within)
EXTENSION_NOINLINE bool ST_Contains_Point_LineString(int8_t *p, int64_t psize, int8_t *l, int64_t lsize, double *lbounds, int64_t lbounds_size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr)
EXTENSION_NOINLINE double ST_Distance_MultiPoint_MultiPoint(int8_t *mp1, int64_t mp1size, int8_t *mp2, int64_t mp2size, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_INLINE double ST_Distance_MultiLineString_MultiPoint(int8_t *mls, int64_t mls_size, int32_t *mls_ls_sizes, int64_t mls_ls_num, int8_t *mp, int64_t mpsize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
EXTENSION_INLINE double ST_Distance_MultiPoint_Point(int8_t *mp, int64_t mpsize, int8_t *p, int64_t psize, int32_t ic1, int32_t isr1, int32_t ic2, int32_t isr2, int32_t osr, double threshold)
DEVICE ALWAYS_INLINE double distance_point_point(double p1x, double p1y, double p2x, double p2y)
DEVICE ALWAYS_INLINE bool centroid_add_ring(int8_t *ring, int64_t ringsize, int32_t ic, int32_t isr, int32_t osr, double sign, double *total_area2, double *cg3, double *total_length, double *linestring_centroid_sum, int64_t *num_points, double *point_centroid_sum)