Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SEDONA-652] Add ST_MakeEnvelope #1585

Merged
merged 1 commit into from
Sep 13, 2024
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
11 changes: 11 additions & 0 deletions common/src/main/java/org/apache/sedona/common/Constructors.java
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,17 @@ public static Geometry polygonFromEnvelope(double minX, double minY, double maxX
return GEOMETRY_FACTORY.createPolygon(coordinates);
}

public static Geometry makeEnvelope(
double minX, double minY, double maxX, double maxY, int srid) {
Geometry envelope = polygonFromEnvelope(minX, minY, maxX, maxY);
envelope.setSRID(srid);
return envelope;
}

public static Geometry makeEnvelope(double minX, double minY, double maxX, double maxY) {
return makeEnvelope(minX, minY, maxX, maxY, 0);
}

public static Geometry geomFromGeoHash(String geoHash, Integer precision) {
try {
return GeoHashDecoder.decode(geoHash, precision);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@

import org.apache.sedona.common.utils.GeomUtils;
import org.junit.Test;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBWriter;

Expand Down Expand Up @@ -226,6 +223,24 @@ public void pointFromGeoHash() {
assertEquals("POINT (-112.5 22.5)", point);
}

@Test
public void makeEnvelope() {
Geometry geom = Constructors.makeEnvelope(10, 10, 11, 11, 4326);
assertTrue(geom instanceof Polygon);
String actual = Functions.asWKT(geom);
String expected = "POLYGON ((10 10, 10 11, 11 11, 11 10, 10 10))";
assertEquals(expected, actual);

int actualSrid = geom.getSRID();
int expectedSrid = 4326;
assertEquals(expectedSrid, actualSrid);

geom = Constructors.makeEnvelope(10, 10, 11, 11);
assertTrue(geom instanceof Polygon);
actual = Functions.asWKT(geom);
assertEquals(expected, actual);
}

@Test
public void makePointM() {
Geometry point = Constructors.makePointM(1, 2, 3);
Expand Down
28 changes: 28 additions & 0 deletions docs/api/flink/Constructor.md
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,34 @@ Output:
LINESTRING (-2.1047439575195312 -0.354827880859375, -1.49606454372406 -0.6676061153411865)
```

## ST_MakeEnvelope

Introduction: Construct a Polygon from MinX, MinY, MaxX, MaxY, and an optional SRID.

Format:

```
ST_MakeEnvelope(MinX: Double, MinY: Double, MaxX: Double, MaxY: Double)
```

```
ST_MakeEnvelope(MinX: Double, MinY: Double, MaxX: Double, MaxY: Double, srid: Integer)
```

Since: `v1.7.0`

SQL Example

```sql
SELECT ST_MakeEnvelope(1.234, 2.234, 3.345, 3.345, 4236)
```

Output:

```
POLYGON ((1.234 2.234, 1.234 3.345, 3.345 3.345, 3.345 2.234, 1.234 2.234))
```

## ST_MLineFromText

Introduction: Construct a MultiLineString from Text and Optional SRID
Expand Down
26 changes: 26 additions & 0 deletions docs/api/snowflake/vector-data/Constructor.md
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,32 @@ Output:
LINESTRING (-2.1047439575195312 -0.354827880859375, -1.49606454372406 -0.6676061153411865)
```

## ST_MakeEnvelope

Introduction: Construct a Polygon from MinX, MinY, MaxX, MaxY, and an optional SRID.

Format:

```
ST_MakeEnvelope(MinX: Double, MinY: Double, MaxX: Double, MaxY: Double)
```

```
ST_MakeEnvelope(MinX: Double, MinY: Double, MaxX: Double, MaxY: Double, srid: Integer)
```

SQL Example

```sql
SELECT ST_MakeEnvelope(1.234, 2.234, 3.345, 3.345, 4236)
```

Output:

```
POLYGON ((1.234 2.234, 1.234 3.345, 3.345 3.345, 3.345 2.234, 1.234 2.234))
```

## ST_MLineFromText

Introduction: Construct a MultiLineString from Wkt. If srid is not set, it defaults to 0 (unknown).
Expand Down
28 changes: 28 additions & 0 deletions docs/api/sql/Constructor.md
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,34 @@ Output:
LINESTRING (-2.1047439575195312 -0.354827880859375, -1.49606454372406 -0.6676061153411865)
```

## ST_MakeEnvelope

Introduction: Construct a Polygon from MinX, MinY, MaxX, MaxY, and an optional SRID.

Format:

```
ST_MakeEnvelope(MinX: Double, MinY: Double, MaxX: Double, MaxY: Double)
```

```
ST_MakeEnvelope(MinX: Double, MinY: Double, MaxX: Double, MaxY: Double, srid: Integer)
```

Since: `v1.7.0`

SQL Example

```sql
SELECT ST_MakeEnvelope(1.234, 2.234, 3.345, 3.345, 4236)
```

Output:

```
POLYGON ((1.234 2.234, 1.234 3.345, 3.345 3.345, 3.345 2.234, 1.234 2.234))
```

## ST_MLineFromText

Introduction: Construct a MultiLineString from Wkt. If srid is not set, it defaults to 0 (unknown).
Expand Down
1 change: 1 addition & 0 deletions flink/src/main/java/org/apache/sedona/flink/Catalog.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public static UserDefinedFunction[] getFuncs() {
new Constructors.ST_PointFromWKB(),
new Constructors.ST_LineFromWKB(),
new Constructors.ST_LinestringFromWKB(),
new Constructors.ST_MakeEnvelope(),
new Constructors.ST_MakePoint(),
new Constructors.ST_MakePointM(),
new Constructors.ST_LineStringFromText(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,27 @@ public Geometry eval(@DataTypeHint("String") String polygonString) throws ParseE
}
}

public static class ST_MakeEnvelope extends ScalarFunction {
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
public Geometry eval(
@DataTypeHint("Double") Double minX,
@DataTypeHint("Double") Double minY,
@DataTypeHint("Double") Double maxX,
@DataTypeHint("Double") Double maxY,
@DataTypeHint("Integer") Integer srid) {
return org.apache.sedona.common.Constructors.makeEnvelope(minX, minY, maxX, maxY, srid);
}

@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
public Geometry eval(
@DataTypeHint("Double") Double minX,
@DataTypeHint("Double") Double minY,
@DataTypeHint("Double") Double maxX,
@DataTypeHint("Double") Double maxY) {
return org.apache.sedona.common.Constructors.makeEnvelope(minX, minY, maxX, maxY);
}
}

public static class ST_PolygonFromEnvelope extends ScalarFunction {
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
public Geometry eval(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,33 @@ public void testGeometryFromText() {
assertEquals(4326, actual);
}

@Test
public void testMakeEvelope() {
Double minX = 1.0;
Double minY = 100.0;
Double maxX = 2.0;
Double maxY = 200.0;
Coordinate[] coordinates = new Coordinate[5];
coordinates[0] = new Coordinate(minX, minY);
coordinates[1] = new Coordinate(minX, maxY);
coordinates[2] = new Coordinate(maxX, maxY);
coordinates[3] = new Coordinate(maxX, minY);
coordinates[4] = coordinates[0];
GeometryFactory geometryFactory = new GeometryFactory();
Geometry geom = geometryFactory.createPolygon(coordinates);
Geometry actualGeom =
(Geometry)
last(tableEnv.sqlQuery("SELECT ST_MakeEnvelope(1, 100, 2, 200, 1111)")).getField(0);
assertEquals(actualGeom.toString(), geom.toString());
assertEquals(1111, actualGeom.getSRID());

assertEquals(
last(tableEnv.sqlQuery("SELECT ST_MakeEnvelope(1.0, 100.0, 2.0, 200.0)"))
.getField(0)
.toString(),
geom.toString());
}

@Test
public void testPolygonFromEnvelope() {
Double minX = 1.0;
Expand Down
22 changes: 22 additions & 0 deletions python/sedona/sql/st_constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,28 @@ def ST_MakePoint(x: ColumnOrNameOrNumber, y: ColumnOrNameOrNumber, z: Optional[C
args = args + (m,)
return _call_constructor_function("ST_MakePoint", (args))

@validate_argument_types
def ST_MakeEnvelope(min_x: ColumnOrNameOrNumber, min_y: ColumnOrNameOrNumber, max_x: ColumnOrNameOrNumber, max_y: ColumnOrNameOrNumber, srid: Optional[ColumnOrNameOrNumber] = None) -> Column:
"""Generate a polygon geometry column from the minimum and maximum coordinates of an envelope with an option to add SRID

:param min_x: Minimum X coordinate for the envelope.
:type min_x: ColumnOrNameOrNumber
:param min_y: Minimum Y coordinate for the envelope.
:type min_y: ColumnOrNameOrNumber
:param max_x: Maximum X coordinate for the envelope.
:type max_x: ColumnOrNameOrNumber
:param max_y: Maximum Y coordinate for the envelope.
:type max_y: ColumnOrNameOrNumber
:param srid: SRID to be set for the envelope.
:type srid: ColumnOrNameOrNumber
:return: Polygon geometry column representing the envelope described by the coordinate bounds.
:rtype: Column
"""
args = (min_x, min_y, max_x, max_y, srid)
if srid is None:
args = (min_x, min_y, max_x, max_y)

return _call_constructor_function("ST_MakeEnvelope", args)

@validate_argument_types
def ST_PolygonFromEnvelope(min_x: ColumnOrNameOrNumber, min_y: ColumnOrNameOrNumber, max_x: ColumnOrNameOrNumber, max_y: ColumnOrNameOrNumber) -> Column:
Expand Down
10 changes: 10 additions & 0 deletions python/tests/sql/test_constructor_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ def test_st_geom_from_wkt_3d(self):
polygon_df = self.spark.sql("select ST_GeomFromWkt(wkt) as geomn from input_wkt")
assert polygon_df.count() == 8

def test_st_make_envelope(self):
polygonDF = self.spark.sql(
"select ST_MakeEnvelope(double(1.234),double(2.234),double(3.345),double(3.345), 1111) as geom")
assert (polygonDF.count() == 1)
assert (1111 == polygonDF.selectExpr("ST_SRID(geom)").first()[0])

polygonDF = self.spark.sql(
"select ST_MakeEnvelope(double(1.234),double(2.234),double(3.345),double(3.345))")
assert (polygonDF.count() == 1)

def test_st_geom_from_text(self):
polygon_wkt_df = self.spark.read.format("csv").\
option("delimiter", "\t").\
Expand Down
7 changes: 7 additions & 0 deletions python/tests/sql/test_dataframe_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@
(stc.ST_PointFromWKB, ("wkbPoint",), "constructor", "", "POINT (10 15)"),
(stc.ST_MakePoint, ("x", "y", "z"), "constructor", "", "POINT Z (0 1 2)"),
(stc.ST_MakePointM, ("x", "y", "z"), "constructor", "ST_AsText(geom)", "POINT M(0 1 2)"),
(stc.ST_MakeEnvelope, ("minx", "miny", "maxx", "maxy"), "min_max_x_y", "", "POLYGON ((0 1, 0 3, 2 3, 2 1, 0 1))"),
(stc.ST_MakeEnvelope, ("minx", "miny", "maxx", "maxy", lambda: f.lit(1111)), "min_max_x_y", "", "POLYGON ((0 1, 0 3, 2 3, 2 1, 0 1))"),
(stc.ST_MakeEnvelope, ("minx", "miny", "maxx", "maxy", lambda: f.lit(1111)), "min_max_x_y", "ST_SRID(geom)", 1111),
(stc.ST_PolygonFromEnvelope, ("minx", "miny", "maxx", "maxy"), "min_max_x_y", "", "POLYGON ((0 1, 0 3, 2 3, 2 1, 0 1))"),
(stc.ST_PolygonFromEnvelope, (0.0, 1.0, 2.0, 3.0), "null", "", "POLYGON ((0 1, 0 3, 2 3, 2 1, 0 1))"),
(stc.ST_PolygonFromText, ("multiple_point", lambda: f.lit(',')), "constructor", "", "POLYGON ((0 0, 1 0, 1 1, 0 0))"),
Expand Down Expand Up @@ -296,6 +299,10 @@
(stc.ST_PointFromText, ("", None)),
(stc.ST_PointFromWKB, (None,)),
(stc.ST_MPointFromText, (None,)),
(stc.ST_MakeEnvelope, (None, "", "", "", "")),
(stc.ST_MakeEnvelope, ("", None, "", "", "")),
(stc.ST_MakeEnvelope, ("", "", None, "", None)),
(stc.ST_MakeEnvelope, ("", "", "", None, None)),
(stc.ST_PolygonFromEnvelope, (None, "", "", "")),
(stc.ST_PolygonFromEnvelope, ("", None, "", "")),
(stc.ST_PolygonFromEnvelope, ("", "", None, "")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,22 @@ public void test_ST_PointFromText() {
"select sedona.ST_AsText(sedona.ST_PointFromText('1.23,2.3', ','))", "POINT (1.23 2.3)");
}

@Test
public void test_ST_MakeEnvelope() {
registerUDF("ST_MakeEnvelope", double.class, double.class, double.class, double.class);
verifySqlSingleRes(
"select sedona.ST_AsText(sedona.ST_MakeEnvelope(1.23, 2.3, 3.4, 4.5))",
"POLYGON ((1.23 2.3, 1.23 4.5, 3.4 4.5, 3.4 2.3, 1.23 2.3))");

registerUDF(
"ST_MakeEnvelope", double.class, double.class, double.class, double.class, int.class);
verifySqlSingleRes(
"select sedona.ST_AsText(sedona.ST_MakeEnvelope(1.23, 2.3, 3.4, 4.5, 1111))",
"POLYGON ((1.23 2.3, 1.23 4.5, 3.4 4.5, 3.4 2.3, 1.23 2.3))");
verifySqlSingleRes(
"select sedona.ST_SRID(sedona.ST_MakeEnvelope(1.23, 2.3, 3.4, 4.5, 1111))", 1111);
}

@Test
public void test_ST_PolygonFromEnvelope() {
registerUDF("ST_PolygonFromEnvelope", double.class, double.class, double.class, double.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,17 @@ public static byte[] ST_PolygonFromEnvelope(double minX, double minY, double max
return GeometrySerde.serialize(Constructors.polygonFromEnvelope(minX, minY, maxX, maxY));
}

@UDFAnnotations.ParamMeta(argNames = {"minX", "minY", "maxX", "maxY"})
public static byte[] ST_MakeEnvelope(double minX, double minY, double maxX, double maxY) {
return GeometrySerde.serialize(Constructors.makeEnvelope(minX, minY, maxX, maxY));
}

@UDFAnnotations.ParamMeta(argNames = {"minX", "minY", "maxX", "maxY", "srid"})
public static byte[] ST_MakeEnvelope(
double minX, double minY, double maxX, double maxY, int srid) {
return GeometrySerde.serialize(Constructors.makeEnvelope(minX, minY, maxX, maxY, srid));
}

@UDFAnnotations.ParamMeta(argNames = {"geomString", "delimiter"})
public static byte[] ST_PolygonFromText(String geomString, String geomFormat) {
return GeometrySerde.serialize(Constructors.polygonFromText(geomString, geomFormat));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ object Catalog {
function[ST_CoordDim](),
function[ST_Point](),
function[ST_Points](),
function[ST_MakeEnvelope](),
function[ST_MakePoint](null, null),
function[ST_MakePointM](),
function[ST_PointZ](0),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,21 @@ case class ST_MakePoint(inputExpressions: Seq[Expression])
}
}

/**
* Return a polygon given minX,minY,maxX,maxY and optional SRID
*
* @param inputExpressions
*/
case class ST_MakeEnvelope(inputExpressions: Seq[Expression])
extends InferredExpression(
inferrableFunction5(Constructors.makeEnvelope),
inferrableFunction4(Constructors.makeEnvelope)) {

protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
copy(inputExpressions = newChildren)
}
}

/**
* Return a polygon given minX,minY,maxX,maxY
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,29 @@ object st_constructors extends DataFrameAPI {
def ST_PointFromText(coords: String, delimiter: String): Column =
wrapExpression[ST_PointFromText](coords, delimiter)

def ST_MakeEnvelope(minX: Column, minY: Column, maxX: Column, maxY: Column): Column =
wrapExpression[ST_MakeEnvelope](minX, minY, maxX, maxY)
def ST_MakeEnvelope(minX: String, minY: String, maxX: String, maxY: String): Column =
wrapExpression[ST_MakeEnvelope](minX, minY, maxX, maxY)
def ST_MakeEnvelope(minX: Double, minY: Double, maxX: Double, maxY: Double): Column =
wrapExpression[ST_MakeEnvelope](minX, minY, maxX, maxY)
def ST_MakeEnvelope(
minX: Column,
minY: Column,
maxX: Column,
maxY: Column,
srid: Column): Column =
wrapExpression[ST_MakeEnvelope](minX, minY, maxX, maxY, srid)
def ST_MakeEnvelope(
minX: String,
minY: String,
maxX: String,
maxY: String,
srid: String): Column =
wrapExpression[ST_MakeEnvelope](minX, minY, maxX, maxY, srid)
def ST_MakeEnvelope(minX: Double, minY: Double, maxX: Double, maxY: Double, srid: Int): Column =
wrapExpression[ST_MakeEnvelope](minX, minY, maxX, maxY, srid)

def ST_PolygonFromEnvelope(minX: Column, minY: Column, maxX: Column, maxY: Column): Column =
wrapExpression[ST_PolygonFromEnvelope](minX, minY, maxX, maxY)
def ST_PolygonFromEnvelope(minX: String, minY: String, maxX: String, maxY: String): Column =
Expand Down
Loading
Loading