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/10 07:11:19 UTC
(sedona) branch master updated: [SEDONA-422] Add a feature in RS_SetBandNoDataValue and fix NoDataValue in RS_Clip (#1081)
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 94d772773 [SEDONA-422] Add a feature in RS_SetBandNoDataValue and fix NoDataValue in RS_Clip (#1081)
94d772773 is described below
commit 94d772773bcf89e6f4cc3da5a7a0b7ee9c471978
Author: Furqaan Khan <46...@users.noreply.github.com>
AuthorDate: Fri Nov 10 02:11:14 2023 -0500
[SEDONA-422] Add a feature in RS_SetBandNoDataValue and fix NoDataValue in RS_Clip (#1081)
---
.../sedona/common/raster/RasterBandEditors.java | 35 ++++++++++++++++++---
.../common/raster/RasterBandEditorsTest.java | 36 +++++++++++++---------
docs/api/sql/Raster-operators.md | 4 +--
.../org/apache/sedona/sql/rasteralgebraTest.scala | 7 +++--
4 files changed, 59 insertions(+), 23 deletions(-)
diff --git a/common/src/main/java/org/apache/sedona/common/raster/RasterBandEditors.java b/common/src/main/java/org/apache/sedona/common/raster/RasterBandEditors.java
index da37429c7..3c2f36be9 100644
--- a/common/src/main/java/org/apache/sedona/common/raster/RasterBandEditors.java
+++ b/common/src/main/java/org/apache/sedona/common/raster/RasterBandEditors.java
@@ -40,10 +40,28 @@ import java.util.Arrays;
import java.util.Collections;
public class RasterBandEditors {
- public static GridCoverage2D setBandNoDataValue(GridCoverage2D raster, int bandIndex, double noDataValue) {
+ /**
+ * Adds no-data value to the raster.
+ * @param raster Source raster to add no-data value
+ * @param bandIndex Band index to add no-data value
+ * @param noDataValue Value to set as no-data value, if null then remove existing no-data value
+ * @return Raster with no-data value
+ */
+ public static GridCoverage2D setBandNoDataValue(GridCoverage2D raster, int bandIndex, Double noDataValue) {
RasterUtils.ensureBand(raster, bandIndex);
Double rasterNoData = RasterBandAccessors.getBandNoDataValue(raster, bandIndex);
- if ( !(rasterNoData == null) && rasterNoData == noDataValue) {
+
+ // Remove no-Data if it is null
+ if (noDataValue == null) {
+ if (RasterBandAccessors.getBandNoDataValue(raster) == null) {
+ return raster;
+ }
+ GridSampleDimension[] sampleDimensions = raster.getSampleDimensions();
+ sampleDimensions [bandIndex - 1] = RasterUtils.removeNoDataValue(sampleDimensions[bandIndex - 1]);
+ return RasterUtils.create(raster.getRenderedImage(), raster.getGridGeometry(), sampleDimensions, null);
+ }
+
+ if ( !(rasterNoData == null) && rasterNoData.equals(noDataValue)) {
return raster;
}
GridSampleDimension[] bands = raster.getSampleDimensions();
@@ -60,7 +78,13 @@ public class RasterBandEditors {
return RasterUtils.create(raster.getRenderedImage(), gridGeometry2D, bands, null);
}
- public static GridCoverage2D setBandNoDataValue(GridCoverage2D raster, double noDataValue) {
+ /**
+ * Adds no-data value to the raster.
+ * @param raster Source raster to add no-data value
+ * @param noDataValue Value to set as no-data value, if null then remove existing no-data value
+ * @return Raster with no-data value
+ */
+ public static GridCoverage2D setBandNoDataValue(GridCoverage2D raster, Double noDataValue) {
return setBandNoDataValue(raster, 1, noDataValue);
}
@@ -223,7 +247,10 @@ public class RasterBandEditors {
}
}
}
- newRaster = RasterUtils.create(resultRaster, raster.getGridGeometry(), newRaster.getSampleDimensions());
+ newRaster = RasterUtils.create(resultRaster, raster.getGridGeometry(), newRaster.getSampleDimensions(), noDataValue);
+ } else {
+ // to add no-data value
+ newRaster = RasterUtils.create(newRaster.getRenderedImage(), newRaster.getGridGeometry(), newRaster.getSampleDimensions(), noDataValue);
}
return newRaster;
diff --git a/common/src/test/java/org/apache/sedona/common/raster/RasterBandEditorsTest.java b/common/src/test/java/org/apache/sedona/common/raster/RasterBandEditorsTest.java
index 0901593bc..362a99d32 100644
--- a/common/src/test/java/org/apache/sedona/common/raster/RasterBandEditorsTest.java
+++ b/common/src/test/java/org/apache/sedona/common/raster/RasterBandEditorsTest.java
@@ -33,31 +33,39 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.*;
public class RasterBandEditorsTest extends RasterTestBase{
@Test
public void testSetBandNoDataValueWithRaster() throws IOException {
GridCoverage2D raster = rasterFromGeoTiff(resourceFolder + "raster/test1.tiff");
- GridCoverage2D grid = RasterBandEditors.setBandNoDataValue(raster, 1,3);
+ GridCoverage2D grid = RasterBandEditors.setBandNoDataValue(raster, 1,3d);
double actual = RasterBandAccessors.getBandNoDataValue(grid);
double expected = 3;
assertEquals(expected, actual, 0.1d);
assert(Arrays.equals(MapAlgebra.bandAsArray(raster, 1), MapAlgebra.bandAsArray(grid, 1)));
- grid = RasterBandEditors.setBandNoDataValue(raster, -999);
+ grid = RasterBandEditors.setBandNoDataValue(raster, -999d);
actual = RasterBandAccessors.getBandNoDataValue(grid);
expected = -999;
assertEquals(expected, actual, 0.1d);
assert(Arrays.equals(MapAlgebra.bandAsArray(raster, 1), MapAlgebra.bandAsArray(grid, 1)));
}
+ @Test
+ public void testSetBandNoDataValueWithNull() throws IOException {
+ GridCoverage2D raster = rasterFromGeoTiff(resourceFolder + "raster/raster_with_no_data/test5.tiff");
+ GridCoverage2D grid = RasterBandEditors.setBandNoDataValue(raster, 1,null);
+ String actual = Arrays.toString(grid.getSampleDimensions());
+ String expected = "[RenderedSampleDimension[\"PALETTE_INDEX\"]]";
+ assertEquals(expected, actual);
+ }
+
@Test
public void testSetBandNoDataValueWithEmptyRaster() throws FactoryException {
GridCoverage2D emptyRaster = RasterConstructors.makeEmptyRaster(1, 20, 20, 0, 0, 8, 8, 0.1, 0.1, 4326);
- GridCoverage2D grid = RasterBandEditors.setBandNoDataValue(emptyRaster, 1, 999);
+ GridCoverage2D grid = RasterBandEditors.setBandNoDataValue(emptyRaster, 1, 999d);
double actual = RasterBandAccessors.getBandNoDataValue(grid);
double expected = 999;
assertEquals(expected, actual, 0.1d);
@@ -71,8 +79,8 @@ public class RasterBandEditorsTest extends RasterTestBase{
@Test
public void testSetBandNoDataValueWithEmptyRasterMultipleBand() throws FactoryException {
GridCoverage2D emptyRaster = RasterConstructors.makeEmptyRaster(2, 20, 20, 0, 0, 8, 8, 0.1, 0.1, 0);
- GridCoverage2D grid = RasterBandEditors.setBandNoDataValue(emptyRaster, -9999);
- grid = RasterBandEditors.setBandNoDataValue(grid, 2, 444);
+ GridCoverage2D grid = RasterBandEditors.setBandNoDataValue(emptyRaster, -9999d);
+ grid = RasterBandEditors.setBandNoDataValue(grid, 2, 444d);
assertEquals(-9999, (double) RasterBandAccessors.getBandNoDataValue(grid), 0.1d);
assertEquals(444, (double) RasterBandAccessors.getBandNoDataValue(grid, 2), 0.1d);
}
@@ -89,7 +97,7 @@ public class RasterBandEditorsTest extends RasterTestBase{
assertArrayEquals(originalMetadata, clippedMetadata, 0.01d);
String actual = String.valueOf(clippedRaster.getSampleDimensions()[0]);
- String expected = String.valueOf(raster.getSampleDimensions()[0]);
+ String expected = "RenderedSampleDimension(\"RED_BAND\":[200.0 ... 200.0])\n ‣ Category(\"No data\":[200...200])\n";
assertEquals(expected, actual);
List<Geometry> points = new ArrayList<>();
@@ -98,9 +106,9 @@ public class RasterBandEditorsTest extends RasterTestBase{
points.add(Constructors.geomFromWKT("POINT(237201 4.20429e+06)", 26918));
points.add(Constructors.geomFromWKT("POINT(237919 4.20357e+06)", 26918));
points.add(Constructors.geomFromWKT("POINT(254668 4.21769e+06)", 26918));
- double[] actualValues = PixelFunctions.values(clippedRaster, points, 1).stream().mapToDouble(d -> d).toArray();
- double[] expectedValues = new double[] {200.0, 200.0, 0.0, 0.0, 200.0};
- assertArrayEquals(expectedValues, actualValues, 0.001d);
+ Double[] actualValues = PixelFunctions.values(clippedRaster, points, 1).toArray(new Double[0]);
+ Double[] expectedValues = new Double[] {null, null, 0.0, 0.0, null};
+ assertTrue(Arrays.equals(expectedValues, actualValues));
GridCoverage2D croppedRaster = RasterBandEditors.clip(raster, 1, geom, 200, true);
points = new ArrayList<>();
@@ -109,9 +117,9 @@ public class RasterBandEditorsTest extends RasterTestBase{
points.add(Constructors.geomFromWKT("POINT(237201 4.20429e+06)", 26918));
points.add(Constructors.geomFromWKT("POINT(237919 4.20357e+06)", 26918));
points.add(Constructors.geomFromWKT("POINT(223802 4.20465e+06)", 26918));
- actualValues = PixelFunctions.values(croppedRaster, points, 1).stream().mapToDouble(d -> d).toArray();
- expectedValues = new double[] {0.0, 0.0, 0.0, 0.0, 200.0};
- assertArrayEquals(expectedValues, actualValues, 0.001d);
+ actualValues = PixelFunctions.values(croppedRaster, points, 1).toArray(new Double[0]);
+ expectedValues = new Double[] {0.0, 0.0, 0.0, 0.0, null};
+ assertTrue(Arrays.equals(expectedValues, actualValues));
}
@Test
diff --git a/docs/api/sql/Raster-operators.md b/docs/api/sql/Raster-operators.md
index 02ee063b3..8eef3a2be 100644
--- a/docs/api/sql/Raster-operators.md
+++ b/docs/api/sql/Raster-operators.md
@@ -1069,8 +1069,6 @@ Introduction: Returns a raster that is clipped by the given geometry.
If `crop` is not specified then it will default to `true`, meaning it will make the resulting raster shrink to the geometry's extent and if `noDataValue` is not specified then the resulting raster will have the minimum possible value for the band pixel data type.
-!!!note
- When `crop` is `true`, no new raster is created - instead a viewpoint to the source raster is returned, and when `false`, a new raster is generated.
Format:
@@ -1291,7 +1289,7 @@ Output:
### RS_SetBandNoDataValue
-Introduction: Sets no data value for given band. If band index not specified then band 1 is assumed.
+Introduction: This sets the no data value for a specified band in the raster. If the band index is not provided, band 1 is assumed by default. Passing a `null` value for `noDataValue` will remove the no data value and that will ensure all pixels are included in functions rather than excluded as no data.
Format: `RS_SetBandNoDataValue(raster: Raster, bandIndex: Integer = 1, noDataValue: Double)`
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 eb37f1425..6e77a1ba7 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
@@ -451,6 +451,9 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen
val actual = df.selectExpr("RS_BandNoDataValue(RS_SetBandNoDataValue(raster, 1, -999))").first().getDouble(0)
val expected = -999
assertEquals(expected, actual, 0.001d)
+
+ val actualNull = df.selectExpr("RS_BandNoDataValue(RS_SetBandNoDataValue(raster, 1, null))").first().get(0)
+ assertNull(actualNull)
}
it("Passed RS_SetBandNoDataValue with empty raster") {
@@ -540,7 +543,7 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen
"ST_GeomFromWKT('POINT(237201 4.20429e+06)'),ST_GeomFromWKT('POINT(237919 4.20357e+06)')," +
"ST_GeomFromWKT('POINT(254668 4.21769e+06)')), 1)"
).first().get(0)
- var expectedValues = Seq(200.0, 200.0, 0.0, 0.0, 200.0)
+ var expectedValues = Seq(null, null, 0.0, 0.0, null)
assertTrue(expectedValues.equals(actualValues))
val croppedDf = df.selectExpr("RS_Clip(raster, 1, geom, 200, false) as cropped")
@@ -550,7 +553,7 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen
"ST_GeomFromWKT('POINT(237201 4.20429e+06)'),ST_GeomFromWKT('POINT(237919 4.20357e+06)')," +
"ST_GeomFromWKT('POINT(223802 4.20465e+06)')), 1)"
).first().get(0)
- expectedValues = Seq(0.0, 0.0, 0.0, 0.0, 200.0)
+ expectedValues = Seq(0.0, 0.0, 0.0, 0.0, null)
assertTrue(expectedValues.equals(actualValues))
}