OmniSciDB  cde582ebc3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GeosRuntime.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifdef ENABLE_GEOS
18 
19 #ifndef __CUDACC__
20 
21 #include <cstdarg>
22 #include <mutex>
23 
24 #include "Geospatial/Compression.h"
25 #include "Geospatial/Types.h"
27 #include "Shared/checked_alloc.h"
28 #include "Shared/funcannotations.h"
29 
30 #define GEOS_USE_ONLY_R_API
31 #include <geos_c.h>
32 
33 using namespace Geospatial;
34 
35 using WKB = std::vector<uint8_t>;
36 
37 #define MAX_GEOS_MESSAGE_LEN 200
38 
39 static std::mutex geos_log_info_mutex;
40 static std::mutex geos_log_error_mutex;
41 
42 // called by GEOS on notice
43 static void geos_notice_handler(const char* fmt, ...) {
44  char buffer[MAX_GEOS_MESSAGE_LEN];
45  va_list args;
46  va_start(args, fmt);
47  vsnprintf(buffer, MAX_GEOS_MESSAGE_LEN, fmt, args);
48  va_end(args);
49  {
50  std::lock_guard<std::mutex> guard(geos_log_info_mutex);
51  LOG(INFO) << "GEOS Notice: " << std::string(buffer);
52  }
53 }
54 
55 // called by GEOS on error
56 static void geos_error_handler(const char* fmt, ...) {
57  va_list args;
58  char buffer[MAX_GEOS_MESSAGE_LEN];
59  va_start(args, fmt);
60  vsnprintf(buffer, MAX_GEOS_MESSAGE_LEN, fmt, args);
61  va_end(args);
62  {
63  std::lock_guard<std::mutex> guard(geos_log_error_mutex);
64  LOG(ERROR) << "GEOS Error: " << std::string(buffer);
65  }
66 }
67 
68 GEOSContextHandle_t create_context() {
69 #if GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR < 5
70  GEOSContextHandle_t context = initGEOS_r(geos_notice_handler, geos_error_handler);
71  CHECK(context);
72  return context;
73 #else
74  GEOSContextHandle_t context = GEOS_init_r();
75  CHECK(context);
76  GEOSContext_setNoticeHandler_r(context, geos_notice_handler);
77  GEOSContext_setErrorHandler_r(context, geos_error_handler);
78  return context;
79 #endif
80 }
81 
82 void destroy_context(GEOSContextHandle_t context) {
83  CHECK(context);
84 #if GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR < 5
85  finishGEOS_r(context);
86 #else
87  GEOS_finish_r(context);
88 #endif
89 }
90 
91 bool toWkb(WKB& wkb,
92  int type, // internal geometry type
93  int8_t* coords,
94  int64_t coords_size,
95  int32_t* meta1, // e.g. ring_sizes
96  int64_t meta1_size, // e.g. num_rings
97  int32_t* meta2, // e.g. rings (number of rings in each poly)
98  int64_t meta2_size, // e.g. num_polys
99  int32_t ic, // input compression
100  int32_t srid_in, // input srid
101  int32_t srid_out, // output srid
102  int32_t* best_planar_srid_ptr) {
103  // decompressed double coords
104  auto cv = Geospatial::decompress_coords<double, int32_t>(ic, coords, coords_size);
105  auto execute_transform = (srid_in > 0 && srid_out > 0 && srid_in != srid_out);
106  if (static_cast<SQLTypes>(type) == kPOINT) {
107  GeoPoint point(*cv);
108  if (execute_transform && !point.transform(srid_in, srid_out)) {
109  return false;
110  }
111  if (best_planar_srid_ptr) {
112  // A non-NULL pointer signifies a request to find the best planar srid
113  // to transform this WGS84 geometry to.
114  *best_planar_srid_ptr = point.getBestPlanarSRID();
115  if (!point.transform(4326, *best_planar_srid_ptr)) {
116  return false;
117  }
118  }
119  return point.getWkb(wkb);
120  }
121  if (static_cast<SQLTypes>(type) == kLINESTRING) {
122  GeoLineString linestring(*cv);
123  if (execute_transform && !linestring.transform(srid_in, srid_out)) {
124  return false;
125  }
126  if (best_planar_srid_ptr) {
127  // A non-NULL pointer signifies a request to find the best planar srid
128  // to transform this WGS84 geometry to, based on geometry's centroid.
129  *best_planar_srid_ptr = linestring.getBestPlanarSRID();
130  if (!linestring.transform(4326, *best_planar_srid_ptr)) {
131  return false;
132  }
133  }
134  return linestring.getWkb(wkb);
135  }
136  std::vector<int32_t> meta1v(meta1, meta1 + meta1_size);
137  if (static_cast<SQLTypes>(type) == kPOLYGON) {
138  GeoPolygon poly(*cv, meta1v);
139  if (execute_transform && !poly.transform(srid_in, srid_out)) {
140  return false;
141  }
142  if (best_planar_srid_ptr) {
143  // A non-NULL pointer signifies a request to find the best planar srid
144  // to transform this WGS84 geometry to, based on geometry's centroid.
145  *best_planar_srid_ptr = poly.getBestPlanarSRID();
146  if (!poly.transform(4326, *best_planar_srid_ptr)) {
147  return false;
148  };
149  }
150  return poly.getWkb(wkb);
151  }
152  std::vector<int32_t> meta2v(meta2, meta2 + meta2_size);
153  if (static_cast<SQLTypes>(type) == kMULTIPOLYGON) {
154  // Recognize GEOMETRYCOLLECTION EMPTY encoding
155  // MULTIPOLYGON (((0 0,0.00000012345 0.0,0.0 0.00000012345,0 0)))
156  // Used to pass along EMPTY from ST_Intersection to ST_IsEmpty for example
157  if (meta1_size == 1 && meta2_size == 1) {
158  const std::vector<double> ecv = {0.0, 0.0, 0.00000012345, 0.0, 0.0, 0.00000012345};
159  if (*cv == ecv) {
160  GeoGeometryCollection empty("GEOMETRYCOLLECTION EMPTY");
161  return empty.getWkb(wkb);
162  }
163  }
164  GeoMultiPolygon mpoly(*cv, meta1v, meta2v);
165  if (execute_transform && !mpoly.transform(srid_in, srid_out)) {
166  return false;
167  }
168  if (best_planar_srid_ptr) {
169  // A non-NULL pointer signifies a request to find the best planar srid
170  // to transform this WGS84 geometry to, based on geometry's centroid.
171  *best_planar_srid_ptr = mpoly.getBestPlanarSRID();
172  if (!mpoly.transform(4326, *best_planar_srid_ptr)) {
173  return false;
174  };
175  }
176  return mpoly.getWkb(wkb);
177  }
178  return false;
179 }
180 
181 // Conversion form wkb to internal vector representation.
182 // Each vector components is malloced, caller is reponsible for freeing.
183 bool fromWkb(WKB& wkb,
184  int* result_type,
185  int8_t** result_coords,
186  int64_t* result_coords_size,
187  int32_t** result_meta1,
188  int64_t* result_meta1_size,
189  int32_t** result_meta2,
190  int64_t* result_meta2_size,
191  int32_t result_srid_in,
192  int32_t result_srid_out,
193  int32_t* best_planar_srid_ptr) {
195  if (!result->isEmpty()) {
196  if (best_planar_srid_ptr) {
197  // If original geometry has previously been projected to planar srid,
198  // need to transform back to WGS84
199  if (!result->transform(*best_planar_srid_ptr, 4326)) {
200  return false;
201  }
202  }
203  if (result_srid_in > 0 && result_srid_out > 0 and result_srid_in != result_srid_out) {
204  if (!result->transform(result_srid_in, result_srid_out)) {
205  return false;
206  }
207  }
208  }
209 
210  // Get the column values
211  std::vector<double> coords{};
212  std::vector<int32_t> ring_sizes{};
213  std::vector<int32_t> poly_rings{};
214  std::vector<double> bounds{};
215 
216  // Forcing MULTIPOLYGON result until we can handle any geo.
217  if (result->isEmpty()) {
218  // Generate a tiny polygon around POINT(0 0), make it a multipolygon
219  // MULTIPOLYGON (((0 0,0.00000012345 0.0,0.0 0.00000012345,0 0)))
220  // to simulate an empty result
221  coords = {0.0, 0.0, 0.00000012345, 0.0, 0.0, 0.00000012345};
222  ring_sizes.push_back(3);
223  poly_rings.push_back(1);
224  } else if (auto result_point = dynamic_cast<GeoPoint*>(result.get())) {
225  result_point->getColumns(coords);
226  // Generate a tiny polygon around the point, make it a multipolygon
227  coords.push_back(coords[0] + 0.0000001);
228  coords.push_back(coords[1]);
229  coords.push_back(coords[0]);
230  coords.push_back(coords[1] + 0.0000001);
231  ring_sizes.push_back(3);
232  poly_rings.push_back(ring_sizes.size());
233  } else if (auto result_poly = dynamic_cast<GeoPolygon*>(result.get())) {
234  result_poly->getColumns(coords, ring_sizes, bounds);
235  // Convert to a 1-polygon multipolygon
236  poly_rings.push_back(ring_sizes.size());
237  } else if (auto result_mpoly = dynamic_cast<GeoMultiPolygon*>(result.get())) {
238  result_mpoly->getColumns(coords, ring_sizes, poly_rings, bounds);
239  } else {
240  return false;
241  }
242 
243  // TODO: consider using a single buffer to hold all components,
244  // instead of allocating and registering each component buffer separately
245 
246  *result_type = static_cast<int>(kMULTIPOLYGON);
247 
248  *result_coords = nullptr;
249  int64_t size = coords.size() * sizeof(double);
250  if (size > 0) {
251  auto buf = checked_malloc(size);
252  std::memcpy(buf, coords.data(), size);
253  *result_coords = reinterpret_cast<int8_t*>(buf);
254  }
255  *result_coords_size = size;
256 
257  *result_meta1 = nullptr;
258  size = ring_sizes.size() * sizeof(int32_t);
259  if (size > 0) {
260  auto buf = checked_malloc(size);
261  std::memcpy(buf, ring_sizes.data(), size);
262  *result_meta1 = reinterpret_cast<int32_t*>(buf);
263  }
264  *result_meta1_size = ring_sizes.size();
265 
266  *result_meta2 = nullptr;
267  size = poly_rings.size() * sizeof(int32_t);
268  if (size > 0) {
269  auto buf = checked_malloc(size);
270  std::memcpy(buf, poly_rings.data(), size);
271  *result_meta2 = reinterpret_cast<int32_t*>(buf);
272  }
273  *result_meta2_size = poly_rings.size();
274 
275  return true;
276 }
277 
278 GEOSGeometry* postprocess(GEOSContextHandle_t context, GEOSGeometry* g) {
279  if (g && GEOSisEmpty_r(context, g) == 0) {
280  auto type = GEOSGeomTypeId_r(context, g);
281  if (type != -1) {
282  if (type != GEOS_POINT && type != GEOS_POLYGON && type != GEOS_MULTIPOLYGON) {
283  int quadsegs = 1; // coarse
284  double tiny_distance = 0.000000001;
285  auto ng = GEOSBuffer_r(context, g, tiny_distance, quadsegs);
286  GEOSGeom_destroy_r(context, g);
287  return ng;
288  }
289  }
290  }
291  return g;
292 }
293 #endif
294 
295 extern "C" RUNTIME_EXPORT bool Geos_Wkb_Wkb(
296  int op,
297  int arg1_type,
298  int8_t* arg1_coords,
299  int64_t arg1_coords_size,
300  int32_t* arg1_meta1,
301  int64_t arg1_meta1_size,
302  int32_t* arg1_meta2,
303  int64_t arg1_meta2_size,
304  // TODO: add meta3 args to support generic geometries
305  int32_t arg1_ic,
306  int32_t arg1_srid_in,
307  int32_t arg1_srid_out,
308  int arg2_type,
309  int8_t* arg2_coords,
310  int64_t arg2_coords_size,
311  int32_t* arg2_meta1,
312  int64_t arg2_meta1_size,
313  int32_t* arg2_meta2,
314  int64_t arg2_meta2_size,
315  // TODO: add meta3 args to support generic geometries
316  int32_t arg2_ic,
317  int32_t arg2_srid_in,
318  int32_t arg2_srid_out,
319  // TODO: add transform args
320  int* result_type,
321  int8_t** result_coords,
322  int64_t* result_coords_size,
323  int32_t** result_meta1,
324  int64_t* result_meta1_size,
325  int32_t** result_meta2,
326  int64_t* result_meta2_size,
327  // TODO: add support for output compression
328  int32_t result_srid_out) {
329 #ifndef __CUDACC__
330  // Get the result geo
331  // What if intersection is not a POLYGON? POINT? LINESTRING, MULTIPOLYGON?
332  // What if intersection is empty? Return null buffer pointers? Return false?
333  // What if geos fails?
334 
335  int32_t best_planar_srid;
336  int32_t* best_planar_srid_ptr = nullptr;
337  if (arg1_srid_out == 4326 &&
338  static_cast<GeoBase::GeoOp>(op) == GeoBase::GeoOp::kINTERSECTION) {
339  // Use the best (location-based) planar transform to project 4326 argument before
340  // running geos operation, back-project the result of the operation to 4326
341  // TODO: Turn on automatic planar transform for Intersection, other binary ops
342  // best_planar_srid_ptr = &best_planar_srid;
343  }
344  WKB wkb1{};
345  if (!toWkb(wkb1,
346  arg1_type,
347  arg1_coords,
348  arg1_coords_size,
349  arg1_meta1,
350  arg1_meta1_size,
351  arg1_meta2,
352  arg1_meta2_size,
353  arg1_ic,
354  arg1_srid_in,
355  arg1_srid_out,
356  best_planar_srid_ptr)) {
357  return false;
358  }
359  WKB wkb2{};
360  if (!toWkb(wkb2,
361  arg2_type,
362  arg2_coords,
363  arg2_coords_size,
364  arg2_meta1,
365  arg2_meta1_size,
366  arg2_meta2,
367  arg2_meta2_size,
368  arg2_ic,
369  arg2_srid_in,
370  arg2_srid_out,
371  best_planar_srid_ptr)) {
372  return false;
373  }
374  auto status = false;
375  auto context = create_context();
376  if (!context) {
377  return status;
378  }
379  auto* g1 = GEOSGeomFromWKB_buf_r(context, wkb1.data(), wkb1.size());
380  if (g1) {
381  auto* g2 = GEOSGeomFromWKB_buf_r(context, wkb2.data(), wkb2.size());
382  if (g2) {
383  GEOSGeometry* g = nullptr;
384  if (static_cast<GeoBase::GeoOp>(op) == GeoBase::GeoOp::kINTERSECTION) {
385  g = GEOSIntersection_r(context, g1, g2);
386  } else if (static_cast<GeoBase::GeoOp>(op) == GeoBase::GeoOp::kDIFFERENCE) {
387  g = GEOSDifference_r(context, g1, g2);
388  } else if (static_cast<GeoBase::GeoOp>(op) == GeoBase::GeoOp::kUNION) {
389  g = GEOSUnion_r(context, g1, g2);
390  }
391  g = postprocess(context, g);
392  if (g) {
393  size_t wkb_size = 0ULL;
394  auto wkb_buf = GEOSGeomToWKB_buf_r(context, g, &wkb_size);
395  if (wkb_buf && wkb_size > 0ULL) {
396  WKB wkb(wkb_buf, wkb_buf + wkb_size);
397  free(wkb_buf);
398  status = fromWkb(wkb,
399  result_type,
400  result_coords,
401  result_coords_size,
402  result_meta1,
403  result_meta1_size,
404  result_meta2,
405  result_meta2_size,
406  /* result_srid_in = */ arg1_srid_out,
407  result_srid_out,
408  best_planar_srid_ptr);
409  }
410  GEOSGeom_destroy_r(context, g);
411  }
412  GEOSGeom_destroy_r(context, g2);
413  }
414  GEOSGeom_destroy_r(context, g1);
415  }
416  destroy_context(context);
417  return status;
418 #else
419  return false;
420 #endif
421 }
422 
423 extern "C" RUNTIME_EXPORT bool Geos_Wkb_Wkb_Predicate(
424  int op,
425  int arg1_type,
426  int8_t* arg1_coords,
427  int64_t arg1_coords_size,
428  int32_t* arg1_meta1,
429  int64_t arg1_meta1_size,
430  int32_t* arg1_meta2,
431  int64_t arg1_meta2_size,
432  // TODO: add meta3 args to support generic geometries
433  int32_t arg1_ic,
434  int32_t arg1_srid_in,
435  int32_t arg1_srid_out,
436  int arg2_type,
437  int8_t* arg2_coords,
438  int64_t arg2_coords_size,
439  int32_t* arg2_meta1,
440  int64_t arg2_meta1_size,
441  int32_t* arg2_meta2,
442  int64_t arg2_meta2_size,
443  // TODO: add meta3 args to support generic geometries
444  int32_t arg2_ic,
445  int32_t arg2_srid_in,
446  int32_t arg2_srid_out,
447  bool* result) {
448 #ifndef __CUDACC__
449  WKB wkb1{};
450  if (!toWkb(wkb1,
451  arg1_type,
452  arg1_coords,
453  arg1_coords_size,
454  arg1_meta1,
455  arg1_meta1_size,
456  arg1_meta2,
457  arg1_meta2_size,
458  arg1_ic,
459  arg1_srid_in,
460  arg1_srid_out,
461  nullptr)) {
462  return false;
463  }
464  WKB wkb2{};
465  if (!toWkb(wkb2,
466  arg2_type,
467  arg2_coords,
468  arg2_coords_size,
469  arg2_meta1,
470  arg2_meta1_size,
471  arg2_meta2,
472  arg2_meta2_size,
473  arg2_ic,
474  arg2_srid_in,
475  arg2_srid_out,
476  nullptr)) {
477  return false;
478  }
479  auto status = false;
480  auto context = create_context();
481  if (!context) {
482  return status;
483  }
484  auto* g1 = GEOSGeomFromWKB_buf_r(context, wkb1.data(), wkb1.size());
485  if (g1) {
486  auto* g2 = GEOSGeomFromWKB_buf_r(context, wkb2.data(), wkb2.size());
487  if (g2) {
488  if (static_cast<GeoBase::GeoOp>(op) == GeoBase::GeoOp::kEQUALS) {
489  if (arg1_ic != arg2_ic &&
490  (arg1_ic == COMPRESSION_GEOINT32 || arg2_ic == COMPRESSION_GEOINT32)) {
491  *result = GEOSEqualsExact_r(context, g1, g2, TOLERANCE_GEOINT32);
492  } else {
493  *result = GEOSEquals_r(context, g1, g2);
494  }
495  status = true;
496  }
497  GEOSGeom_destroy_r(context, g2);
498  }
499  GEOSGeom_destroy_r(context, g1);
500  }
501  destroy_context(context);
502  return status;
503 #else
504  return false;
505 #endif
506 }
507 
508 extern "C" RUNTIME_EXPORT bool Geos_Wkb_double(
509  int op,
510  int arg1_type,
511  int8_t* arg1_coords,
512  int64_t arg1_coords_size,
513  int32_t* arg1_meta1,
514  int64_t arg1_meta1_size,
515  int32_t* arg1_meta2,
516  int64_t arg1_meta2_size,
517  // TODO: add meta3 args to support generic geometries
518  int32_t arg1_ic,
519  int32_t arg1_srid_in,
520  int32_t arg1_srid_out,
521  double arg2,
522  // TODO: add transform args
523  int* result_type,
524  int8_t** result_coords,
525  int64_t* result_coords_size,
526  int32_t** result_meta1,
527  int64_t* result_meta1_size,
528  int32_t** result_meta2,
529  int64_t* result_meta2_size,
530  // TODO: add support for output compression
531  int32_t result_srid_out) {
532 #ifndef __CUDACC__
533  int32_t best_planar_srid;
534  int32_t* best_planar_srid_ptr = nullptr;
535  if (arg1_srid_out == 4326 &&
536  static_cast<GeoBase::GeoOp>(op) == GeoBase::GeoOp::kBUFFER && arg2 != 0.0) {
537  // Use the best (location-based) planar transform to project 4326 argument before
538  // running geos operation, back-project the result of the operation to 4326
539  best_planar_srid_ptr = &best_planar_srid;
540  }
541  WKB wkb1{};
542  if (!toWkb(wkb1,
543  arg1_type,
544  arg1_coords,
545  arg1_coords_size,
546  arg1_meta1,
547  arg1_meta1_size,
548  arg1_meta2,
549  arg1_meta2_size,
550  arg1_ic,
551  arg1_srid_in,
552  arg1_srid_out,
553  best_planar_srid_ptr)) {
554  return false;
555  }
556 
557  auto status = false;
558  auto context = create_context();
559  if (!context) {
560  return status;
561  }
562  auto* g1 = GEOSGeomFromWKB_buf_r(context, wkb1.data(), wkb1.size());
563  if (g1) {
564  GEOSGeometry* g = nullptr;
565  if (static_cast<GeoBase::GeoOp>(op) == GeoBase::GeoOp::kBUFFER) {
566  if (arg2 != 0.0) {
567  int quadsegs = 8; // default
568  g = GEOSBuffer_r(context, g1, arg2, quadsegs);
569  } else {
570  g = GEOSGeom_clone_r(context, g1);
571  }
572  }
573  g = postprocess(context, g);
574  if (g) {
575  size_t wkb_size = 0ULL;
576  auto wkb_buf = GEOSGeomToWKB_buf_r(context, g, &wkb_size);
577  if (wkb_buf && wkb_size > 0ULL) {
578  WKB wkb(wkb_buf, wkb_buf + wkb_size);
579  free(wkb_buf);
580  // Back-project the result from planar to 4326 if necessary
581  status = fromWkb(wkb,
582  result_type,
583  result_coords,
584  result_coords_size,
585  result_meta1,
586  result_meta1_size,
587  result_meta2,
588  result_meta2_size,
589  /* result_srid_in = */ arg1_srid_out,
590  result_srid_out,
591  best_planar_srid_ptr);
592  }
593  GEOSGeom_destroy_r(context, g);
594  }
595  GEOSGeom_destroy_r(context, g1);
596  }
597  destroy_context(context);
598  return status;
599 #else
600  return false;
601 #endif
602 }
603 
604 extern "C" RUNTIME_EXPORT bool Geos_Wkb(
605  int op,
606  int arg_type,
607  int8_t* arg_coords,
608  int64_t arg_coords_size,
609  int32_t* arg_meta1,
610  int64_t arg_meta1_size,
611  int32_t* arg_meta2,
612  int64_t arg_meta2_size,
613  // TODO: add meta3 args to support generic geometries
614  int32_t arg_ic,
615  int32_t arg_srid_in,
616  int32_t arg_srid_out,
617  bool* result) {
618 #ifndef __CUDACC__
619  WKB wkb1{};
620  if (!result || !toWkb(wkb1,
621  arg_type,
622  arg_coords,
623  arg_coords_size,
624  arg_meta1,
625  arg_meta1_size,
626  arg_meta2,
627  arg_meta2_size,
628  arg_ic,
629  arg_srid_in,
630  arg_srid_out,
631  nullptr)) {
632  return false;
633  }
634 
635  auto status = false;
636  auto context = create_context();
637  if (!context) {
638  return status;
639  }
640  auto* g1 = GEOSGeomFromWKB_buf_r(context, wkb1.data(), wkb1.size());
641  if (g1) {
642  if (static_cast<GeoBase::GeoOp>(op) == GeoBase::GeoOp::kISEMPTY) {
643  *result = GEOSisEmpty_r(context, g1);
644  status = true;
645  } else if (static_cast<GeoBase::GeoOp>(op) == GeoBase::GeoOp::kISVALID) {
646  *result = GEOSisValid_r(context, g1);
647  status = true;
648  }
649  GEOSGeom_destroy_r(context, g1);
650  }
651  destroy_context(context);
652  return status;
653 #else
654  return false;
655 #endif
656 }
657 
658 #endif
static std::unique_ptr< GeoBase > createGeoType(const std::string &wkt_or_wkb_hex)
Definition: Types.cpp:919
#define LOG(tag)
Definition: Logger.h:216
RUNTIME_EXPORT bool Geos_Wkb_double(int op, int arg1_type, int8_t *arg1_coords, int64_t arg1_coords_size, int32_t *arg1_meta1, int64_t arg1_meta1_size, int32_t *arg1_meta2, int64_t arg1_meta2_size, int32_t arg1_ic, int32_t arg1_srid_in, int32_t arg1_srid_out, double arg2, int *result_type, int8_t **result_coords, int64_t *result_coords_size, int32_t **result_meta1, int64_t *result_meta1_size, int32_t **result_meta2, int64_t *result_meta2_size, int32_t result_srid_out)
#define TOLERANCE_GEOINT32
void * checked_malloc(const size_t size)
Definition: checked_alloc.h:45
RUNTIME_EXPORT bool Geos_Wkb_Wkb(int op, int arg1_type, int8_t *arg1_coords, int64_t arg1_coords_size, int32_t *arg1_meta1, int64_t arg1_meta1_size, int32_t *arg1_meta2, int64_t arg1_meta2_size, int32_t arg1_ic, int32_t arg1_srid_in, int32_t arg1_srid_out, int arg2_type, int8_t *arg2_coords, int64_t arg2_coords_size, int32_t *arg2_meta1, int64_t arg2_meta1_size, int32_t *arg2_meta2, int64_t arg2_meta2_size, int32_t arg2_ic, int32_t arg2_srid_in, int32_t arg2_srid_out, int *result_type, int8_t **result_coords, int64_t *result_coords_size, int32_t **result_meta1, int64_t *result_meta1_size, int32_t **result_meta2, int64_t *result_meta2_size, int32_t result_srid_out)
#define RUNTIME_EXPORT
std::shared_ptr< std::vector< double > > decompress_coords< double, int32_t >(const int32_t &ic, const int8_t *coords, const size_t coords_sz)
RUNTIME_EXPORT bool Geos_Wkb(int op, int arg_type, int8_t *arg_coords, int64_t arg_coords_size, int32_t *arg_meta1, int64_t arg_meta1_size, int32_t *arg_meta2, int64_t arg_meta2_size, int32_t arg_ic, int32_t arg_srid_in, int32_t arg_srid_out, bool *result)
#define CHECK(condition)
Definition: Logger.h:222
RUNTIME_EXPORT bool Geos_Wkb_Wkb_Predicate(int op, int arg1_type, int8_t *arg1_coords, int64_t arg1_coords_size, int32_t *arg1_meta1, int64_t arg1_meta1_size, int32_t *arg1_meta2, int64_t arg1_meta2_size, int32_t arg1_ic, int32_t arg1_srid_in, int32_t arg1_srid_out, int arg2_type, int8_t *arg2_coords, int64_t arg2_coords_size, int32_t *arg2_meta1, int64_t arg2_meta1_size, int32_t *arg2_meta2, int64_t arg2_meta2_size, int32_t arg2_ic, int32_t arg2_srid_in, int32_t arg2_srid_out, bool *result)
#define COMPRESSION_GEOINT32