use of io.trino.spi.function.ScalarFunction in project trino by trinodb.
the class BingTileFunctions method geometryToBingTiles.
@Description("Given a geometry and a zoom level, returns the minimum set of Bing tiles that fully covers that geometry")
@ScalarFunction("geometry_to_bing_tiles")
@SqlType("array(" + BingTileType.NAME + ")")
public static Block geometryToBingTiles(@SqlType(GEOMETRY_TYPE_NAME) Slice input, @SqlType(StandardTypes.INTEGER) long zoomLevelInput) {
checkZoomLevel(zoomLevelInput);
int zoomLevel = toIntExact(zoomLevelInput);
OGCGeometry ogcGeometry = deserialize(input);
if (ogcGeometry.isEmpty()) {
return EMPTY_TILE_ARRAY;
}
Envelope envelope = getEnvelope(ogcGeometry);
checkLatitude(envelope.getYMin(), LATITUDE_SPAN_OUT_OF_RANGE);
checkLatitude(envelope.getYMax(), LATITUDE_SPAN_OUT_OF_RANGE);
checkLongitude(envelope.getXMin(), LONGITUDE_SPAN_OUT_OF_RANGE);
checkLongitude(envelope.getXMax(), LONGITUDE_SPAN_OUT_OF_RANGE);
boolean pointOrRectangle = isPointOrRectangle(ogcGeometry, envelope);
BingTile leftUpperTile = latitudeLongitudeToTile(envelope.getYMax(), envelope.getXMin(), zoomLevel);
BingTile rightLowerTile = getTileCoveringLowerRightCorner(envelope, zoomLevel);
// XY coordinates start at (0,0) in the left upper corner and increase left to right and top to bottom
long tileCount = (long) (rightLowerTile.getX() - leftUpperTile.getX() + 1) * (rightLowerTile.getY() - leftUpperTile.getY() + 1);
checkGeometryToBingTilesLimits(ogcGeometry, envelope, pointOrRectangle, tileCount, zoomLevel);
BlockBuilder blockBuilder = BIGINT.createBlockBuilder(null, toIntExact(tileCount));
if (pointOrRectangle || zoomLevel <= OPTIMIZED_TILING_MIN_ZOOM_LEVEL) {
// all tiles covering the bounding box intersect the geometry.
for (int x = leftUpperTile.getX(); x <= rightLowerTile.getX(); x++) {
for (int y = leftUpperTile.getY(); y <= rightLowerTile.getY(); y++) {
BingTile tile = BingTile.fromCoordinates(x, y, zoomLevel);
if (pointOrRectangle || !disjoint(tileToEnvelope(tile), ogcGeometry)) {
BIGINT.writeLong(blockBuilder, tile.encode());
}
}
}
} else {
// Intersection checks above are expensive. The logic below attempts to reduce the number
// of these checks. The idea is to identify large tiles which are fully covered by the
// geometry. For each such tile, we can cheaply compute all the containing tiles at
// the right zoom level and append them to results in bulk. This way we perform a single
// containment check instead of 2 to the power of level delta intersection checks, where
// level delta is the difference between the desired zoom level and level of the large
// tile covered by the geometry.
BingTile[] tiles = getTilesInBetween(leftUpperTile, rightLowerTile, OPTIMIZED_TILING_MIN_ZOOM_LEVEL);
for (BingTile tile : tiles) {
appendIntersectingSubtiles(ogcGeometry, zoomLevel, tile, blockBuilder);
}
}
return blockBuilder.build();
}
use of io.trino.spi.function.ScalarFunction in project trino by trinodb.
the class GeoFunctions method toSphericalGeography.
@Description("Converts a Geometry object to a SphericalGeography object")
@ScalarFunction("to_spherical_geography")
@SqlType(SPHERICAL_GEOGRAPHY_TYPE_NAME)
public static Slice toSphericalGeography(@SqlType(GEOMETRY_TYPE_NAME) Slice input) {
// "every point in input is in range" <=> "the envelope of input is in range"
Envelope envelope = deserializeEnvelope(input);
if (!envelope.isEmpty()) {
checkLatitude(envelope.getYMin());
checkLatitude(envelope.getYMax());
checkLongitude(envelope.getXMin());
checkLongitude(envelope.getXMax());
}
OGCGeometry geometry = deserialize(input);
if (geometry.is3D()) {
throw new TrinoException(INVALID_FUNCTION_ARGUMENT, "Cannot convert 3D geometry to a spherical geography");
}
GeometryCursor cursor = geometry.getEsriGeometryCursor();
while (true) {
com.esri.core.geometry.Geometry subGeometry = cursor.next();
if (subGeometry == null) {
break;
}
if (!GEOMETRY_TYPES_FOR_SPHERICAL_GEOGRAPHY.contains(subGeometry.getType())) {
throw new TrinoException(INVALID_FUNCTION_ARGUMENT, "Cannot convert geometry of this type to spherical geography: " + subGeometry.getType());
}
}
return input;
}
use of io.trino.spi.function.ScalarFunction in project trino by trinodb.
the class GeoFunctions method stEndPoint.
@SqlNullable
@Description("Returns the last point of a LINESTRING geometry as a Point")
@ScalarFunction("ST_EndPoint")
@SqlType(GEOMETRY_TYPE_NAME)
public static Slice stEndPoint(@SqlType(GEOMETRY_TYPE_NAME) Slice input) {
OGCGeometry geometry = deserialize(input);
validateType("ST_EndPoint", geometry, EnumSet.of(LINE_STRING));
if (geometry.isEmpty()) {
return null;
}
MultiPath lines = (MultiPath) geometry.getEsriGeometry();
SpatialReference reference = geometry.getEsriSpatialReference();
return serialize(createFromEsriGeometry(lines.getPoint(lines.getPointCount() - 1), reference));
}
use of io.trino.spi.function.ScalarFunction in project trino by trinodb.
the class GeoFunctions method stGeometries.
@SqlNullable
@Description("Returns an array of geometries in the specified collection")
@ScalarFunction("ST_Geometries")
@SqlType("array(" + GEOMETRY_TYPE_NAME + ")")
public static Block stGeometries(@SqlType(GEOMETRY_TYPE_NAME) Slice input) {
OGCGeometry geometry = deserialize(input);
if (geometry.isEmpty()) {
return null;
}
GeometryType type = GeometryType.getForEsriGeometryType(geometry.geometryType());
if (!type.isMultitype()) {
BlockBuilder blockBuilder = GEOMETRY.createBlockBuilder(null, 1);
GEOMETRY.writeSlice(blockBuilder, serialize(geometry));
return blockBuilder.build();
}
OGCGeometryCollection collection = (OGCGeometryCollection) geometry;
BlockBuilder blockBuilder = GEOMETRY.createBlockBuilder(null, collection.numGeometries());
for (int i = 0; i < collection.numGeometries(); i++) {
GEOMETRY.writeSlice(blockBuilder, serialize(collection.geometryN(i)));
}
return blockBuilder.build();
}
use of io.trino.spi.function.ScalarFunction in project trino by trinodb.
the class GeoFunctions method stIntersects.
@SqlNullable
@Description("Returns TRUE if the Geometries spatially intersect in 2D - (share any portion of space) and FALSE if they don't (they are Disjoint)")
@ScalarFunction("ST_Intersects")
@SqlType(BOOLEAN)
public static Boolean stIntersects(@SqlType(GEOMETRY_TYPE_NAME) Slice left, @SqlType(GEOMETRY_TYPE_NAME) Slice right) {
if (!envelopes(left, right, Envelope::intersect)) {
return false;
}
OGCGeometry leftGeometry = deserialize(left);
OGCGeometry rightGeometry = deserialize(right);
verifySameSpatialReference(leftGeometry, rightGeometry);
return leftGeometry.intersects(rightGeometry);
}
Aggregations