OmniSciDB  eb3a3d0a03
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Types.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 MapD Technologies, 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 #include "Geospatial/Types.h"
18 
19 #include <limits>
20 #include <mutex>
21 
22 #include <gdal.h>
23 #include <ogr_geometry.h>
24 #include <ogrsf_frmts.h>
25 
26 #include "Geospatial/GDAL.h"
27 #include "Logger/Logger.h"
28 #include "Shared/sqltypes.h"
29 
39 namespace {
40 constexpr auto DOUBLE_MAX = std::numeric_limits<double>::max();
41 constexpr auto DOUBLE_MIN = std::numeric_limits<double>::lowest();
42 
43 struct Coords {
44  double x;
45  double y;
46  Coords(double x, double y) : x(x), y(y) {}
47 };
48 
49 struct BoundingBox {
52  BoundingBox() : min(DOUBLE_MAX, DOUBLE_MAX), max(DOUBLE_MIN, DOUBLE_MIN) {}
53 
54  void update(double x, double y) {
55  if (x < min.x) {
56  min.x = x;
57  }
58  if (y < min.y) {
59  min.y = y;
60  }
61  if (x > max.x) {
62  max.x = x;
63  }
64  if (y > max.y) {
65  max.y = y;
66  }
67  }
68 };
69 
70 int process_poly_ring(OGRLinearRing* ring,
71  std::vector<double>& coords,
72  BoundingBox* bbox) {
73  double last_x = DOUBLE_MAX, last_y = DOUBLE_MAX;
74  size_t first_index = coords.size();
75  int num_points_added = 0;
76  int num_points_in_ring = ring->getNumPoints();
77  if (num_points_in_ring < 3) {
79  "PolyRing",
80  "All poly rings must have more than 3 points. Found ring with " +
81  std::to_string(num_points_in_ring) + " points.");
82  }
83  for (auto i = 0; i < num_points_in_ring; i++) {
84  OGRPoint point;
85  ring->getPoint(i, &point);
86  last_x = point.getX();
87  last_y = point.getY();
88  coords.push_back(last_x);
89  coords.push_back(last_y);
90  if (bbox) {
91  bbox->update(last_x, last_y);
92  }
93  num_points_added++;
94  }
95  // Store all rings as open rings (implicitly assumes all rings are closed)
96  if ((coords[first_index] == last_x) && (coords[first_index + 1] == last_y)) {
97  coords.pop_back();
98  coords.pop_back();
99  num_points_added--;
100  if (num_points_added < 3) {
102  "PolyRing",
103  "All exterior rings must have more than 3 points. Found ring with " +
104  std::to_string(num_points_added) + " points.");
105  }
106  }
107  return num_points_added;
108 }
109 
110 } // namespace
111 
112 namespace Geospatial {
113 
115 std::map<std::tuple<int32_t, int32_t>, std::shared_ptr<OGRCoordinateTransformation>>
117 
118 std::string GeoTypesError::OGRErrorToStr(const int ogr_err) {
119  switch (ogr_err) {
120  case OGRERR_NOT_ENOUGH_DATA:
121  return std::string("not enough input data");
122  case OGRERR_NOT_ENOUGH_MEMORY:
123  return std::string("not enough memory");
124  case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
125  return std::string("unsupported geometry type");
126  case OGRERR_UNSUPPORTED_OPERATION:
127  return std::string("unsupported operation");
128  case OGRERR_CORRUPT_DATA:
129  return std::string("corrupt input data");
130  case OGRERR_FAILURE:
131  return std::string("ogr failure");
132  case OGRERR_UNSUPPORTED_SRS:
133  return std::string("unsupported spatial reference system");
134  case OGRERR_INVALID_HANDLE:
135  return std::string("invalid file handle");
136 #if (GDAL_VERSION_MAJOR > 1)
137  case OGRERR_NON_EXISTING_FEATURE:
138  return std::string("feature does not exist in input geometry");
139 #endif
140  default:
141  return std::string("Unknown OGOR error encountered: ") + std::to_string(ogr_err);
142  }
143 }
144 
146  // Note: Removing the geometry object that was pulled from an OGRFeature results in a
147  // segfault. If we are wrapping around a pre-existing OGRGeometry object, we let the
148  // caller manage the memory.
149  if (geom_ && owns_geom_obj_) {
150  OGRGeometryFactory::destroyGeometry(geom_);
151  }
152 }
153 
154 OGRErr GeoBase::createFromWktString(const std::string& wkt, OGRGeometry** geom) {
155 #if (GDAL_VERSION_MAJOR > 2) || (GDAL_VERSION_MAJOR == 2 && GDAL_VERSION_MINOR >= 3)
156  OGRErr ogr_status = OGRGeometryFactory::createFromWkt(wkt.c_str(), nullptr, geom);
157 #else
158  auto data = (char*)wkt.c_str();
159  OGRErr ogr_status = OGRGeometryFactory::createFromWkt(&data, NULL, geom);
160 #endif
161  return ogr_status;
162 }
163 
164 std::string GeoBase::getWktString() const {
165  char* wkt = nullptr;
166  geom_->exportToWkt(&wkt);
167  CHECK(wkt);
168  std::string wkt_str(wkt);
169  CPLFree(wkt);
170  return wkt_str;
171 }
172 
173 OGRErr GeoBase::createFromWkb(const std::vector<uint8_t>& wkb, OGRGeometry** geom) {
174 #if (GDAL_VERSION_MAJOR > 2) || (GDAL_VERSION_MAJOR == 2 && GDAL_VERSION_MINOR >= 3)
175  OGRErr ogr_status =
176  OGRGeometryFactory::createFromWkb(wkb.data(), nullptr, geom, wkb.size());
177  return ogr_status;
178 #else
179  CHECK(false);
180 #endif
181 }
182 
183 // GeoBase could also generate GEOS geometries through geom_->exportToGEOS(),
184 // conversion to WKB and subsequent load of WKB into GEOS could be eliminated.
185 
186 bool GeoBase::getWkb(std::vector<uint8_t>& wkb) const {
187  auto size = geom_->WkbSize();
188  if (size > 0) {
189  wkb.resize(size);
190  geom_->exportToWkb(wkbNDR, wkb.data());
191  return true;
192  }
193  return false;
194 }
195 
196 bool GeoBase::isEmpty() const {
197  return geom_ && geom_->IsEmpty();
198 }
199 
200 bool GeoBase::operator==(const GeoBase& other) const {
201  if (!this->geom_ || !other.geom_) {
202  return false;
203  }
204  return this->geom_->Equals(other.geom_);
205 }
206 
208 #define SRID_WORLD_MERCATOR 999000
209 
210 #define SRID_NORTH_UTM_START 999001
211 
212 #define SRID_NORTH_UTM_END 999060
213 
214 #define SRID_NORTH_LAMBERT 999061
215 
216 #define SRID_SOUTH_UTM_START 999101
217 
218 #define SRID_SOUTH_UTM_END 999160
219 
220 #define SRID_SOUTH_LAMBERT 999161
221 
222 #define SRID_LAEA_START 999163
223 
224 #define SRID_LAEA_END 999283
225 
226 int32_t GeoBase::getBestPlanarSRID() const {
227  if (!this->geom_) {
228  return 0;
229  }
230  double cx, cy, xwidth, ywidth;
231  OGREnvelope envelope;
232  geom_->getEnvelope(&envelope);
233  // Can't use GDAL's Centroid geom_->Centroid(OGRPoint*): requires GEOS
234  // Use center of the bounding box for now.
235  // TODO: hook up our own Centroid implementation
236  cx = (envelope.MaxX + envelope.MinX) / 2.0;
237  cy = (envelope.MaxY + envelope.MinY) / 2.0;
238  xwidth = envelope.MaxX - envelope.MinX;
239  ywidth = envelope.MaxY - envelope.MinY;
240 
241  // Arctic coords: Lambert Azimuthal Equal Area North
242  if (cy > 70.0 && ywidth < 45.0) {
243  return SRID_NORTH_LAMBERT;
244  }
245  // Antarctic coords: Lambert Azimuthal Equal Area South
246  if (cy < -70.0 && ywidth < 45.0) {
247  return SRID_SOUTH_LAMBERT;
248  }
249 
250  // Can geometry fit into a single UTM zone?
251  if (xwidth < 6.0) {
252  int zone = floor((cx + 180.0) / 6.0);
253  if (zone > 59) {
254  zone = 59;
255  }
256  // Below the equator: UTM South
257  // Above the equator: UTM North
258  if (cy < 0.0) {
259  return SRID_SOUTH_UTM_START + zone;
260  } else {
261  return SRID_NORTH_UTM_START + zone;
262  }
263  }
264 
265  // TODO: to be removed once we add custom LAEA zone transforms
266  // Can geometry still fit into 5 consecutive UTM zones?
267  // Then go for the mid-UTM zone, tolerating some limited distortion
268  // in the left and right corners. That's still better than Mercator.
269  if (xwidth < 30.0) {
270  int zone = floor((cx + 180.0) / 6.0);
271  if (zone > 59) {
272  zone = 59;
273  }
274  // Below the equator: UTM South
275  // Above the equator: UTM North
276  if (cy < 0.0) {
277  return SRID_SOUTH_UTM_START + zone;
278  } else {
279  return SRID_NORTH_UTM_START + zone;
280  }
281  }
282 
283  // Can geometry fit into a custom LAEA area 30 degrees high? Allow some overlap.
284  if (ywidth < 25.0) {
285  int xzone = -1;
286  int yzone = 3 + floor(cy / 30.0); // range of 0-5
287  if ((yzone == 2 || yzone == 3) && xwidth < 30.0) {
288  // Equatorial band, 12 zones, 30 degrees wide
289  xzone = 6 + floor(cx / 30.0);
290  } else if ((yzone == 1 || yzone == 4) && xwidth < 45.0) {
291  // Temperate band, 8 zones, 45 degrees wide
292  xzone = 4 + floor(cx / 45.0);
293  } else if ((yzone == 0 || yzone == 5) && xwidth < 90.0) {
294  // Arctic band, 4 zones, 90 degrees wide
295  xzone = 2 + floor(cx / 90.0);
296  }
297  // Found an appropriate xzone to fit in?
298  if (xzone != -1) {
299  return SRID_LAEA_START + 20 * yzone + xzone;
300  }
301  }
302 
303  // Fall-back to Mercator
304  return SRID_WORLD_MERCATOR;
305 }
306 
307 std::shared_ptr<OGRCoordinateTransformation> GeoBase::getTransformation(int32_t srid0,
308  int32_t srid1) {
309  std::lock_guard<std::mutex> guard(transformation_map_mutex_);
310  std::tuple<int32_t, int32_t> key{srid0, srid1};
311  auto it = transformation_map_.find(key);
312  if (it != transformation_map_.end()) {
313  return it->second;
314  }
315  auto setSpatialReference = [&](OGRSpatialReference* sr, int32_t srid) -> bool {
316  OGRErr status = OGRERR_NONE;
317  if (srid == 4326) {
318  status = sr->importFromEPSG(4326);
319  } else if (srid == SRID_NORTH_LAMBERT) {
320  // +proj=laea +lat_0=90 +lon_0=-40 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m
321  // +no_defs
322  status = sr->importFromEPSG(3574);
323  } else if (srid == SRID_SOUTH_LAMBERT) {
324  // +proj=laea +lat_0=-90 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m
325  // +no_defs
326  status = sr->importFromEPSG(3409);
327  } else if (SRID_SOUTH_UTM_START <= srid && srid <= SRID_SOUTH_UTM_END) {
328  // +proj=utm +zone=%d +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs
329  int32_t zone = srid - SRID_SOUTH_UTM_START;
330  status = sr->importFromEPSG(32701 + zone);
331  } else if (SRID_NORTH_UTM_START <= srid && srid <= SRID_NORTH_UTM_END) {
332  // +proj=utm +zone=%d +ellps=WGS84 +datum=WGS84 +units=m +no_defs"
333  int32_t zone = srid - SRID_NORTH_UTM_START;
334  status = sr->importFromEPSG(32601 + zone);
335  } else if (SRID_LAEA_START <= srid && srid <= SRID_LAEA_END) {
336  // TODO: add support and coordinate operations for custom Lambert zones,
337  // need to calculate lat/lon for the zone, SetCoordinateOperation in options.
338  // +proj=laea +ellps=WGS84 +datum=WGS84 +lat_0=%g +lon_0=%g +units=m +no_defs
339  // Go with Mercator for now
340  status = sr->importFromEPSG(3395);
341  } else if (srid == SRID_WORLD_MERCATOR) {
342  // +proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m
343  // +no_defs
344  status = sr->importFromEPSG(3395);
345  } else if (srid > 0) {
346  // Attempt to import from srid directly
347  status = sr->importFromEPSG(srid);
348  } else {
349  return false;
350  }
351 #if GDAL_VERSION_MAJOR >= 3
352  // GDAL 3.x (really Proj.4 6.x) now enforces lat, lon order
353  // this results in X and Y being transposed for angle-based
354  // coordinate systems. This restores the previous behavior.
355  if (status == OGRERR_NONE) {
356  sr->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
357  }
358 #endif
359  return (status == OGRERR_NONE);
360  };
361 
362  // lazy init GDAL
363  GDAL::init();
364 
365  OGRSpatialReference sr0;
366  if (!setSpatialReference(&sr0, srid0)) {
367  return nullptr;
368  }
369  OGRSpatialReference sr1;
370  if (!setSpatialReference(&sr1, srid1)) {
371  return nullptr;
372  }
373  // GDAL 3 allows specification of advanced transformations in
374  // OGRCoordinateTransformationOptions, including multi-step pipelines.
375  // GDAL 3 would be required to handle Lambert zone proj4 strings.
376  // Using a simple transform for now.
377  std::shared_ptr<OGRCoordinateTransformation> new_transformation;
378  new_transformation.reset(OGRCreateCoordinateTransformation(&sr0, &sr1));
379  transformation_map_[key] = new_transformation;
380  return new_transformation;
381 }
382 
383 bool GeoBase::transform(int32_t srid0, int32_t srid1) {
384  auto coordinate_transformation = getTransformation(srid0, srid1);
385  if (!coordinate_transformation) {
386  return false;
387  }
388  auto ogr_status = geom_->transform(coordinate_transformation.get());
389  return (ogr_status == OGRERR_NONE);
390 }
391 
393  auto srid1 = ti.get_output_srid();
394  if (srid1 == 4326) {
395  auto srid0 = ti.get_input_srid();
396  if (srid0 > 0 && srid0 != 4326) {
397  if (!transform(srid0, srid1)) {
398  return false;
399  }
400  }
401  }
402  return true;
403 }
404 
405 // Run a specific geo operation on this and other geometries
406 std::unique_ptr<GeoBase> GeoBase::run(GeoBase::GeoOp op, const GeoBase& other) const {
407  OGRGeometry* result = nullptr;
408  // Invalid geometries are derailing geo op performance,
409  // Checking validity before running an operation doesn't have lesser penalty.
410  // DOES NOT HELP: if (geom_->IsValid() && other.geom_->IsValid()) {
411  switch (op) {
413  result = geom_->Intersection(other.geom_);
414  break;
416  result = geom_->Difference(other.geom_);
417  break;
419  result = geom_->Union(other.geom_);
420  break;
421  default:
422  break;
423  }
424  // TODO: Need to handle empty/non-POLYGON result
425  if (!result || result->IsEmpty() ||
426  !(result->getGeometryType() == wkbPolygon ||
427  result->getGeometryType() == wkbMultiPolygon)) {
428  // throw GeoTypesError(std::string(OGRGeometryTypeToName(geom_->getGeometryType())),
429  // "Currenly don't support invalid or empty result");
430  // return GeoTypesFactory::createGeoType("POLYGON EMPTY");
431  // Not supporting EMPTY polygons, return a dot polygon
433  "MULTIPOLYGON(((0 0,0.0000001 0,0 0.0000001)))");
434  }
435  return GeoTypesFactory::createGeoType(result);
436 }
437 
438 // Run a specific geo operation on this and other geometries
439 std::unique_ptr<GeoBase> GeoBase::optimized_run(GeoBase::GeoOp op,
440  const GeoBase& other) const {
441  OGRGeometry* result = nullptr;
442  // Loop through polys combinations, check validity, do intersections
443  // where needed, return a union of all intersections
444  auto gc1 = geom_->toGeometryCollection();
445  auto gc2 = other.geom_->toGeometryCollection();
446  if (!gc1 || !gc2 || gc1->IsEmpty() || gc2->IsEmpty()) {
447  return nullptr;
448  }
449  for (int i1 = 0; i1 < gc1->getNumGeometries(); i1++) {
450  auto g1 = gc1->getGeometryRef(i1);
451  // Validity check is very slow
452  if (!g1 || g1->IsEmpty() /*|| !g1->IsValid()*/) {
453  continue;
454  }
455  OGREnvelope ge1;
456  g1->getEnvelope(&ge1);
457  for (int i2 = 0; i2 < gc2->getNumGeometries(); i2++) {
458  auto g2 = gc2->getGeometryRef(i2);
459  // Validity check is very slow
460  if (!g2 || g2->IsEmpty() /*|| !g2->IsValid()*/) {
461  continue;
462  }
463  // Check for bounding box overlap
464  OGREnvelope ge2;
465  g2->getEnvelope(&ge2);
466  if (!ge1.Intersects(ge2)) {
467  continue;
468  }
469  // Do intersection
470  auto intermediate_result = g1->Intersection(g2);
471  if (!intermediate_result || intermediate_result->IsEmpty()) {
472  continue;
473  }
474  if (!result) {
475  result = intermediate_result;
476  } else {
477  result = result->Union(intermediate_result);
478  }
479  }
480  }
481 
482  // TODO: Need to handle empty/non-POLYGON result
483  if (!result || result->IsEmpty() ||
484  !(result->getGeometryType() == wkbPolygon ||
485  result->getGeometryType() == wkbMultiPolygon)) {
486  // throw GeoTypesError(std::string(OGRGeometryTypeToName(geom_->getGeometryType())),
487  // "Currenly don't support invalid or empty result");
488  // return GeoTypesFactory::createGeoType("POLYGON EMPTY");
489  // Not supporting EMPTY polygons, return a dot polygon
491  "MULTIPOLYGON(((0 0,0.0000001 0,0 0.0000001)))");
492  }
493  return GeoTypesFactory::createGeoType(result);
494 }
495 
496 // Run a specific geo operation on this geometry and a double param
497 std::unique_ptr<GeoBase> GeoBase::run(GeoBase::GeoOp op, double param) const {
498  OGRGeometry* result = nullptr;
499  switch (op) {
501  result = geom_->Buffer(param);
502  break;
503  default:
504  break;
505  }
506  // TODO: Need to handle empty/non-POLYGON result
507  if (!result || result->IsEmpty() ||
508  !(result->getGeometryType() == wkbPolygon ||
509  result->getGeometryType() == wkbMultiPolygon)) {
510  // throw GeoTypesError(std::string(OGRGeometryTypeToName(geom_->getGeometryType())),
511  // "Currenly don't support invalid or empty result");
512  // return GeoTypesFactory::createGeoType("POLYGON EMPTY");
513  // Not supporting EMPTY polygons, return a dot polygon
515  "MULTIPOLYGON(((0 0,0.0000001 0,0 0.0000001)))");
516  }
517  return GeoTypesFactory::createGeoType(result);
518 }
519 
520 // Run a specific predicate operation on this geometry
521 bool GeoBase::run(GeoBase::GeoOp op) const {
522  auto result = false;
523  switch (op) {
525  result = geom_->IsValid();
526  break;
528  result = isEmpty();
529  break;
530  default:
531  break;
532  }
533  return result;
534 }
535 
536 std::unique_ptr<GeoBase> GeoPoint::clone() const {
537  CHECK(geom_);
538  return std::unique_ptr<GeoBase>(new GeoPoint(geom_->clone(), true));
539 }
540 
541 GeoPoint::GeoPoint(const std::vector<double>& coords) {
542  if (coords.size() != 2) {
543  throw GeoTypesError("Point",
544  "Incorrect coord size of " + std::to_string(coords.size()) +
545  " supplied. Expected 2.");
546  }
547  geom_ = OGRGeometryFactory::createGeometry(OGRwkbGeometryType::wkbPoint);
548  OGRPoint* point = dynamic_cast<OGRPoint*>(geom_);
549  CHECK(point);
550  point->setX(coords[0]);
551  point->setY(coords[1]);
552 }
553 
554 GeoPoint::GeoPoint(const std::string& wkt) {
555  const auto err = GeoBase::createFromWktString(wkt, &geom_);
556  if (err != OGRERR_NONE) {
557  throw GeoTypesError("Point", err);
558  }
559  CHECK(geom_);
560  if (wkbFlatten(geom_->getGeometryType()) != OGRwkbGeometryType::wkbPoint) {
561  throw GeoTypesError("Point",
562  "Unexpected geometry type from WKT string: " +
563  std::string(OGRGeometryTypeToName(geom_->getGeometryType())));
564  }
565 }
566 
567 void GeoPoint::getColumns(std::vector<double>& coords) const {
568  const auto point_geom = dynamic_cast<OGRPoint*>(geom_);
569  CHECK(point_geom);
570 
571  if (point_geom->IsEmpty()) {
572  // until the run-time can handle empties
573  throw GeoTypesError("Point", "'EMPTY' not supported");
574  // we cannot yet handle NULL fixed-length array
575  // so we have to store sentinel values instead
576  coords.push_back(NULL_DOUBLE);
577  coords.push_back(NULL_DOUBLE);
578  return;
579  }
580 
581  coords.push_back(point_geom->getX());
582  coords.push_back(point_geom->getY());
583 }
584 
585 std::unique_ptr<GeoBase> GeoLineString::clone() const {
586  CHECK(geom_);
587  return std::unique_ptr<GeoBase>(new GeoLineString(geom_->clone(), true));
588 }
589 
590 GeoLineString::GeoLineString(const std::vector<double>& coords) {
591  geom_ = OGRGeometryFactory::createGeometry(OGRwkbGeometryType::wkbLineString);
592  OGRLineString* line = dynamic_cast<OGRLineString*>(geom_);
593  CHECK(line);
594  for (size_t i = 0; i < coords.size(); i += 2) {
595  line->addPoint(coords[i], coords[i + 1]);
596  }
597 }
598 
599 GeoLineString::GeoLineString(const std::string& wkt) {
600  const auto err = GeoBase::createFromWktString(wkt, &geom_);
601  if (err != OGRERR_NONE) {
602  throw GeoTypesError("LineString", err);
603  }
604  CHECK(geom_);
605  if (wkbFlatten(geom_->getGeometryType()) != OGRwkbGeometryType::wkbLineString) {
606  throw GeoTypesError("LineString",
607  "Unexpected geometry type from WKT string: " +
608  std::string(OGRGeometryTypeToName(geom_->getGeometryType())));
609  }
610 }
611 
612 void GeoLineString::getColumns(std::vector<double>& coords,
613  std::vector<double>& bounds) const {
614  auto linestring_geom = dynamic_cast<OGRLineString*>(geom_);
615  CHECK(linestring_geom);
616 
617  if (linestring_geom->IsEmpty()) {
618  // until the run-time can handle empties
619  throw GeoTypesError("LineString", "'EMPTY' not supported");
620  // return null bounds
621  bounds.push_back(NULL_DOUBLE);
622  bounds.push_back(NULL_DOUBLE);
623  bounds.push_back(NULL_DOUBLE);
624  bounds.push_back(NULL_DOUBLE);
625  return;
626  }
627 
628  BoundingBox bbox;
629  for (auto i = 0; i < linestring_geom->getNumPoints(); i++) {
630  OGRPoint point;
631  linestring_geom->getPoint(i, &point);
632  double x = point.getX();
633  double y = point.getY();
634  coords.push_back(x);
635  coords.push_back(y);
636  bbox.update(x, y);
637  }
638  bounds.push_back(bbox.min.x);
639  bounds.push_back(bbox.min.y);
640  bounds.push_back(bbox.max.x);
641  bounds.push_back(bbox.max.y);
642 }
643 
644 std::unique_ptr<GeoBase> GeoPolygon::clone() const {
645  CHECK(geom_);
646  return std::unique_ptr<GeoBase>(new GeoPolygon(geom_->clone(), true));
647 }
648 
649 GeoPolygon::GeoPolygon(const std::vector<double>& coords,
650  const std::vector<int32_t>& ring_sizes) {
651  geom_ = OGRGeometryFactory::createGeometry(OGRwkbGeometryType::wkbPolygon);
652  OGRPolygon* poly = dynamic_cast<OGRPolygon*>(geom_);
653  CHECK(poly);
654 
655  size_t coords_ctr = 0;
656  for (size_t r = 0; r < ring_sizes.size(); r++) {
657  OGRLinearRing ring;
658  const auto ring_sz = ring_sizes[r];
659  for (auto i = 0; i < 2 * ring_sz; i += 2) {
660  ring.addPoint(coords[coords_ctr + i], coords[coords_ctr + i + 1]);
661  }
662  ring.addPoint(coords[coords_ctr], coords[coords_ctr + 1]);
663  coords_ctr += 2 * ring_sz;
664  poly->addRing(&ring);
665  }
666 }
667 
668 GeoPolygon::GeoPolygon(const std::string& wkt) {
669  const auto err = GeoBase::createFromWktString(wkt, &geom_);
670  if (err != OGRERR_NONE) {
671  throw GeoTypesError("Polygon", err);
672  }
673  CHECK(geom_);
674  if (wkbFlatten(geom_->getGeometryType()) != OGRwkbGeometryType::wkbPolygon) {
675  throw GeoTypesError("Polygon",
676  "Unexpected geometry type from WKT string: " +
677  std::string(OGRGeometryTypeToName(geom_->getGeometryType())));
678  }
679 }
680 
681 void GeoPolygon::getColumns(std::vector<double>& coords,
682  std::vector<int32_t>& ring_sizes,
683  std::vector<double>& bounds) const {
684  const auto poly_geom = dynamic_cast<OGRPolygon*>(geom_);
685  CHECK(poly_geom);
686 
687  if (poly_geom->IsEmpty()) {
688  // until the run-time can handle empties
689  throw GeoTypesError("Polygon", "'EMPTY' not supported");
690  // return null bounds
691  bounds.push_back(NULL_DOUBLE);
692  bounds.push_back(NULL_DOUBLE);
693  bounds.push_back(NULL_DOUBLE);
694  bounds.push_back(NULL_DOUBLE);
695  return;
696  }
697 
698  BoundingBox bbox;
699  const auto exterior_ring = poly_geom->getExteriorRing();
700  CHECK(exterior_ring);
701  // All exterior rings are imported CCW
702  if (exterior_ring->isClockwise()) {
703  exterior_ring->reverseWindingOrder();
704  }
705  const auto num_points_added = process_poly_ring(exterior_ring, coords, &bbox);
706  ring_sizes.push_back(num_points_added);
707  for (auto r = 0; r < poly_geom->getNumInteriorRings(); r++) {
708  auto interior_ring = poly_geom->getInteriorRing(r);
709  CHECK(interior_ring);
710  // All interior rings are imported CW
711  if (!interior_ring->isClockwise()) {
712  interior_ring->reverseWindingOrder();
713  }
714  const auto num_points_added = process_poly_ring(interior_ring, coords, nullptr);
715  ring_sizes.push_back(num_points_added);
716  }
717  bounds.push_back(bbox.min.x);
718  bounds.push_back(bbox.min.y);
719  bounds.push_back(bbox.max.x);
720  bounds.push_back(bbox.max.y);
721 }
722 
724  const auto poly_geom = dynamic_cast<OGRPolygon*>(geom_);
725  CHECK(poly_geom);
726  return poly_geom->getNumInteriorRings();
727 }
728 
729 std::unique_ptr<GeoBase> GeoMultiPolygon::clone() const {
730  CHECK(geom_);
731  return std::unique_ptr<GeoBase>(new GeoMultiPolygon(geom_->clone(), true));
732 }
733 
734 GeoMultiPolygon::GeoMultiPolygon(const std::vector<double>& coords,
735  const std::vector<int32_t>& ring_sizes,
736  const std::vector<int32_t>& poly_rings) {
737  geom_ = OGRGeometryFactory::createGeometry(OGRwkbGeometryType::wkbMultiPolygon);
738  OGRMultiPolygon* multipoly = dynamic_cast<OGRMultiPolygon*>(geom_);
739  CHECK(multipoly);
740 
741  size_t ring_ctr = 0;
742  size_t coords_ctr = 0;
743  for (const auto& rings_in_poly : poly_rings) {
744  OGRPolygon poly;
745  for (auto r = 0; r < rings_in_poly; r++) {
746  OGRLinearRing ring;
747  const auto ring_sz = ring_sizes[ring_ctr];
748  for (auto i = 0; i < 2 * ring_sz; i += 2) {
749  ring.addPoint(coords[coords_ctr + i], coords[coords_ctr + i + 1]);
750  }
751  ring.addPoint(coords[coords_ctr], coords[coords_ctr + 1]);
752  coords_ctr += 2 * ring_sz;
753  poly.addRing(&ring);
754  ring_ctr++;
755  }
756  multipoly->addGeometry(&poly);
757  }
758 }
759 
760 GeoMultiPolygon::GeoMultiPolygon(const std::string& wkt) {
761  const auto err = GeoBase::createFromWktString(wkt, &geom_);
762  if (err != OGRERR_NONE) {
763  throw GeoTypesError("MultiPolygon", err);
764  }
765  CHECK(geom_);
766  if (wkbFlatten(geom_->getGeometryType()) != OGRwkbGeometryType::wkbMultiPolygon) {
767  throw GeoTypesError("MultiPolygon",
768  "Unexpected geometry type from WKT string: " +
769  std::string(OGRGeometryTypeToName(geom_->getGeometryType())));
770  }
771 }
772 
773 void GeoMultiPolygon::getColumns(std::vector<double>& coords,
774  std::vector<int32_t>& ring_sizes,
775  std::vector<int32_t>& poly_rings,
776  std::vector<double>& bounds) const {
777  const auto mpoly = dynamic_cast<OGRMultiPolygon*>(geom_);
778  CHECK(mpoly);
779 
780  if (mpoly->IsEmpty()) {
781  // until the run-time can handle empties
782  throw GeoTypesError("MultiPolygon", "'EMPTY' not supported");
783  // return null bounds
784  bounds.push_back(NULL_DOUBLE);
785  bounds.push_back(NULL_DOUBLE);
786  bounds.push_back(NULL_DOUBLE);
787  bounds.push_back(NULL_DOUBLE);
788  return;
789  }
790 
791  BoundingBox bbox;
792  for (auto p = 0; p < mpoly->getNumGeometries(); p++) {
793  const auto mpoly_geom = mpoly->getGeometryRef(p);
794  CHECK(mpoly_geom);
795  const auto poly_geom = dynamic_cast<OGRPolygon*>(mpoly_geom);
796  if (!poly_geom) {
797  throw GeoTypesError("MultiPolygon",
798  "Failed to read polygon geometry from multipolygon");
799  }
800  const auto exterior_ring = poly_geom->getExteriorRing();
801  CHECK(exterior_ring);
802  // All exterior rings are imported CCW
803  if (exterior_ring->isClockwise()) {
804  exterior_ring->reverseWindingOrder();
805  }
806  const auto num_points_added = process_poly_ring(exterior_ring, coords, &bbox);
807  ring_sizes.push_back(num_points_added);
808 
809  for (auto r = 0; r < poly_geom->getNumInteriorRings(); r++) {
810  auto interior_ring = poly_geom->getInteriorRing(r);
811  CHECK(interior_ring);
812  // All interior rings are imported CW
813  if (!interior_ring->isClockwise()) {
814  interior_ring->reverseWindingOrder();
815  }
816  const auto num_points_added = process_poly_ring(interior_ring, coords, nullptr);
817  ring_sizes.push_back(num_points_added);
818  }
819  poly_rings.push_back(poly_geom->getNumInteriorRings() + 1);
820  }
821  bounds.push_back(bbox.min.x);
822  bounds.push_back(bbox.min.y);
823  bounds.push_back(bbox.max.x);
824  bounds.push_back(bbox.max.y);
825 }
826 
827 std::unique_ptr<GeoBase> GeoGeometry::clone() const {
828  CHECK(geom_);
829  return std::unique_ptr<GeoBase>(new GeoGeometry(geom_->clone(), true));
830 }
831 
832 std::unique_ptr<GeoBase> GeoGeometryCollection::clone() const {
833  CHECK(geom_);
834  return std::unique_ptr<GeoBase>(new GeoGeometryCollection(geom_->clone(), true));
835 }
836 
838  const auto err = GeoBase::createFromWktString(wkt, &geom_);
839  if (err != OGRERR_NONE) {
840  throw GeoTypesError("GeometryCollection", err);
841  }
842  CHECK(geom_);
843  if (wkbFlatten(geom_->getGeometryType()) != OGRwkbGeometryType::wkbGeometryCollection) {
844  throw GeoTypesError("GeometryCollection",
845  "Unexpected geometry type from WKT string: " +
846  std::string(OGRGeometryTypeToName(geom_->getGeometryType())));
847  }
848 }
849 
850 namespace {
851 
853  uint8_t table_[128];
854  constexpr HexDigitToDecimalTable() : table_{} {
855  table_['1'] = 1;
856  table_['2'] = 2;
857  table_['3'] = 3;
858  table_['4'] = 4;
859  table_['5'] = 5;
860  table_['6'] = 6;
861  table_['7'] = 7;
862  table_['8'] = 8;
863  table_['9'] = 9;
864  table_['a'] = 10;
865  table_['A'] = 10;
866  table_['b'] = 11;
867  table_['B'] = 11;
868  table_['c'] = 12;
869  table_['C'] = 12;
870  table_['d'] = 13;
871  table_['D'] = 13;
872  table_['e'] = 14;
873  table_['E'] = 14;
874  table_['f'] = 15;
875  table_['F'] = 15;
876  }
877  constexpr uint8_t operator[](const char& hex_digit) const {
878  return (hex_digit < 0) ? 0 : table_[static_cast<int>(hex_digit)];
879  }
880 };
881 
883 
884 inline uint8_t hex_to_binary(const char& usb, const char& lsb) {
885  return (hex_digit_to_decimal_table[usb] << 4) | hex_digit_to_decimal_table[lsb];
886 }
887 
888 std::vector<uint8_t> hex_string_to_binary_vector(const std::string& wkb_hex) {
889  auto num_bytes = wkb_hex.size() >> 1;
890  std::vector<uint8_t> wkb(num_bytes);
891  auto* chars = wkb_hex.data();
892  auto* bytes = wkb.data();
893  for (size_t i = 0; i < num_bytes; i++) {
894  auto const& usb = *chars++;
895  auto const& lsb = *chars++;
896  *bytes++ = hex_to_binary(usb, lsb);
897  }
898  return wkb;
899 }
900 
901 } // namespace
902 
903 OGRGeometry* GeoTypesFactory::createOGRGeometry(const std::string& wkt_or_wkb_hex) {
904  OGRGeometry* geom = nullptr;
905  OGRErr err = OGRERR_NONE;
906  if (wkt_or_wkb_hex.empty()) {
907  err = OGRERR_NOT_ENOUGH_DATA;
908  } else if (wkt_or_wkb_hex[0] == '0') { // all WKB hex strings start with a 0
909  err = GeoBase::createFromWkb(hex_string_to_binary_vector(wkt_or_wkb_hex), &geom);
910  } else {
911  err = GeoBase::createFromWktString(wkt_or_wkb_hex, &geom);
912  }
913  if (err != OGRERR_NONE) {
914  throw GeoTypesError("GeoFactory", err);
915  }
916  return geom;
917 }
918 
919 std::unique_ptr<GeoBase> GeoTypesFactory::createGeoType(
920  const std::string& wkt_or_wkb_hex) {
922 }
923 
924 std::unique_ptr<GeoBase> GeoTypesFactory::createGeoType(const std::vector<uint8_t>& wkb) {
925  OGRGeometry* geom = nullptr;
926  const auto err = GeoBase::createFromWkb(wkb, &geom);
927  if (err != OGRERR_NONE) {
928  throw GeoTypesError("GeoFactory", err);
929  }
931 }
932 
933 std::unique_ptr<GeoBase> GeoTypesFactory::createGeoType(OGRGeometry* geom) {
934  return GeoTypesFactory::createGeoTypeImpl(geom, false);
935 }
936 
937 bool GeoTypesFactory::getGeoColumns(const std::string& wkt_or_wkb_hex,
938  SQLTypeInfo& ti,
939  std::vector<double>& coords,
940  std::vector<double>& bounds,
941  std::vector<int>& ring_sizes,
942  std::vector<int>& poly_rings,
943  const bool promote_poly_to_mpoly) {
944  try {
945  if (wkt_or_wkb_hex.empty() || wkt_or_wkb_hex == "NULL") {
947  ti, coords, bounds, ring_sizes, poly_rings, promote_poly_to_mpoly);
948  return true;
949  }
950 
951  const auto geospatial_base = GeoTypesFactory::createGeoType(wkt_or_wkb_hex);
952 
953  if (!geospatial_base || !geospatial_base->transform(ti)) {
954  return false;
955  }
956 
957  getGeoColumnsImpl(geospatial_base,
958  ti,
959  coords,
960  bounds,
961  ring_sizes,
962  poly_rings,
963  promote_poly_to_mpoly);
964 
965  } catch (const std::exception& e) {
966  LOG(ERROR) << "Geospatial Import Error: " << e.what();
967  return false;
968  }
969 
970  return true;
971 }
972 
973 bool GeoTypesFactory::getGeoColumns(const std::vector<uint8_t>& wkb,
974  SQLTypeInfo& ti,
975  std::vector<double>& coords,
976  std::vector<double>& bounds,
977  std::vector<int>& ring_sizes,
978  std::vector<int>& poly_rings,
979  const bool promote_poly_to_mpoly) {
980  try {
981  const auto geospatial_base = GeoTypesFactory::createGeoType(wkb);
982 
983  if (!geospatial_base || !geospatial_base->transform(ti)) {
984  return false;
985  }
986 
987  getGeoColumnsImpl(geospatial_base,
988  ti,
989  coords,
990  bounds,
991  ring_sizes,
992  poly_rings,
993  promote_poly_to_mpoly);
994 
995  } catch (const std::exception& e) {
996  LOG(ERROR) << "Geospatial Import Error: " << e.what();
997  return false;
998  }
999 
1000  return true;
1001 }
1002 
1003 bool GeoTypesFactory::getGeoColumns(OGRGeometry* geom,
1004  SQLTypeInfo& ti,
1005  std::vector<double>& coords,
1006  std::vector<double>& bounds,
1007  std::vector<int>& ring_sizes,
1008  std::vector<int>& poly_rings,
1009  const bool promote_poly_to_mpoly) {
1010  try {
1011  const auto geospatial_base = GeoTypesFactory::createGeoType(geom);
1012 
1013  if (!geospatial_base || !geospatial_base->transform(ti)) {
1014  return false;
1015  }
1016 
1017  getGeoColumnsImpl(geospatial_base,
1018  ti,
1019  coords,
1020  bounds,
1021  ring_sizes,
1022  poly_rings,
1023  promote_poly_to_mpoly);
1024 
1025  } catch (const std::exception& e) {
1026  LOG(ERROR) << "Geospatial Import Error: " << e.what();
1027  return false;
1028  }
1029 
1030  return true;
1031 }
1032 
1033 bool GeoTypesFactory::getGeoColumns(const std::vector<std::string>* wkt_or_wkb_hex_column,
1034  SQLTypeInfo& ti,
1035  std::vector<std::vector<double>>& coords_column,
1036  std::vector<std::vector<double>>& bounds_column,
1037  std::vector<std::vector<int>>& ring_sizes_column,
1038  std::vector<std::vector<int>>& poly_rings_column,
1039  const bool promote_poly_to_mpoly) {
1040  try {
1041  for (const auto& wkt_or_wkb_hex : *wkt_or_wkb_hex_column) {
1042  std::vector<double> coords;
1043  std::vector<double> bounds;
1044  std::vector<int> ring_sizes;
1045  std::vector<int> poly_rings;
1046 
1047  SQLTypeInfo row_ti{ti};
1048  getGeoColumns(wkt_or_wkb_hex,
1049  row_ti,
1050  coords,
1051  bounds,
1052  ring_sizes,
1053  poly_rings,
1054  promote_poly_to_mpoly);
1055 
1056  if (ti.get_type() != row_ti.get_type()) {
1057  throw GeoTypesError("GeoFactory", "Columnar: Geometry type mismatch");
1058  }
1059  coords_column.push_back(coords);
1060  bounds_column.push_back(bounds);
1061  ring_sizes_column.push_back(ring_sizes);
1062  poly_rings_column.push_back(poly_rings);
1063  }
1064 
1065  } catch (const std::exception& e) {
1066  LOG(ERROR) << "Geospatial column Import Error: " << e.what();
1067  return false;
1068  }
1069 
1070  return true;
1071 }
1072 
1073 std::unique_ptr<GeoBase> GeoTypesFactory::createGeoTypeImpl(OGRGeometry* geom,
1074  const bool owns_geom_obj) {
1075  switch (wkbFlatten(geom->getGeometryType())) {
1076  case wkbPoint:
1077  return std::unique_ptr<GeoPoint>(new GeoPoint(geom, owns_geom_obj));
1078  case wkbLineString:
1079  return std::unique_ptr<GeoLineString>(new GeoLineString(geom, owns_geom_obj));
1080  case wkbPolygon:
1081  return std::unique_ptr<GeoPolygon>(new GeoPolygon(geom, owns_geom_obj));
1082  case wkbMultiPolygon:
1083  return std::unique_ptr<GeoMultiPolygon>(new GeoMultiPolygon(geom, owns_geom_obj));
1084  case wkbGeometryCollection:
1085  return std::unique_ptr<GeoGeometryCollection>(
1086  new GeoGeometryCollection(geom, owns_geom_obj));
1087  default:
1088  throw GeoTypesError(
1089  "GeoTypesFactory",
1090  "Unrecognized geometry type: " + std::string(geom->getGeometryName()));
1091  }
1092 }
1093 
1094 void GeoTypesFactory::getGeoColumnsImpl(const std::unique_ptr<GeoBase>& geospatial_base,
1095  SQLTypeInfo& ti,
1096  std::vector<double>& coords,
1097  std::vector<double>& bounds,
1098  std::vector<int>& ring_sizes,
1099  std::vector<int>& poly_rings,
1100  const bool promote_poly_to_mpoly) {
1101  switch (geospatial_base->getType()) {
1102  case GeoBase::GeoType::kPOINT: {
1103  const auto geospatial_point = dynamic_cast<GeoPoint*>(geospatial_base.get());
1104  CHECK(geospatial_point);
1105  geospatial_point->getColumns(coords);
1106  ti.set_type(kPOINT);
1107  break;
1108  }
1110  const auto geospatial_linestring =
1111  dynamic_cast<GeoLineString*>(geospatial_base.get());
1112  CHECK(geospatial_linestring);
1113  geospatial_linestring->getColumns(coords, bounds);
1114  ti.set_type(kLINESTRING);
1115  break;
1116  }
1118  const auto geospatial_poly = dynamic_cast<GeoPolygon*>(geospatial_base.get());
1119  CHECK(geospatial_poly);
1120  geospatial_poly->getColumns(coords, ring_sizes, bounds);
1121  if (promote_poly_to_mpoly) {
1122  if (ring_sizes.size()) {
1123  CHECK_GT(coords.size(), 0u);
1124  poly_rings.push_back(1 + geospatial_poly->getNumInteriorRings());
1125  }
1126  }
1127  ti.set_type(kPOLYGON);
1128  break;
1129  }
1131  const auto geospatial_mpoly = dynamic_cast<GeoMultiPolygon*>(geospatial_base.get());
1132  CHECK(geospatial_mpoly);
1133  geospatial_mpoly->getColumns(coords, ring_sizes, poly_rings, bounds);
1134  ti.set_type(kMULTIPOLYGON);
1135  break;
1136  }
1139  default:
1140  throw std::runtime_error("Unrecognized geospatial type");
1141  }
1142 }
1143 
1145  std::vector<double>& coords,
1146  std::vector<double>& bounds,
1147  std::vector<int>& ring_sizes,
1148  std::vector<int>& poly_rings,
1149  const bool promote_poly_to_mpoly) {
1150  auto t = ti.get_type();
1151  switch (t) {
1152  case kPOINT: {
1153  // NULL fixlen coords array
1154  coords.push_back(NULL_ARRAY_DOUBLE);
1155  coords.push_back(NULL_DOUBLE);
1156  } break;
1157  case kLINESTRING:
1158  case kPOLYGON:
1159  case kMULTIPOLYGON: {
1160  // Leaving coords array empty
1161  // NULL fixlen bounds array
1162  bounds.push_back(NULL_ARRAY_DOUBLE);
1163  bounds.push_back(NULL_DOUBLE);
1164  bounds.push_back(NULL_DOUBLE);
1165  bounds.push_back(NULL_DOUBLE);
1166  // Leaving ring_sizes and poly_rings arrays empty
1167  } break;
1168  default:
1169  throw std::runtime_error("Unsupported NULL geo");
1170  }
1171 }
1172 
1173 } // namespace Geospatial
OGRGeometry * geom_
Definition: Types.h:92
std::unique_ptr< GeoBase > optimized_run(GeoOp op, const GeoBase &other) const
Definition: Types.cpp:439
static std::unique_ptr< GeoBase > createGeoType(const std::string &wkt_or_wkb_hex)
Definition: Types.cpp:919
GeoPoint(const std::vector< double > &coords)
Definition: Types.cpp:541
#define NULL_DOUBLE
void getColumns(std::vector< double > &coords) const
Definition: Types.cpp:567
#define SRID_LAEA_START
Definition: Types.cpp:222
int32_t getNumInteriorRings() const
Definition: Types.cpp:723
#define SRID_NORTH_UTM_END
Definition: Types.cpp:212
GeoMultiPolygon(const std::vector< double > &coords, const std::vector< int32_t > &ring_sizes, const std::vector< int32_t > &poly_rings)
Definition: Types.cpp:734
bool owns_geom_obj_
Definition: Types.h:93
constexpr auto DOUBLE_MAX
Definition: Types.cpp:40
#define LOG(tag)
Definition: Logger.h:203
constexpr HexDigitToDecimalTable hex_digit_to_decimal_table
Definition: Types.cpp:882
GeoLineString(const std::vector< double > &coords)
Definition: Types.cpp:590
GeoGeometryCollection(const std::vector< double > &coords, const std::vector< int32_t > &ring_sizes, const std::vector< int32_t > &poly_rings, const std::vector< int32_t > &geo_kinds)
Definition: Types.h:207
static void init()
Definition: GDAL.cpp:59
static void getGeoColumnsImpl(const std::unique_ptr< GeoBase > &geospatial_base, SQLTypeInfo &ti, std::vector< double > &coords, std::vector< double > &bounds, std::vector< int > &ring_sizes, std::vector< int > &poly_rings, const bool promote_poly_to_mpoly=false)
Definition: Types.cpp:1094
Constants for Builtin SQL Types supported by OmniSci.
static void getNullGeoColumns(SQLTypeInfo &ti, std::vector< double > &coords, std::vector< double > &bounds, std::vector< int > &ring_sizes, std::vector< int > &poly_rings, const bool promote_poly_to_mpoly=false)
Definition: Types.cpp:1144
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:329
static std::unique_ptr< Geospatial::GeoBase > createGeoTypeImpl(OGRGeometry *geom, const bool owns_geom_obj=true)
Definition: Types.cpp:1073
bool getWkb(std::vector< uint8_t > &) const
Definition: Types.cpp:186
#define CHECK_GT(x, y)
Definition: Logger.h:221
constexpr uint8_t operator[](const char &hex_digit) const
Definition: Types.cpp:877
static std::shared_ptr< OGRCoordinateTransformation > getTransformation(int32_t srid0, int32_t srid1)
Definition: Types.cpp:307
std::string to_string(char const *&&v)
std::unique_ptr< GeoBase > clone() const final
Definition: Types.cpp:729
bool isEmpty() const
Definition: Types.cpp:196
int process_poly_ring(OGRLinearRing *ring, std::vector< double > &coords, BoundingBox *bbox)
Definition: Types.cpp:70
virtual ~GeoBase()
Definition: Types.cpp:145
void update(double x, double y)
Definition: Types.cpp:54
static std::string OGRErrorToStr(const int ogr_err)
Definition: Types.cpp:118
GeoGeometry(const std::vector< double > &coords, const std::vector< int32_t > &ring_sizes, const std::vector< int32_t > &poly_rings, const std::vector< int32_t > &geo_kinds)
Definition: Types.h:179
#define SRID_NORTH_UTM_START
Definition: Types.cpp:210
static int createFromWkb(const std::vector< uint8_t > &wkb, OGRGeometry **geom)
Definition: Types.cpp:173
void getColumns(std::vector< double > &coords, std::vector< int32_t > &ring_sizes, std::vector< int32_t > &poly_rings, std::vector< double > &bounds) const
Definition: Types.cpp:773
std::unique_ptr< GeoBase > clone() const
Definition: Types.cpp:536
static bool getGeoColumns(const std::string &wkt_or_wkb_hex, SQLTypeInfo &ti, std::vector< double > &coords, std::vector< double > &bounds, std::vector< int > &ring_sizes, std::vector< int > &poly_rings, const bool promote_poly_to_mpoly=false)
Definition: Types.cpp:937
virtual bool operator==(const GeoBase &other) const
Definition: Types.cpp:200
static OGRGeometry * createOGRGeometry(const std::string &wkt_or_wkb_hex)
Definition: Types.cpp:903
std::unique_ptr< GeoBase > clone() const final
Definition: Types.cpp:644
static int createFromWktString(const std::string &wkt, OGRGeometry **geom)
Definition: Types.cpp:154
tuple line
Definition: parse_ast.py:10
void getColumns(std::vector< double > &coords, std::vector< double > &bounds) const
Definition: Types.cpp:612
std::mutex transformation_map_mutex_
Definition: Types.cpp:114
std::unique_ptr< GeoBase > clone() const final
Definition: Types.cpp:827
constexpr auto DOUBLE_MIN
Definition: Types.cpp:41
HOST DEVICE int get_input_srid() const
Definition: sqltypes.h:333
bool transform(int32_t srid0, int32_t srid1)
Definition: Types.cpp:383
#define NULL_ARRAY_DOUBLE
#define SRID_SOUTH_UTM_START
Definition: Types.cpp:216
#define SRID_SOUTH_UTM_END
Definition: Types.cpp:218
#define CHECK(condition)
Definition: Logger.h:209
char * t
std::string getWktString() const
Definition: Types.cpp:164
#define SRID_SOUTH_LAMBERT
Definition: Types.cpp:220
#define SRID_WORLD_MERCATOR
Definition: Types.cpp:208
#define SRID_LAEA_END
Definition: Types.cpp:224
std::unique_ptr< GeoBase > clone() const final
Definition: Types.cpp:585
uint8_t hex_to_binary(const char &usb, const char &lsb)
Definition: Types.cpp:884
std::unique_ptr< GeoBase > run(GeoOp op, const GeoBase &other) const
Definition: Types.cpp:406
#define SRID_NORTH_LAMBERT
Definition: Types.cpp:214
std::map< std::tuple< int32_t, int32_t >, std::shared_ptr< OGRCoordinateTransformation > > transformation_map_
Definition: Types.cpp:116
std::unique_ptr< GeoBase > clone() const final
Definition: Types.cpp:832
std::vector< uint8_t > hex_string_to_binary_vector(const std::string &wkb_hex)
Definition: Types.cpp:888
void getColumns(std::vector< double > &coords, std::vector< int32_t > &ring_sizes, std::vector< double > &bounds) const
Definition: Types.cpp:681
int32_t getBestPlanarSRID() const
Definition: Types.cpp:226
GeoPolygon(const std::vector< double > &coords, const std::vector< int32_t > &ring_sizes)
Definition: Types.cpp:649
HOST DEVICE int get_output_srid() const
Definition: sqltypes.h:335
HOST DEVICE void set_type(SQLTypes t)
Definition: sqltypes.h:419