Skip to content

Commit

Permalink
[SEDONA-666] add ST_Scale and ST_ScaleGeom (#1650)
Browse files Browse the repository at this point in the history
* feat: add ST_Scale and ST_ScaleGeom

* fix: spark integration

* docs: add docs

* checking snowflake tests

* fix: formatting snowflake tests

* fix: snowflake tests

* fix: snowflake tests 2/2

* Apply suggestions from code review

Co-authored-by: John Bampton <[email protected]>

---------

Co-authored-by: John Bampton <[email protected]>
  • Loading branch information
furqaankhan and jbampton authored Oct 24, 2024
1 parent f8a4a8a commit d0f6e9f
Show file tree
Hide file tree
Showing 21 changed files with 637 additions and 2 deletions.
39 changes: 39 additions & 0 deletions common/src/main/java/org/apache/sedona/common/Functions.java
Original file line number Diff line number Diff line change
Expand Up @@ -2266,6 +2266,45 @@ public static Geometry points(Geometry geometry) {
return geometry.getFactory().createMultiPointFromCoords(coordinates);
}

public static Geometry scale(Geometry geometry, double scaleX, double scaleY) {
return scaleGeom(geometry, Constructors.point(scaleX, scaleY));
}

public static Geometry scaleGeom(Geometry geometry, Geometry factor) {
return scaleGeom(geometry, factor, null);
}

public static Geometry scaleGeom(Geometry geometry, Geometry factor, Geometry origin) {
if (geometry == null || factor == null || geometry.isEmpty() || factor.isEmpty()) {
return geometry;
}

if (!factor.getGeometryType().equalsIgnoreCase(Geometry.TYPENAME_POINT)) {
throw new IllegalArgumentException("Scale factor geometry should be a Point type.");
}

Geometry resultGeom = null;
AffineTransformation scaleInstance = null;
Coordinate factorCoordinate = factor.getCoordinate();

if (origin == null || origin.isEmpty()) {
scaleInstance =
AffineTransformation.scaleInstance(factorCoordinate.getX(), factorCoordinate.getY());
resultGeom = scaleInstance.transform(geometry);
} else {
Coordinate falseOrigin = origin.getCoordinate();
scaleInstance =
AffineTransformation.scaleInstance(
factorCoordinate.getX(),
factorCoordinate.getY(),
falseOrigin.getX(),
falseOrigin.getY());
resultGeom = scaleInstance.transform(geometry);
}

return resultGeom;
}

public static Geometry rotateX(Geometry geometry, double angle) {
if (GeomUtils.isAnyGeomEmpty(geometry)) {
return geometry;
Expand Down
38 changes: 38 additions & 0 deletions common/src/test/java/org/apache/sedona/common/FunctionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3994,6 +3994,44 @@ public void points() throws ParseException {
assertEquals("MULTIPOINT Z((0 0 1), (1 1 2), (2 2 3), (0 0 1))", result1);
}

@Test
public void scale() throws ParseException {
Geometry geom = Constructors.geomFromWKT("POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))", 0);
Geometry actual = Functions.scale(geom, 3, 2);
String expected = "POLYGON ((0 0, 0 2, 3 2, 3 0, 0 0))";
assertEquals(expected, actual.toString());

geom = Constructors.geomFromWKT("LINESTRING(0 1, 1 0)", 0);
actual = Functions.scale(geom, 10, 5);
expected = "LINESTRING (0 5, 10 0)";
assertEquals(expected, actual.toString());

geom = Constructors.geomFromWKT("POLYGON ((0 0, 0 1.5, 1.5 1.5, 1.5 0, 0 0))", 1111);
actual = Functions.scaleGeom(geom, Constructors.point(1.8, 2.1));
expected = "POLYGON ((0 0, 0 3.1500000000000004, 2.7 3.1500000000000004, 2.7 0, 0 0))";
assertEquals(expected, actual.toString());
assertEquals(1111, actual.getSRID());

actual =
Functions.scaleGeom(geom, Constructors.point(3, 2), Constructors.point(0.32959, 0.796483));
expected =
"POLYGON ((-0.6591799999999999 -0.796483, -0.6591799999999999 2.2035169999999997, 3.84082 2.2035169999999997, 3.84082 -0.796483, -0.6591799999999999 -0.796483))";
assertEquals(expected, actual.toString());

// test to check Z and M ordinate preservation
geom = Constructors.geomFromWKT("POLYGON ((0 0 1, 0 1.5 2, 1.5 1.5 2, 1.5 0 3, 0 0 1))", 0);
String actualWKT = Functions.asWKT(Functions.scale(geom, 3, 2));
expected = "POLYGON Z((0 0 1, 0 3 2, 4.5 3 2, 4.5 0 3, 0 0 1))";
assertEquals(expected, actualWKT);

geom =
Constructors.geomFromWKT(
"POLYGON ZM((0 0 1 2, 0 1.5 2 2, 1.5 1.5 2 2, 1.5 0 3 2, 0 0 1 2))", 0);
actualWKT = Functions.asWKT(Functions.scale(geom, 3, 2));
expected = "POLYGON ZM((0 0 1 2, 0 3 2 2, 4.5 3 2 2, 4.5 0 3 2, 0 0 1 2))";
assertEquals(expected, actualWKT);
}

@Test
public void rotateX() throws ParseException {
Geometry lineString = Constructors.geomFromEWKT("LINESTRING (50 160, 50 50, 100 50)");
Expand Down
73 changes: 73 additions & 0 deletions docs/api/flink/Function.md
Original file line number Diff line number Diff line change
Expand Up @@ -3430,6 +3430,79 @@ Output:
[POLYGON ((-36.609392788630245 -38.169532607255846, -36.609392706252954 -38.169532607255846, -36.609392706252954 -38.169532507473015, -36.609392788630245 -38.169532507473015, -36.609392788630245 -38.169532607255846))]
```

## ST_Scale

Introduction: This function scales the geometry to a new size by multiplying the ordinates with the corresponding scaling factors provided as parameters `scaleX` and `scaleY`.

!!!Note
This function is designed for scaling 2D geometries. While it currently doesn't support scaling the Z and M coordinates, it preserves these values during the scaling operation.

Format: `ST_Scale(geometry: Geometry, scaleX: Double, scaleY: Double)`

Since: `v1.7.0`

SQL Example:

```sql
SELECT ST_Scale(
ST_GeomFromWKT('POLYGON ((0 0, 0 1.5, 1.5 1.5, 1.5 0, 0 0))'),
3, 2
)
```

Output:

```
POLYGON ((0 0, 0 3, 4.5 3, 4.5 0, 0 0))
```

## ST_ScaleGeom

Introduction: This function scales the input geometry (`geometry`) to a new size. It does this by multiplying the coordinates of the input geometry with corresponding values from another geometry (`factor`) representing the scaling factors.

To scale the geometry relative to a point other than the true origin (e.g., scaling a polygon in place using its centroid), you can use the three-geometry variant of this function. This variant requires an additional geometry (`origin`) representing the "false origin" for the scaling operation. If no `origin` is provided, the scaling occurs relative to the true origin, with all coordinates of the input geometry simply multiplied by the corresponding scale factors.

!!!Note
This function is designed for scaling 2D geometries. While it currently doesn't support scaling the Z and M coordinates, it preserves these values during the scaling operation.

Format:

`ST_ScaleGeom(geometry: Geometry, factor: Geometry, origin: Geometry)`

`ST_ScaleGeom(geometry: Geometry, factor: Geometry)`

Since: `v1.7.0`

SQL Example:

```sql
SELECT ST_Scale(
ST_GeomFromWKT('POLYGON ((0 0, 0 1.5, 1.5 1.5, 1.5 0, 0 0))'),
ST_Point(3, 2)
)
```

Output:

```
POLYGON ((0 0, 0 3, 4.5 3, 4.5 0, 0 0))
```

SQL Example:

```sql
SELECT ST_Scale(
ST_GeomFromWKT('POLYGON ((0 0, 0 1.5, 1.5 1.5, 1.5 0, 0 0))'),
ST_Point(3, 2), ST_Point(1, 2)
)
```

Output:

```
POLYGON ((-2 -2, -2 1, 2.5 1, 2.5 -2, -2 -2))
```

## ST_SetPoint

Introduction: Replace Nth point of linestring with given point. Index is 0-based. Negative index are counted backwards, e.g., -1 is last point.
Expand Down
69 changes: 69 additions & 0 deletions docs/api/snowflake/vector-data/Function.md
Original file line number Diff line number Diff line change
Expand Up @@ -2640,6 +2640,75 @@ Output:
+------------------------------------------------------------------------------------------------------------------------------+
```

## ST_Scale

Introduction: This function scales the geometry to a new size by multiplying the ordinates with the corresponding scaling factors provided as parameters `scaleX` and `scaleY`.

!!!Note
This function is designed for scaling 2D geometries. While it currently doesn't support scaling the Z and M coordinates, it preserves these values during the scaling operation.

Format: `ST_Scale(geometry: Geometry, scaleX: Double, scaleY: Double)`

SQL Example:

```sql
SELECT ST_Scale(
ST_GeomFromWKT('POLYGON ((0 0, 0 1.5, 1.5 1.5, 1.5 0, 0 0))'),
3, 2
)
```

Output:

```
POLYGON ((0 0, 0 3, 4.5 3, 4.5 0, 0 0))
```

## ST_ScaleGeom

Introduction: This function scales the input geometry (`geometry`) to a new size. It does this by multiplying the coordinates of the input geometry with corresponding values from another geometry (`factor`) representing the scaling factors.

To scale the geometry relative to a point other than the true origin (e.g., scaling a polygon in place using its centroid), you can use the three-geometry variant of this function. This variant requires an additional geometry (`origin`) representing the "false origin" for the scaling operation. If no `origin` is provided, the scaling occurs relative to the true origin, with all coordinates of the input geometry simply multiplied by the corresponding scale factors.

!!!Note
This function is designed for scaling 2D geometries. While it currently doesn't support scaling the Z and M coordinates, it preserves these values during the scaling operation.

Format:

`ST_ScaleGeom(geometry: Geometry, factor: Geometry, origin: Geometry)`

`ST_ScaleGeom(geometry: Geometry, factor: Geometry)`

SQL Example:

```sql
SELECT ST_Scale(
ST_GeomFromWKT('POLYGON ((0 0, 0 1.5, 1.5 1.5, 1.5 0, 0 0))'),
ST_Point(3, 2)
)
```

Output:

```
POLYGON ((0 0, 0 3, 4.5 3, 4.5 0, 0 0))
```

SQL Example:

```sql
SELECT ST_Scale(
ST_GeomFromWKT('POLYGON ((0 0, 0 1.5, 1.5 1.5, 1.5 0, 0 0))'),
ST_Point(3, 2), ST_Point(1, 2)
)
```

Output:

```
POLYGON ((-2 -2, -2 1, 2.5 1, 2.5 -2, -2 -2))
```

## ST_SetPoint

Introduction: Replace Nth point of linestring with given point. Index is 0-based. Negative index are counted backwards, e.g., -1 is last point.
Expand Down
73 changes: 73 additions & 0 deletions docs/api/sql/Function.md
Original file line number Diff line number Diff line change
Expand Up @@ -3510,6 +3510,79 @@ Output:
[POLYGON ((-36.609392788630245 -38.169532607255846, -36.609392706252954 -38.169532607255846, -36.609392706252954 -38.169532507473015, -36.609392788630245 -38.169532507473015, -36.609392788630245 -38.169532607255846))]
```

## ST_Scale

Introduction: This function scales the geometry to a new size by multiplying the ordinates with the corresponding scaling factors provided as parameters `scaleX` and `scaleY`.

!!!Note
This function is designed for scaling 2D geometries. While it currently doesn't support scaling the Z and M coordinates, it preserves these values during the scaling operation.

Format: `ST_Scale(geometry: Geometry, scaleX: Double, scaleY: Double)`

Since: `v1.7.0`

SQL Example:

```sql
SELECT ST_Scale(
ST_GeomFromWKT('POLYGON ((0 0, 0 1.5, 1.5 1.5, 1.5 0, 0 0))'),
3, 2
)
```

Output:

```
POLYGON ((0 0, 0 3, 4.5 3, 4.5 0, 0 0))
```

## ST_ScaleGeom

Introduction: This function scales the input geometry (`geometry`) to a new size. It does this by multiplying the coordinates of the input geometry with corresponding values from another geometry (`factor`) representing the scaling factors.

To scale the geometry relative to a point other than the true origin (e.g., scaling a polygon in place using its centroid), you can use the three-geometry variant of this function. This variant requires an additional geometry (`origin`) representing the "false origin" for the scaling operation. If no `origin` is provided, the scaling occurs relative to the true origin, with all coordinates of the input geometry simply multiplied by the corresponding scale factors.

!!!Note
This function is designed for scaling 2D geometries. While it currently doesn't support scaling the Z and M coordinates, it preserves these values during the scaling operation.

Format:

`ST_ScaleGeom(geometry: Geometry, factor: Geometry, origin: Geometry)`

`ST_ScaleGeom(geometry: Geometry, factor: Geometry)`

Since: `v1.7.0`

SQL Example:

```sql
SELECT ST_Scale(
ST_GeomFromWKT('POLYGON ((0 0, 0 1.5, 1.5 1.5, 1.5 0, 0 0))'),
ST_Point(3, 2)
)
```

Output:

```
POLYGON ((0 0, 0 3, 4.5 3, 4.5 0, 0 0))
```

SQL Example:

```sql
SELECT ST_Scale(
ST_GeomFromWKT('POLYGON ((0 0, 0 1.5, 1.5 1.5, 1.5 0, 0 0))'),
ST_Point(3, 2), ST_Point(1, 2)
)
```

Output:

```
POLYGON ((-2 -2, -2 1, 2.5 1, 2.5 -2, -2 -2))
```

## ST_SetPoint

Introduction: Replace Nth point of linestring with given point. Index is 0-based. Negative index are counted backwards, e.g., -1 is last point.
Expand Down
2 changes: 2 additions & 0 deletions flink/src/main/java/org/apache/sedona/flink/Catalog.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ public static UserDefinedFunction[] getFuncs() {
new Functions.ST_FlipCoordinates(),
new Functions.ST_GeoHash(),
new Functions.ST_PointOnSurface(),
new Functions.ST_Scale(),
new Functions.ST_ScaleGeom(),
new Functions.ST_ReducePrecision(),
new Functions.ST_Reverse(),
new Functions.ST_Rotate(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1977,6 +1977,44 @@ public String eval(
}
}

public static class ST_Scale extends ScalarFunction {
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
public Geometry eval(
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o,
@DataTypeHint(value = "Double") Double scaleX,
@DataTypeHint(value = "Double") Double scaleY) {
Geometry geometry = (Geometry) o;
return org.apache.sedona.common.Functions.scale(geometry, scaleX, scaleY);
}
}

public static class ST_ScaleGeom extends ScalarFunction {
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
public Geometry eval(
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
Object o1,
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
Object o2,
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
Object o3) {
Geometry geometry = (Geometry) o1;
Geometry factor = (Geometry) o2;
Geometry origin = (Geometry) o3;
return org.apache.sedona.common.Functions.scaleGeom(geometry, factor, origin);
}

@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
public Geometry eval(
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
Object o1,
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
Object o2) {
Geometry geometry = (Geometry) o1;
Geometry factor = (Geometry) o2;
return org.apache.sedona.common.Functions.scaleGeom(geometry, factor);
}
}

public static class ST_RotateX extends ScalarFunction {
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
public Geometry eval(
Expand Down
Loading

0 comments on commit d0f6e9f

Please sign in to comment.