You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sedona.apache.org by ji...@apache.org on 2023/11/17 00:36:29 UTC

(sedona) branch master updated: [SEDONA-427] Add RS_RasterToWorldCoord (#1123)

This is an automated email from the ASF dual-hosted git repository.

jiayu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sedona.git


The following commit(s) were added to refs/heads/master by this push:
     new 1ed05805e [SEDONA-427] Add RS_RasterToWorldCoord (#1123)
1ed05805e is described below

commit 1ed05805e0374fc7be37ba67c0d9aed0ac7de0b8
Author: Pranav Toggi <pr...@gmail.com>
AuthorDate: Thu Nov 16 19:36:24 2023 -0500

    [SEDONA-427] Add RS_RasterToWorldCoord (#1123)
---
 .../sedona/common/raster/RasterAccessors.java      |  8 +++++-
 .../sedona/common/raster/RasterAccessorsTest.java  | 32 ++++++++++++++++++++++
 docs/api/sql/Raster-operators.md                   | 20 ++++++++++++++
 .../scala/org/apache/sedona/sql/UDF/Catalog.scala  |  1 +
 .../expressions/raster/RasterAccessors.scala       |  7 +++++
 .../org/apache/sedona/sql/rasteralgebraTest.scala  |  8 ++++++
 6 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/common/src/main/java/org/apache/sedona/common/raster/RasterAccessors.java b/common/src/main/java/org/apache/sedona/common/raster/RasterAccessors.java
index 20062d425..4d04bd0a5 100644
--- a/common/src/main/java/org/apache/sedona/common/raster/RasterAccessors.java
+++ b/common/src/main/java/org/apache/sedona/common/raster/RasterAccessors.java
@@ -32,7 +32,7 @@ import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.operation.TransformException;
 
-import java.awt.image.RenderedImage;
+import java.awt.geom.Point2D;
 import java.util.Arrays;
 import java.util.Set;
 
@@ -106,6 +106,12 @@ public class RasterAccessors
         return RasterUtils.getWorldCornerCoordinates(raster, colX, rowY).getY();
     }
 
+    public static Geometry getWorldCoord(GridCoverage2D raster, int colX, int rowY) throws TransformException {
+        Point2D worldCoords = RasterUtils.getWorldCornerCoordinates(raster, colX, rowY);
+        Geometry point = new GeometryFactory().createPoint(new Coordinate(worldCoords.getX(), worldCoords.getY()));
+        return point;
+    }
+
     public static String getGeoReference(GridCoverage2D raster) {
         return getGeoReference(raster, "GDAL");
     }
diff --git a/common/src/test/java/org/apache/sedona/common/raster/RasterAccessorsTest.java b/common/src/test/java/org/apache/sedona/common/raster/RasterAccessorsTest.java
index 2193225f0..5dac999c9 100644
--- a/common/src/test/java/org/apache/sedona/common/raster/RasterAccessorsTest.java
+++ b/common/src/test/java/org/apache/sedona/common/raster/RasterAccessorsTest.java
@@ -155,6 +155,38 @@ public class RasterAccessorsTest extends RasterTestBase
         assertEquals(expectedY, actualY, 0.1d);
     }
 
+    @Test
+    public void testWorldCoord() throws FactoryException, TransformException {
+        int colX = 1, rowY = 1;
+        GridCoverage2D emptyRaster = RasterConstructors.makeEmptyRaster(1, 5, 10, -123, 54, 5, -10, 0, 0, 4326);
+
+        Coordinate actual = RasterAccessors.getWorldCoord(emptyRaster, colX, rowY).getCoordinate();
+        double expectedX = -123, expectedY = 54;
+
+        assertEquals(expectedX, actual.getX(), 0.1d);
+        assertEquals(expectedY, actual.getY(), 0.1d);
+
+        rowY = 2;
+        actual = RasterAccessors.getWorldCoord(emptyRaster, colX, rowY).getCoordinate();
+        expectedY = 44;
+
+        assertEquals(expectedX, actual.getX(), 0.1d);
+        assertEquals(expectedY, actual.getY(), 0.1d);
+    }
+
+    @Test
+    public void testWorldCoordOutOfBounds() throws FactoryException, TransformException{
+        int colX = 4;
+        int rowY = 11;
+        GridCoverage2D emptyRaster = RasterConstructors.makeEmptyRaster(1, 5, 10, -123, 54, 5, -10, 0, 0, 4326);
+
+        double expectedX = -108, expectedY = -46;
+        Coordinate actual = RasterAccessors.getWorldCoord(emptyRaster, colX, rowY).getCoordinate();
+
+        assertEquals(expectedX, actual.getX(), 0.1d);
+        assertEquals(expectedY, actual.getY(), 0.1d);
+    }
+
     @Test
     public void testGridCoordLatLon() throws TransformException, FactoryException {
         double longitude = -123, latitude = 54;
diff --git a/docs/api/sql/Raster-operators.md b/docs/api/sql/Raster-operators.md
index 697c21af0..55d0a8d57 100644
--- a/docs/api/sql/Raster-operators.md
+++ b/docs/api/sql/Raster-operators.md
@@ -384,6 +384,26 @@ Output:
 54
 ```
 
+### RS_RasterToWorldCoord
+
+Introduction: Returns the upper left X and Y coordinates of the given row and column of the given raster geometric units of the geo-referenced raster as a Point geometry. If any out of bounds values are given, the X and Y coordinates of the assumed point considering existing raster pixel size and skew values will be returned.
+
+Format: `RS_RasterToWorldCoord(raster: Raster, colX: Integer, rowY: Integer)`
+
+Since: `v1.5.1`
+
+Spark SQL Example:
+
+```sql
+SELECT RS_RasterToWorldCoord(ST_MakeEmptyRaster(1, 5, 10, -123, 54, 5, -10, 0, 0, 4326), 1, 1) from rasters
+```
+
+Output:
+
+```
+POINT (-123 54)
+```
+
 ### RS_Rotation
 
 Introduction: Returns the uniform rotation of the raster in radian.
diff --git a/spark/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala b/spark/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
index 75f30016c..3a176db8d 100644
--- a/spark/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
+++ b/spark/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
@@ -240,6 +240,7 @@ object Catalog {
     function[RS_ConvexHull](),
     function[RS_RasterToWorldCoordX](),
     function[RS_RasterToWorldCoordY](),
+    function[RS_RasterToWorldCoord](),
     function[RS_Within](),
     function[RS_Contains](),
     function[RS_WorldToRasterCoord](),
diff --git a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/RasterAccessors.scala b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/RasterAccessors.scala
index e6f13eb3f..f0039c6af 100644
--- a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/RasterAccessors.scala
+++ b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/RasterAccessors.scala
@@ -121,6 +121,13 @@ case class RS_RasterToWorldCoordY(inputExpressions: Seq[Expression]) extends Inf
     copy(inputExpressions = newChildren)
   }
 }
+
+case class RS_RasterToWorldCoord(inputExpressions: Seq[Expression]) extends InferredExpression(RasterAccessors.getWorldCoord _) {
+  protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
+    copy(inputExpressions = newChildren)
+  }
+}
+
 case class RS_WorldToRasterCoord(inputExpressions: Seq[Expression]) extends InferredExpression(inferrableFunction3(RasterAccessors.getGridCoord), inferrableFunction2(RasterAccessors.getGridCoord)) {
   protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
     copy(inputExpressions = newChildren)
diff --git a/spark/common/src/test/scala/org/apache/sedona/sql/rasteralgebraTest.scala b/spark/common/src/test/scala/org/apache/sedona/sql/rasteralgebraTest.scala
index d855e145d..018ed42f6 100644
--- a/spark/common/src/test/scala/org/apache/sedona/sql/rasteralgebraTest.scala
+++ b/spark/common/src/test/scala/org/apache/sedona/sql/rasteralgebraTest.scala
@@ -969,6 +969,14 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen
       assertEquals(4021262.7487925636, result, 0.5d)
     }
 
+    it("Passed RS_RasterToWorldCoord with raster") {
+      var df = sparkSession.read.format("binaryFile").load(resourceFolder + "raster/test1.tiff")
+      df = df.selectExpr("RS_FromGeoTiff(content) as raster")
+      val result = df.selectExpr("RS_RasterToWorldCoord(raster, 1, 1)").first().get(0).toString
+      val expected = "POINT (-13095818 4021262.75)"
+      assertEquals(expected, result)
+    }
+
     it("Passed RS_WorldToRasterCoord with raster") {
       var df = sparkSession.read.format("binaryFile").load(resourceFolder + "raster/test1.tiff")
       df = df.selectExpr("RS_FromGeoTiff(content) as raster")