Skip to content

Commit

Permalink
[SEDONA-652] Add ST_MakeEnvelope (#1585)
Browse files Browse the repository at this point in the history
  • Loading branch information
furqaankhan authored Sep 13, 2024
1 parent b49b31e commit 20488c0
Show file tree
Hide file tree
Showing 19 changed files with 303 additions and 4 deletions.
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
27 changes: 27 additions & 0 deletions flink/src/test/java/org/apache/sedona/flink/ConstructorTest.java
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

0 comments on commit 20488c0

Please sign in to comment.