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/08/29 00:08:56 UTC

[sedona] branch master updated: [SEDONA-378] Add RS_SetValue (#990)

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 43c53707b [SEDONA-378] Add RS_SetValue (#990)
43c53707b is described below

commit 43c53707bd87221c9f8a1c925d6167d2322f105d
Author: Furqaanahmed Khan <46...@users.noreply.github.com>
AuthorDate: Mon Aug 28 20:08:51 2023 -0400

    [SEDONA-378] Add RS_SetValue (#990)
---
 .../sedona/common/raster/PixelFunctionEditors.java | 12 ++++++++
 .../sedona/common/raster/FunctionEditorsTest.java  | 26 +++++++++++++----
 docs/api/sql/Raster-operators.md                   | 34 +++++++++++++++++++++-
 .../scala/org/apache/sedona/sql/UDF/Catalog.scala  |  1 +
 .../expressions/raster/PixelFunctionEditors.scala  |  9 ++++++
 .../org/apache/sedona/sql/rasteralgebraTest.scala  | 17 +++++++++--
 6 files changed, 91 insertions(+), 8 deletions(-)

diff --git a/common/src/main/java/org/apache/sedona/common/raster/PixelFunctionEditors.java b/common/src/main/java/org/apache/sedona/common/raster/PixelFunctionEditors.java
index 66db6fe13..cd4a687d1 100644
--- a/common/src/main/java/org/apache/sedona/common/raster/PixelFunctionEditors.java
+++ b/common/src/main/java/org/apache/sedona/common/raster/PixelFunctionEditors.java
@@ -46,6 +46,10 @@ public class PixelFunctionEditors {
         if (keepNoData) {
             noDataValue = RasterBandAccessors.getBandNoDataValue(raster, band);
         }
+
+        // making them 0-indexed
+        colX--; rowY--;
+      
         int iterator = 0;
         for (int j = rowY; j < rowY + height; j++) {
             for (int i = colX; i < colX + width; i++) {
@@ -66,4 +70,12 @@ public class PixelFunctionEditors {
     public static GridCoverage2D setValues(GridCoverage2D raster, int band, int colX, int rowY, int width, int height, double[] values) {
         return setValues(raster, band, colX, rowY, width, height, values, false);
     }
+  
+    public static GridCoverage2D setValue(GridCoverage2D raster, int band, int colX, int rowY, double newValue) {
+        return setValues(raster, band, colX, rowY, 1, 1, new double[]{newValue}, false);
+    }
+
+    public static GridCoverage2D setValue(GridCoverage2D raster, int colX, int rowY, double newValue) {
+        return setValues(raster, 1, colX, rowY, 1, 1, new double[]{newValue}, false);
+    }
 }
diff --git a/common/src/test/java/org/apache/sedona/common/raster/FunctionEditorsTest.java b/common/src/test/java/org/apache/sedona/common/raster/FunctionEditorsTest.java
index 516f07e62..c5292dd39 100644
--- a/common/src/test/java/org/apache/sedona/common/raster/FunctionEditorsTest.java
+++ b/common/src/test/java/org/apache/sedona/common/raster/FunctionEditorsTest.java
@@ -22,26 +22,42 @@ import org.geotools.coverage.grid.GridCoverage2D;
 import org.junit.Test;
 import org.opengis.referencing.FactoryException;
 
-import java.util.Arrays;
-
 import static org.junit.Assert.*;
 
 public class FunctionEditorsTest extends RasterTestBase {
 
     @Test
-    public void testSetValueWithEmptyRaster() throws FactoryException {
+    public void testSetValuesWithEmptyRaster() throws FactoryException {
         GridCoverage2D emptyRaster = RasterConstructors.makeEmptyRaster(1, 5, 5, 0, 0, 1, -1, 0, 0, 0);
         double[] values = new double[] {1,1,1,0,0,0,1,2,3,3,5,6,7,0,0,3,0,0,3,0,0,0,0,0,0};
         emptyRaster = MapAlgebra.addBandFromArray(emptyRaster, values, 1, 0d);
         double[] newValues = new double[] {11,12,13,14,15,16,17,18,19};
         GridCoverage2D raster = PixelFunctionEditors.setValues(emptyRaster, 1, 2, 2, 3, 3, newValues, true);
         double[] actual = MapAlgebra.bandAsArray(raster, 1);
-        double[] expected = new double[] {1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 5.0, 6.0, 11.0, 0.0, 0.0, 3.0, 0.0, 0.0, 15.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
+        double[] expected = new double[] {1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 11.0, 12.0, 13.0, 3.0, 5.0, 14.0, 15.0, 0.0, 0.0, 3.0, 0.0, 0.0, 19.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
         assertArrayEquals(actual, expected, 0.0);
 
         raster = PixelFunctionEditors.setValues(emptyRaster, 1, 2, 2, 3, 3, newValues);
         actual = MapAlgebra.bandAsArray(raster, 1);
-        expected = new double[] {1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 5.0, 6.0, 11.0, 12.0, 13.0, 3.0, 0.0, 14.0, 15.0, 16.0, 0.0, 0.0, 17.0, 18.0, 19.0};
+        expected = new double[] {1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 11.0, 12.0, 13.0, 3.0, 5.0, 14.0, 15.0, 16.0, 0.0, 3.0, 17.0, 18.0, 19.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
         assertArrayEquals(actual, expected, 0.0);
     }
+
+    @Test
+    public void testSetValueWithEmptyRaster() throws FactoryException {
+        GridCoverage2D emptyRaster = RasterConstructors.makeEmptyRaster(1, 5, 5, 0, 0, 1, -1, 0, 0, 0);
+        double[] values = new double[] {1,1,1,0,0,0,1,2,3,3,5,6,7,0,0,3,0,0,3,0,0,0,0,0,0};
+        emptyRaster = MapAlgebra.addBandFromArray(emptyRaster, values, 1, 0d);
+        double newValue = 1777;
+        GridCoverage2D raster = PixelFunctionEditors.setValue(emptyRaster, 1, 2, 2, newValue);
+        double[] actual = MapAlgebra.bandAsArray(raster, 1);
+        double[] expected = new double[]{1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1777.0, 2.0, 3.0, 3.0, 5.0, 6.0, 7.0, 0.0, 0.0, 3.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
+        assertArrayEquals(expected, actual, 0.1d);
+
+        newValue = 8723;
+        raster = PixelFunctionEditors.setValue(emptyRaster, 2, 2, newValue);
+        actual = MapAlgebra.bandAsArray(raster, 1);
+        expected = new double[]{1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 8723.0, 2.0, 3.0, 3.0, 5.0, 6.0, 7.0, 0.0, 0.0, 3.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
+        assertArrayEquals(expected, actual, 0.1d);
+    }
 }
diff --git a/docs/api/sql/Raster-operators.md b/docs/api/sql/Raster-operators.md
index 3fe33532b..16ff2a806 100644
--- a/docs/api/sql/Raster-operators.md
+++ b/docs/api/sql/Raster-operators.md
@@ -963,6 +963,38 @@ Output:
 -3.000000
 ```
 
+### RS_SetValue
+
+Introduction: Returns a raster by replacing the value of pixel specified by `colX` and `rowY`.
+
+Format: 
+
+```
+RS_SetValue(raster: Raster, bandIndex: Integer = 1, colX: Integer, rowY: Integer, newValue: Double)
+```
+
+Since: `v1.5.0`
+
+Spark SQL Example:
+
+```sql
+SELECT RS_BandAsArray(
+               RS_SetValue(
+                       RS_AddBandFromArray(
+                               RS_MakeEmptyRaster(1, 5, 5, 0, 0, 1, -1, 0, 0, 0),
+                           [1,1,1,0,0,0,1,2,3,3,5,6,7,0,0,3,0,0,3,0,0,0,0,0,0], 1, 0d
+                           ),
+                       1, 2, 2, 255
+                   )
+           )
+```
+
+Output:
+
+```
+[1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 255.0, 2.0, 3.0, 3.0, 5.0, 6.0, 7.0, 0.0, 0.0, 3.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
+```
+
 ### RS_SetValues
 
 Introduction: Returns a raster by replacing the values of pixels in a specified rectangular region. The top left 
@@ -1004,7 +1036,7 @@ SELECT RS_BandAsArray(
 Output:
 
 ```
-[1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 5.0, 6.0, 11.0, 12.0, 13.0, 3.0, 0.0, 14.0, 15.0, 16.0, 0.0, 0.0, 17.0, 18.0, 19.0]
+[1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 11.0, 12.0, 13.0, 3.0, 5.0, 14.0, 15.0, 16.0, 0.0, 3.0, 17.0, 18.0, 19.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
 ```
 
 ### RS_SetSRID
diff --git a/sql/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala b/sql/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
index fd8a62611..ee104a411 100644
--- a/sql/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
+++ b/sql/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
@@ -205,6 +205,7 @@ object Catalog {
     function[RS_SetGeoReference](),
     function[RS_SetBandNoDataValue](),
     function[RS_SetValues](),
+    function[RS_SetValue](),
     function[RS_SRID](),
     function[RS_Value](1),
     function[RS_Values](1),
diff --git a/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/PixelFunctionEditors.scala b/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/PixelFunctionEditors.scala
index 94fdf8de3..824f9a7b2 100644
--- a/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/PixelFunctionEditors.scala
+++ b/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/PixelFunctionEditors.scala
@@ -30,4 +30,13 @@ case class RS_SetValues(inputExpressions: Seq[Expression]) extends InferredExpre
   protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
     copy(inputExpressions = newChildren)
   }
+}
+
+case class RS_SetValue(inputExpressions: Seq[Expression]) extends InferredExpression(
+  inferrableFunction5(PixelFunctionEditors.setValue),
+  inferrableFunction4(PixelFunctionEditors.setValue)
+) {
+  protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
+    copy(inputExpressions = newChildren)
+  }
 }
\ No newline at end of file
diff --git a/sql/common/src/test/scala/org/apache/sedona/sql/rasteralgebraTest.scala b/sql/common/src/test/scala/org/apache/sedona/sql/rasteralgebraTest.scala
index 1704b081c..581c66223 100644
--- a/sql/common/src/test/scala/org/apache/sedona/sql/rasteralgebraTest.scala
+++ b/sql/common/src/test/scala/org/apache/sedona/sql/rasteralgebraTest.scala
@@ -345,11 +345,24 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen
       var inputDf = Seq((Seq(1, 1, 1, 0, 0, 0, 1, 2, 3, 3, 5, 6, 7, 0, 0, 3, 0, 0, 3, 0, 0, 0, 0, 0, 0), Seq(11, 12, 13, 14, 15, 16, 17, 18, 19))).toDF("band","newValues")
       var df = inputDf.selectExpr("RS_AddBandFromArray(RS_MakeEmptyRaster(1, 5, 5, 0, 0, 1, -1, 0, 0, 0), band, 1, 0d) as raster", "newValues")
       var actual = df.selectExpr("RS_BandAsArray(RS_SetValues(raster,  1, 2, 2, 3, 3, newValues, true), 1)").first().getSeq(0)
-      var expected = Seq(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 5.0, 6.0, 11.0, 0.0, 0.0, 3.0, 0.0, 0.0, 15.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
+      var expected = Seq(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 11.0, 12.0, 13.0, 3.0, 5.0, 14.0, 15.0, 0.0, 0.0, 3.0, 0.0, 0.0, 19.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
       assert(expected.equals(actual))
 
       actual = df.selectExpr("RS_BandAsArray(RS_SetValues(raster,  1, 2, 2, 3, 3, newValues), 1)").first().getSeq(0)
-      expected = Seq(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 5.0, 6.0, 11.0, 12.0, 13.0, 3.0, 0.0, 14.0, 15.0, 16.0, 0.0, 0.0, 17.0, 18.0, 19.0)
+      expected = Seq(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 11.0, 12.0, 13.0, 3.0, 5.0, 14.0, 15.0, 16.0, 0.0, 3.0, 17.0, 18.0, 19.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
+      assert(expected.equals(actual))
+    }
+
+    it("Passed RS_SetValue with empty raster") {
+      var inputDF = Seq((Seq(1, 1, 1, 0, 0, 0, 1, 2, 3, 3, 5, 6, 7, 0, 0, 3, 0, 0, 3, 0, 0, 0, 0, 0, 0))).toDF("band")
+      var df = inputDF.selectExpr("RS_AddBandFromArray(RS_MakeEmptyRaster(1, 5, 5, 0, 0, 1, -1, 0, 0, 0), " +
+        "band, 1, 0d) as raster")
+      var actual = df.selectExpr("RS_BandAsArray(RS_SetValue(raster,  1, 2, 2, 255), 1)").first().getSeq(0)
+      var expected = Seq(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 255.0, 2.0, 3.0, 3.0, 5.0, 6.0, 7.0, 0.0, 0.0, 3.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
+      assert(expected.equals(actual))
+
+      actual = df.selectExpr("RS_BandAsArray(RS_SetValue(raster, 2, 2, 156), 1)").first().getSeq(0)
+      expected = Seq(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 156.0, 2.0, 3.0, 3.0, 5.0, 6.0, 7.0, 0.0, 0.0, 3.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
       assert(expected.equals(actual))
     }