-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #203 from Maxxen/dev
Add `ST_QuadKey`
- Loading branch information
Showing
5 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
--- | ||
{ | ||
"id": "st_quadkey", | ||
"title": "ST_QuadKey", | ||
"type": "scalar_function", | ||
"signatures": [ | ||
{ | ||
"returns": "VARCHAR", | ||
"parameters": [ | ||
{ | ||
"name": "geom", | ||
"type": "GEOMETRY" | ||
}, | ||
{ | ||
"name": "level", | ||
"type": "INTEGER" | ||
} | ||
] | ||
}, | ||
{ | ||
"returns": "VARCHAR", | ||
"parameters": [ | ||
{ | ||
"name": "longitude", | ||
"type": "DOUBLE" | ||
}, | ||
{ | ||
"name": "latitude", | ||
"type": "DOUBLE" | ||
}, | ||
{ | ||
"name": "level", | ||
"type": "INTEGER" | ||
} | ||
] | ||
} | ||
], | ||
"aliases": [], | ||
"summary": "Computes a quadkey from a given lon/lat point.", | ||
"see_also": [ ], | ||
"tags": [ "property" ] | ||
} | ||
--- | ||
|
||
### Description | ||
|
||
Compute the [quadkey](https://learn.microsoft.com/en-us/bingmaps/articles/bing-maps-tile-system) for a given lon/lat point at a given level. | ||
Note that the the parameter order is __longitude__, __latitude__. | ||
|
||
`level` has to be between 1 and 23, inclusive. | ||
|
||
The input coordinates will be clamped to the lon/lat bounds of the earth (longitude between -180 and 180, latitude between -85.05112878 and 85.05112878). | ||
|
||
Throws for any geometry that is not a `POINT` | ||
|
||
### Examples | ||
|
||
```sql | ||
SELECT ST_QuadKey(st_point(11.08, 49.45), 10); | ||
-- 1333203202 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
108 changes: 108 additions & 0 deletions
108
spatial/src/spatial/core/functions/scalar/st_quadkey.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" | ||
#include "duckdb/common/vector_operations/generic_executor.hpp" | ||
#include "spatial/common.hpp" | ||
#include "spatial/core/functions/scalar.hpp" | ||
#include "spatial/core/functions/common.hpp" | ||
#include "spatial/core/geometry/geometry.hpp" | ||
#include "spatial/core/types.hpp" | ||
|
||
#define _USE_MATH_DEFINES | ||
#include <cmath> | ||
#include "math.h" | ||
|
||
namespace spatial { | ||
|
||
namespace core { | ||
|
||
static void GetQuadKey(double lon, double lat, int32_t level, char* buffer) { | ||
|
||
lat = std::max(-85.05112878, std::min(85.05112878, lat)); | ||
lon = std::max(-180.0, std::min(180.0, lon)); | ||
|
||
double lat_rad = lat * M_PI / 180.0; | ||
auto x = static_cast<int32_t>((lon + 180.0) / 360.0 * (1 << level)); | ||
auto y = static_cast<int32_t>((1.0 - std::log(std::tan(lat_rad) + 1.0 / std::cos(lat_rad)) / M_PI) / 2.0 * (1 << level)); | ||
|
||
for (int i = level; i > 0; --i) { | ||
char digit = '0'; | ||
int32_t mask = 1 << (i - 1); | ||
if ((x & mask) != 0) { | ||
digit += 1; | ||
} | ||
if ((y & mask) != 0) { | ||
digit += 2; | ||
} | ||
|
||
buffer[level - i] = digit; | ||
} | ||
} | ||
//------------------------------------------------------------------------------ | ||
// Coordinates | ||
//------------------------------------------------------------------------------ | ||
static void CoordinateQuadKeyFunction(DataChunk &args, ExpressionState &state, Vector &result) { | ||
auto &lon_in = args.data[0]; | ||
auto &lat_in = args.data[1]; | ||
auto &level = args.data[2]; | ||
auto count = args.size(); | ||
|
||
TernaryExecutor::Execute<double, double, int32_t, string_t>(lon_in, lat_in, level, result, count, [&](double lon, double lat, int32_t level) { | ||
if(level < 1 || level > 23) { | ||
throw InvalidInputException("ST_QuadKey: Level must be between 1 and 23"); | ||
} | ||
char buffer[64]; | ||
GetQuadKey(lon, lat, level, buffer); | ||
return StringVector::AddString(result, buffer, level); | ||
}); | ||
} | ||
|
||
//------------------------------------------------------------------------------ | ||
// GEOMETRY | ||
//------------------------------------------------------------------------------ | ||
static void GeometryQuadKeyFunction(DataChunk &args, ExpressionState &state, Vector &result) { | ||
auto &ctx = GeometryFunctionLocalState::ResetAndGet(state); | ||
|
||
auto &geom = args.data[0]; | ||
auto &level = args.data[1]; | ||
auto count = args.size(); | ||
|
||
BinaryExecutor::Execute<string_t, int32_t, string_t>(geom, level, result, count, [&](string_t input, int32_t level) { | ||
auto header = GeometryHeader::Get(input); | ||
if(header.type != GeometryType::POINT) { | ||
throw InvalidInputException("ST_QuadKey: Only POINT geometries are supported"); | ||
} | ||
auto point = ctx.factory.Deserialize(input); | ||
if(point.IsEmpty()) { | ||
throw InvalidInputException("ST_QuadKey: Empty geometries are not supported"); | ||
} | ||
auto vertex = point.GetPoint().GetVertex(); | ||
auto x = vertex.x; | ||
auto y = vertex.y; | ||
|
||
if(level < 1 || level > 23) { | ||
throw InvalidInputException("ST_QuadKey: Level must be between 1 and 23"); | ||
} | ||
|
||
char buffer[64]; | ||
GetQuadKey(x, y, level, buffer); | ||
return StringVector::AddString(result, buffer, level); | ||
}); | ||
} | ||
|
||
//------------------------------------------------------------------------------ | ||
// Register functions | ||
//------------------------------------------------------------------------------ | ||
void CoreScalarFunctions::RegisterStQuadKey(DatabaseInstance &db) { | ||
|
||
ScalarFunctionSet set("ST_QuadKey"); | ||
|
||
set.AddFunction(ScalarFunction({LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::INTEGER}, LogicalType::VARCHAR, | ||
CoordinateQuadKeyFunction)); | ||
set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY(), LogicalType::INTEGER}, LogicalType::VARCHAR, | ||
GeometryQuadKeyFunction, nullptr, nullptr, nullptr, GeometryFunctionLocalState::Init)); | ||
|
||
ExtensionUtil::RegisterFunction(db, set); | ||
} | ||
|
||
} // namespace core | ||
|
||
} // namespace spatial |