Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions presto-docs/src/main/sphinx/functions/geospatial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,13 @@ Operations
the bounding rectangular polygon of a geometry. Returns ``null`` if input
geometry is empty.

.. function:: expand_envelope(Geometry, double) -> Geometry

Returns the bounding rectangular polygon of a geometry, expanded by a
distance. Empty geometries will return an empty polygon. Negative or NaN
distances will return an error. Positive infinity distances may lead to
undefined results.

.. function:: ST_ExteriorRing(Geometry) -> Geometry

Returns a line string representing the exterior ring of the input polygon.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.esri.core.geometry.ogc.OGCPoint;
import com.esri.core.geometry.ogc.OGCPolygon;
import com.facebook.presto.geospatial.GeometryType;
import com.google.common.annotations.VisibleForTesting;
import io.airlift.slice.BasicSliceInput;
import io.airlift.slice.DynamicSliceOutput;
import io.airlift.slice.Slice;
Expand Down Expand Up @@ -66,7 +67,6 @@ public static Slice serialize(OGCGeometry input)
public static Slice serialize(Envelope envelope)
{
requireNonNull(envelope, "envelope is null");
verify(!envelope.isEmpty());
DynamicSliceOutput output = new DynamicSliceOutput(100);
output.appendByte(GeometrySerializationType.ENVELOPE.code());
writeEnvelopeCoordinates(output, envelope);
Expand Down Expand Up @@ -215,7 +215,8 @@ private static OGCGeometry readSimpleGeometry(BasicSliceInput input, Slice input
return createFromEsriGeometry(esriGeometry, type.geometryType().isMultitype());
}

private static OGCGeometry createFromEsriGeometry(Geometry geometry, boolean multiType)
@VisibleForTesting
static OGCGeometry createFromEsriGeometry(Geometry geometry, boolean multiType)
{
Geometry.Type type = geometry.getType();
switch (type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.ArrayList;
import java.util.List;

import static com.facebook.presto.geospatial.GeometryUtils.isEsriNaN;
import static com.facebook.presto.geospatial.GeometryUtils.translateToAVNaN;
import static com.google.common.base.Verify.verify;
import static com.google.common.collect.Iterables.getOnlyElement;
Expand Down Expand Up @@ -216,6 +217,10 @@ private static Geometry readEnvelope(SliceInput input)
double xMax = input.readDouble();
double yMax = input.readDouble();

if (isEsriNaN(xMin) || isEsriNaN(yMin) || isEsriNaN(xMax) || isEsriNaN(yMax)) {
return GEOMETRY_FACTORY.createPolygon();
}

Coordinate[] coordinates = new Coordinate[5];
coordinates[0] = new Coordinate(xMin, yMin);
coordinates[1] = new Coordinate(xMin, yMax);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import org.locationtech.jts.io.WKTReader;
import org.testng.annotations.Test;

import static com.esri.core.geometry.ogc.OGCGeometry.createFromEsriGeometry;
import static com.facebook.presto.geospatial.serde.GeometrySerde.createFromEsriGeometry;
import static com.facebook.presto.geospatial.serde.GeometrySerde.deserialize;
import static com.facebook.presto.geospatial.serde.GeometrySerde.deserializeEnvelope;
import static com.facebook.presto.geospatial.serde.GeometrySerde.deserializeType;
Expand Down Expand Up @@ -133,16 +133,17 @@ public void testGeometryCollection()
@Test
public void testEnvelope()
{
testEnvelopeSerialization(new Envelope());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you are also fixing something here. Do you think it is worth extracing in a separate commit with an explanation?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hidden admixture is that I'm also allowing empty envelopes to be serialized. I can separate that out into another commit.

testEnvelopeSerialization(new Envelope(0, 0, 1, 1));
testEnvelopeSerialization(new Envelope(1, 2, 3, 4));
testEnvelopeSerialization(new Envelope(10101, -2.05, -3e5, 0));
}

private void testEnvelopeSerialization(Envelope envelope)
{
assertEquals(deserialize(serialize(envelope)), createFromEsriGeometry(envelope, null));
assertEquals(deserialize(serialize(envelope)), createFromEsriGeometry(envelope, false));
assertEquals(deserializeEnvelope(serialize(envelope)), envelope);
assertEquals(JtsGeometrySerde.serialize(JtsGeometrySerde.deserialize(serialize(envelope))), serialize(createFromEsriGeometry(envelope, null)));
assertEquals(JtsGeometrySerde.serialize(JtsGeometrySerde.deserialize(serialize(envelope))), serialize(createFromEsriGeometry(envelope, false)));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,30 @@ public static Block stEnvelopeAsPts(@SqlType(GEOMETRY_TYPE_NAME) Slice input)
return blockBuilder.build();
}

@Description("Returns the bounding rectangle of a Geometry expanded by distance.")
@ScalarFunction("expand_envelope")
@SqlType(GEOMETRY_TYPE_NAME)
public static Slice expandEnvelope(@SqlType(GEOMETRY_TYPE_NAME) Slice input, @SqlType(DOUBLE) double distance)
{
if (isNaN(distance)) {
throw new PrestoException(INVALID_FUNCTION_ARGUMENT, "expand_envelope: distance is NaN");
}

if (distance < 0) {
throw new PrestoException(INVALID_FUNCTION_ARGUMENT, format("expand_envelope: distance %s is negative", distance));
}

Envelope envelope = deserializeEnvelope(input);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jagill perhaps, check that distance is >= 0?

if (envelope.isEmpty()) {
return EMPTY_POLYGON;
}
return serialize(new Envelope(
envelope.getXMin() - distance,
envelope.getYMin() - distance,
envelope.getXMax() + distance,
envelope.getYMax() + distance));
}

@Description("Returns the Geometry value that represents the point set difference of two geometries")
@ScalarFunction("ST_Difference")
@SqlType(GEOMETRY_TYPE_NAME)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,24 @@ private void assertEnvelopeAsPts(String wkt, Point lowerLeftCorner, Point upperR
assertFunction(format("transform(ST_EnvelopeAsPts(ST_GeometryFromText('%s')), x -> ST_AsText(x))", wkt), new ArrayType(VARCHAR), ImmutableList.of(new OGCPoint(lowerLeftCorner, null).asText(), new OGCPoint(upperRightCorner, null).asText()));
}

@Test
public void testExpandEnvelope()
{
assertFunction("ST_IsEmpty(expand_envelope(ST_GeometryFromText('POINT EMPTY'), 1))", BOOLEAN, true);
assertFunction("ST_IsEmpty(expand_envelope(ST_GeometryFromText('POLYGON EMPTY'), 1))", BOOLEAN, true);
assertFunction("ST_AsText(expand_envelope(ST_Envelope(ST_Point(1, 10)), 3))", VARCHAR, "POLYGON ((-2 7, 4 7, 4 13, -2 13, -2 7))");
assertFunction("ST_AsText(expand_envelope(ST_Point(1, 10), 3))", VARCHAR, "POLYGON ((-2 7, 4 7, 4 13, -2 13, -2 7))");
assertFunction("ST_AsText(expand_envelope(ST_GeometryFromText('LINESTRING (1 10, 3 15)'), 2))", VARCHAR, "POLYGON ((-1 8, 5 8, 5 17, -1 17, -1 8))");
assertFunction("ST_AsText(expand_envelope(ST_GeometryFromText('GEOMETRYCOLLECTION (POINT (5 1), LINESTRING (3 4, 4 4))'), 1))", VARCHAR, "POLYGON ((2 0, 6 0, 6 5, 2 5, 2 0))");
// JTS has an envelope expanded by infinity to be empty, which is weird.
// PostGIS returns an infinite envelope, which is a tricky concept.
// We'll leave it like this until it becomes a problem.
assertFunction("ST_AsText(expand_envelope(ST_Point(0, 0), infinity()))", VARCHAR, "POLYGON EMPTY");
assertInvalidFunction("ST_AsText(expand_envelope(ST_Point(0, 0), nan()))", "expand_envelope: distance is NaN");
assertInvalidFunction("ST_AsText(expand_envelope(ST_Point(0, 0), -1))", "expand_envelope: distance -1.0 is negative");
assertInvalidFunction("ST_AsText(expand_envelope(ST_Point(0, 0), -infinity()))", "expand_envelope: distance -Infinity is negative");
}

@Test
public void testSTDifference()
{
Expand Down