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