From cbdc218917dd99de9767ee37f594e5ab81e6bd10 Mon Sep 17 00:00:00 2001 From: Kristin Cowalcijk Date: Mon, 5 Aug 2024 21:20:36 +0800 Subject: [PATCH] Add tileWidth and tileHeight to the result of RS_Metadata; Changed the data types of fields of the result struct of RS_Metadata --- .../sedona/common/raster/RasterAccessors.java | 74 +++++++++++- .../common/raster/RasterAccessorsTest.java | 31 ++++- .../common/raster/RasterEditorsTest.java | 22 ++-- docs/api/sql/Raster-operators.md | 8 +- .../expressions/raster/RasterFunctions.scala | 26 +++- .../apache/sedona/sql/rasteralgebraTest.scala | 114 +++++++++--------- 6 files changed, 194 insertions(+), 81 deletions(-) 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 0baccaff06..cdf08d56a2 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 @@ -19,6 +19,7 @@ package org.apache.sedona.common.raster; import java.awt.geom.Point2D; +import java.awt.image.RenderedImage; import java.util.Arrays; import java.util.Set; import org.apache.sedona.common.utils.RasterUtils; @@ -266,6 +267,7 @@ public static double[] metadata(GridCoverage2D raster) throws FactoryException { // Get Geo-reference metadata GridEnvelope2D gridRange = raster.getGridGeometry().getGridRange2D(); AffineTransform2D affine = RasterUtils.getGDALAffineTransform(raster); + RenderedImage image = raster.getRenderedImage(); // Get the affine parameters double upperLeftX = affine.getTranslateX(); @@ -274,6 +276,8 @@ public static double[] metadata(GridCoverage2D raster) throws FactoryException { double scaleY = affine.getScaleY(); double skewX = affine.getShearX(); double skewY = affine.getShearY(); + double tileWidth = image.getTileWidth(); + double tileHeight = image.getTileHeight(); return new double[] { upperLeftX, upperLeftY, @@ -284,7 +288,75 @@ public static double[] metadata(GridCoverage2D raster) throws FactoryException { skewX, skewY, srid(raster), - raster.getNumSampleDimensions() + raster.getNumSampleDimensions(), + tileWidth, + tileHeight }; } + + public static class RasterMetadata { + public double upperLeftX; + public double upperLeftY; + public int gridWidth; + public int gridHeight; + public double scaleX; + public double scaleY; + public double skewX; + public double skewY; + public int srid; + public int numBands; + public int tileWidth; + public int tileHeight; + + public RasterMetadata( + double upperLeftX, + double upperLeftY, + int gridWidth, + int gridHeight, + double scaleX, + double scaleY, + double skewX, + double skewY, + int srid, + int numBands, + int tileWidth, + int tileHeight) { + this.upperLeftX = upperLeftX; + this.upperLeftY = upperLeftY; + this.gridWidth = gridWidth; + this.gridHeight = gridHeight; + this.scaleX = scaleX; + this.scaleY = scaleY; + this.skewX = skewX; + this.skewY = skewY; + this.srid = srid; + this.numBands = numBands; + this.tileWidth = tileWidth; + this.tileHeight = tileHeight; + } + } + + /** + * Returns the metadata of a raster as a {@link RasterMetadata} object. + * + * @param raster the raster + * @return a {@link RasterMetadata} object + * @throws FactoryException + */ + public static RasterMetadata rasterMetadata(GridCoverage2D raster) throws FactoryException { + double[] meta = metadata(raster); + return new RasterMetadata( + meta[0], + meta[1], + (int) meta[2], + (int) meta[3], + meta[4], + meta[5], + meta[6], + meta[7], + (int) meta[8], + (int) meta[9], + (int) meta[10], + (int) meta[11]); + } } 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 8bc26fc17f..f1a256d2c4 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 @@ -379,7 +379,9 @@ public void testMetaData() throws FactoryException { assertEquals(0, metadata[7], 1e-9); assertEquals(0, metadata[8], 1e-9); assertEquals(numBands, metadata[9], 1e-9); - assertEquals(10, metadata.length); + assertEquals(widthInPixel, metadata[10], 1e-9); + assertEquals(heightInPixel, metadata[11], 1e-9); + assertEquals(12, metadata.length); upperLeftX = 5; upperLeftY = 6; @@ -404,8 +406,29 @@ public void testMetaData() throws FactoryException { assertEquals(0, metadata[7], 1e-9); assertEquals(0, metadata[8], 1e-9); assertEquals(numBands, metadata[9], 1e-9); + assertEquals(widthInPixel, metadata[10], 1e-9); + assertEquals(heightInPixel, metadata[11], 1e-9); - assertEquals(10, metadata.length); + assertEquals(12, metadata.length); + } + + @Test + public void testMetadataOfTiledRasters() throws IOException, FactoryException { + GridCoverage2D raster = rasterFromGeoTiff(resourceFolder + "raster/test1.tiff"); + double[] metadata = RasterAccessors.metadata(raster); + assertEquals(-13095817.809, metadata[0], 0.01); + assertEquals(4021262.749, metadata[1], 0.01); + assertEquals(512, metadata[2], 1e-9); + assertEquals(517, metadata[3], 1e-9); + assertEquals(72.328612721326948, metadata[4], 0.001); + assertEquals(-72.328612721326948, metadata[5], 0.001); + assertEquals(0, metadata[6], 1e-9); + assertEquals(0, metadata[7], 1e-9); + assertEquals(3857, metadata[8], 1e-9); + assertEquals(1, metadata[9], 1e-9); + assertEquals(256, metadata[10], 1e-9); + assertEquals(256, metadata[11], 1e-9); + assertEquals(12, metadata.length); } @Test @@ -443,6 +466,8 @@ public void testMetaDataUsingSkewedRaster() throws FactoryException { assertEquals(skewY, metadata[7], 1e-9); assertEquals(3857, metadata[8], 1e-9); assertEquals(numBands, metadata[9], 1e-9); - assertEquals(10, metadata.length); + assertEquals(widthInPixel, metadata[10], 1e-9); + assertEquals(heightInPixel, metadata[11], 1e-9); + assertEquals(12, metadata.length); } } diff --git a/common/src/test/java/org/apache/sedona/common/raster/RasterEditorsTest.java b/common/src/test/java/org/apache/sedona/common/raster/RasterEditorsTest.java index 378f9783f9..809052d3f2 100644 --- a/common/src/test/java/org/apache/sedona/common/raster/RasterEditorsTest.java +++ b/common/src/test/java/org/apache/sedona/common/raster/RasterEditorsTest.java @@ -3600,7 +3600,7 @@ public void testResample() throws FactoryException, TransformException { -0.33333333333333326, 0.19999999999999996, 6, 5, 1.388888888888889, -1.24, 0, 0, 0, 1 }; // verify correct raster geometry - for (int i = 0; i < metadata.length; i++) { + for (int i = 0; i < expectedMetadata.length; i++) { assertEquals(expectedMetadata[i], metadata[i], 1e-6); } @@ -3621,7 +3621,7 @@ public void testResample() throws FactoryException, TransformException { -0.20000000298023224, 0.4000000059604645, 7.0, 5.0, 1.2, -1.4, 0.0, 0.0, 0.0, 1.0 }; // verify correct raster geometry - for (int i = 0; i < metadata.length; i++) { + for (int i = 0; i < expectedMetadata.length; i++) { assertEquals(expectedMetadata[i], metadata[i], 1e-6); } } @@ -3679,7 +3679,7 @@ public void testResampleNoDataValueHandled() throws FactoryException, TransformE }; assertEquals(expectedRes1, res1); assertEquals(expectedRes2, res2); - for (int i = 0; i < metadata.length; i++) { + for (int i = 0; i < expectedMetadata.length; i++) { assertEquals(expectedMetadata[i], metadata[i], 1e-6); } @@ -3716,7 +3716,7 @@ public void testResampleNoDataValueHandled() throws FactoryException, TransformE }; assertEquals(expectedRes1, res1); assertEquals(expectedRes2, res2); - for (int i = 0; i < metadata.length; i++) { + for (int i = 0; i < expectedMetadata.length; i++) { assertEquals(expectedMetadata[i], metadata[i], 1e-6); } @@ -3749,7 +3749,7 @@ public void testResampleNoDataValueHandled() throws FactoryException, TransformE }; assertEquals(expectedRes1, res1); assertEquals(expectedRes2, res2); - for (int i = 0; i < metadata.length; i++) { + for (int i = 0; i < expectedMetadata.length; i++) { assertEquals(expectedMetadata[i], metadata[i], 1e-6); } } @@ -3772,7 +3772,7 @@ public void testResampleResizeFlavor() throws FactoryException, TransformExcepti double[] metadata = RasterAccessors.metadata(newRaster); double[] expectedMetadata = {0, 0, 6, 5, 1.3333333333333333, -1.2, 0, 0, 0, 1}; // verify correct raster geometry - for (int i = 0; i < metadata.length; i++) { + for (int i = 0; i < expectedMetadata.length; i++) { assertEquals(expectedMetadata[i], metadata[i], 1e-6); } @@ -3790,7 +3790,7 @@ public void testResampleResizeFlavor() throws FactoryException, TransformExcepti metadata = RasterAccessors.metadata(newRaster); expectedMetadata = new double[] {0, 0, 7, 5, 1.2, -1.4, 0, 0, 0, 1}; // verify correct raster geometry - for (int i = 0; i < metadata.length; i++) { + for (int i = 0; i < expectedMetadata.length; i++) { assertEquals(expectedMetadata[i], metadata[i], 1e-6); } } @@ -3819,7 +3819,7 @@ public void testResampleRefRaster() throws FactoryException, TransformException -0.33333333333333326, 0.19999999999999996, 6, 5, 1.388888888888889, -1.24, 0, 0, 0, 1 }; // verify correct raster geometry - for (int i = 0; i < metadata.length; i++) { + for (int i = 0; i < expectedMetadata.length; i++) { assertEquals(expectedMetadata[i], metadata[i], 1e-6); } @@ -3840,7 +3840,7 @@ public void testResampleRefRaster() throws FactoryException, TransformException -0.20000000298023224, 0.4000000059604645, 7.0, 5.0, 1.2, -1.4, 0.0, 0.0, 0.0, 1.0 }; // verify correct raster geometry - for (int i = 0; i < metadata.length; i++) { + for (int i = 0; i < expectedMetadata.length; i++) { assertEquals(expectedMetadata[i], metadata[i], 1e-6); } } @@ -3868,7 +3868,7 @@ public void testResampleDiffAlgorithms() throws FactoryException, TransformExcep double[] metadata = RasterAccessors.metadata(newRaster); double[] expectedMetadata = {0, 0, 5, 5, 1.2, -1.2, 0, 0, 0, 1}; // verify correct raster geometry - for (int i = 0; i < metadata.length; i++) { + for (int i = 0; i < expectedMetadata.length; i++) { assertEquals(expectedMetadata[i], metadata[i], 1e-6); } @@ -3885,7 +3885,7 @@ public void testResampleDiffAlgorithms() throws FactoryException, TransformExcep assertEquals(expectedRes, res); metadata = RasterAccessors.metadata(newRaster); // verify correct raster geometry - for (int i = 0; i < metadata.length; i++) { + for (int i = 0; i < expectedMetadata.length; i++) { assertEquals(expectedMetadata[i], metadata[i], 1e-6); } } diff --git a/docs/api/sql/Raster-operators.md b/docs/api/sql/Raster-operators.md index 08b2d6295e..91c72ee253 100644 --- a/docs/api/sql/Raster-operators.md +++ b/docs/api/sql/Raster-operators.md @@ -1553,9 +1553,15 @@ Introduction: Returns the metadata of the raster as a struct. The struct has the - skewY: skew in y direction (rotation y) - srid: srid of the raster - numSampleDimensions: number of bands +- tileWidth: (Since `v1.6.1`) width of tiles in the raster +- tileHeight: (Since `v1.6.1`) height of tiles in the raster For more information about ScaleX, ScaleY, SkewX, SkewY, please refer to the [Affine Transformations](Raster-affine-transformation.md) section. +`tileWidth` and `tileHeight` are available since `v1.6.1`, they are the dimensions of the tiles in the raster. For example, +rasters written by `RS_FromGeoTiff` uses the tiling scheme of the loaded GeoTIFF file. For rasters that has only 1 tile, +`tileWidth` and `tileHeight` will be equal to `gridWidth` and `gridHeight` respectively. + Format: `RS_MetaData (raster: Raster)` Since: `v1.4.1` @@ -1569,7 +1575,7 @@ SELECT RS_MetaData(raster) FROM raster_table Output: ``` -{-1.3095817809482181E7, 4021262.7487925636, 512.0, 517.0, 72.32861272132695, -72.32861272132695, 0.0, 0.0, 3857.0, 1.0} +{-1.3095817809482181E7, 4021262.7487925636, 512, 517, 72.32861272132695, -72.32861272132695, 0.0, 0.0, 3857, 1, 256, 256} ``` ### RS_NormalizeAll diff --git a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/RasterFunctions.scala b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/RasterFunctions.scala index 971be31ae6..04da5704ad 100644 --- a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/RasterFunctions.scala +++ b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/RasterFunctions.scala @@ -38,14 +38,16 @@ case class RS_Metadata(inputExpressions: Seq[Expression]) Seq( StructField("upperLeftX", DoubleType, nullable = false), StructField("upperLeftY", DoubleType, nullable = false), - StructField("gridWidth", DoubleType, nullable = false), - StructField("gridHeight", DoubleType, nullable = false), + StructField("gridWidth", IntegerType, nullable = false), + StructField("gridHeight", IntegerType, nullable = false), StructField("scaleX", DoubleType, nullable = false), StructField("scaleY", DoubleType, nullable = false), StructField("skewX", DoubleType, nullable = false), StructField("skewY", DoubleType, nullable = false), - StructField("srid", DoubleType, nullable = false), - StructField("numSampleDimensions", DoubleType, nullable = false))) + StructField("srid", IntegerType, nullable = false), + StructField("numSampleDimensions", IntegerType, nullable = false), + StructField("tileWidth", IntegerType, nullable = false), + StructField("tileHeight", IntegerType, nullable = false))) override def eval(input: InternalRow): Any = { // Evaluate the input expressions @@ -56,10 +58,22 @@ case class RS_Metadata(inputExpressions: Seq[Expression]) null } else { // Get the metadata using the Java method - val metaData = RasterAccessors.metadata(rasterGeom) + val metaData = RasterAccessors.rasterMetadata(rasterGeom) // Create an InternalRow with the metadata - InternalRow.fromSeq(metaData.map(_.asInstanceOf[Any])) + InternalRow( + metaData.upperLeftX, + metaData.upperLeftY, + metaData.gridWidth, + metaData.gridHeight, + metaData.scaleX, + metaData.scaleY, + metaData.skewX, + metaData.skewY, + metaData.srid, + metaData.numBands, + metaData.tileWidth, + metaData.tileHeight) } } 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 3343ae64e7..ea81708aed 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 @@ -23,7 +23,7 @@ import org.apache.sedona.common.utils.RasterUtils import org.apache.spark.sql.expressions.Window import org.apache.spark.sql.{DataFrame, Row, SaveMode} import org.apache.spark.sql.functions.{col, collect_list, expr, lit, row_number} -import org.apache.spark.sql.types.{DoubleType, StructField, StructType} +import org.apache.spark.sql.types.{DoubleType, IntegerType, StructField, StructType} import org.geotools.coverage.grid.GridCoverage2D import org.junit.Assert.{assertEquals, assertNotNull, assertNull, assertTrue} import org.locationtech.jts.geom.{Coordinate, Geometry} @@ -446,28 +446,30 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen Seq( StructField("upperLeftX", DoubleType, nullable = false), StructField("upperLeftY", DoubleType, nullable = false), - StructField("gridWidth", DoubleType, nullable = false), - StructField("gridHeight", DoubleType, nullable = false), + StructField("gridWidth", IntegerType, nullable = false), + StructField("gridHeight", IntegerType, nullable = false), StructField("scaleX", DoubleType, nullable = false), StructField("scaleY", DoubleType, nullable = false), StructField("skewX", DoubleType, nullable = false), StructField("skewY", DoubleType, nullable = false), - StructField("srid", DoubleType, nullable = false), - StructField("numSampleDimensions", DoubleType, nullable = false))) + StructField("srid", IntegerType, nullable = false), + StructField("numSampleDimensions", IntegerType, nullable = false), + StructField("tileWidth", IntegerType, nullable = false), + StructField("tileHeight", IntegerType, nullable = false))) assert(dfResult.schema("metadata").dataType == expectedSchema) assert(dfResult.schema("metadata_4326").dataType == expectedSchema) // Assert metadata fields - assert(metadata.getDouble(0) == metadata_4326.getDouble(0)) - assert(metadata.getDouble(1) == metadata_4326.getDouble(1)) - assert(metadata.getDouble(2) == metadata_4326.getDouble(2)) - assert(metadata.getDouble(3) == metadata_4326.getDouble(3)) - assert(metadata.getDouble(4) == metadata_4326.getDouble(4)) - assert(metadata.getDouble(5) == metadata_4326.getDouble(5)) - assert(metadata.getDouble(6) == metadata_4326.getDouble(6)) - assert(metadata.getDouble(7) == metadata_4326.getDouble(7)) - assert(metadata.getDouble(9) == metadata_4326.getDouble(9)) + assert(metadata(0) == metadata_4326(0)) + assert(metadata(1) == metadata_4326(1)) + assert(metadata(2) == metadata_4326(2)) + assert(metadata(3) == metadata_4326(3)) + assert(metadata(4) == metadata_4326(4)) + assert(metadata(5) == metadata_4326(5)) + assert(metadata(6) == metadata_4326(6)) + assert(metadata(7) == metadata_4326(7)) + assert(metadata(9) == metadata_4326(9)) } it("Passed RS_SetGeoReference should handle null values") { @@ -967,14 +969,9 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen .first() .getStruct(0) - // Convert Struct to Seq[Double] - def structToSeq(struct: Row): Seq[Double] = { - (0 until struct.size).map(struct.getDouble) - } - // Compare the metadata - val clippedMetadataSeq = structToSeq(clippedMetadata).slice(0, 9) - val originalMetadataSeq = structToSeq(originalMetadata).slice(0, 9) + val clippedMetadataSeq = metadataStructToSeq(clippedMetadata).slice(0, 9) + val originalMetadataSeq = metadataStructToSeq(originalMetadata).slice(0, 9) assert( clippedMetadataSeq == originalMetadataSeq, s"Expected: $originalMetadataSeq, but got: $clippedMetadataSeq") @@ -1189,19 +1186,12 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen val result = df.selectExpr("RS_Metadata(RS_FromGeoTiff(content)) as metadata").first().getStruct(0) - // Function to convert Struct to Seq[Double] - def structToSeq(struct: Row): Seq[Double] = { - (0 until struct.size).map(struct.getDouble) - } - - // Convert the struct to a sequence of doubles - val metadataSeq = structToSeq(result) - - // Assertions - assert(metadataSeq.length == 10) - assert(metadataSeq(2) == 512.0) - assert(metadataSeq(3) == 517.0) - assert(metadataSeq(9) == 1.0) + assert(result.length == 12) + assert(result(2) == 512) + assert(result(3) == 517) + assert(result(9) == 1) + assert(result(10) == 256) + assert(result(11) == 256) } it("Passed RS_MakeEmptyRaster") { @@ -1217,7 +1207,7 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen s"SELECT RS_Metadata(RS_MakeEmptyRaster($numBands, $widthInPixel, $heightInPixel, $upperLeftX, $upperLeftY, $cellSize))") .first() .getStruct(0) - assertEquals(numBands, result.getDouble(9), 0.001) + assertEquals(numBands, result.getInt(9)) // Test without skewX, skewY, srid result = sparkSession @@ -1225,7 +1215,7 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen s"SELECT RS_Metadata(RS_MakeEmptyRaster($numBands, 'I', $widthInPixel, $heightInPixel, $upperLeftX, $upperLeftY, $cellSize))") .first() .getStruct(0) - assertEquals(numBands, result.getDouble(9), 0.001) + assertEquals(numBands, result.getInt(9)) // Test with integer type input result = sparkSession @@ -1233,7 +1223,7 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen s"SELECT RS_Metadata(RS_MakeEmptyRaster($numBands, $widthInPixel, $heightInPixel, ${upperLeftX.toInt}, ${upperLeftY.toInt}, ${cellSize.toInt}))") .first() .getStruct(0) - assertEquals(numBands, result.getDouble(9), 0.001) + assertEquals(numBands, result.getInt(9)) // Test with skewX, skewY, srid but WITHOUT datatype val skewX = 0.0 @@ -1244,7 +1234,7 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen s"SELECT RS_Metadata(RS_MakeEmptyRaster($numBands, $widthInPixel, $heightInPixel, $upperLeftX, $upperLeftY, $cellSize, -$cellSize, $skewX, $skewY, $srid))") .first() .getStruct(0) - assertEquals(numBands, result.getDouble(9), 0.001) + assertEquals(numBands, result.getInt(9)) // Test with skewX, skewY, srid and datatype result = sparkSession @@ -1252,7 +1242,7 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen s"SELECT RS_Metadata(RS_MakeEmptyRaster($numBands, 'I', $widthInPixel, $heightInPixel, $upperLeftX, $upperLeftY, $cellSize, -$cellSize, $skewX, $skewY, $srid))") .first() .getStruct(0) - assertEquals(numBands, result.getDouble(9), 0.001) + assertEquals(numBands, result.getInt(9)) } it("Passed RS_MakeRaster") { @@ -1261,8 +1251,8 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen .load(resourceFolder + "raster/test1.tiff") .withColumn("rast", expr("RS_FromGeoTiff(content)")) val metadata = df.selectExpr("RS_Metadata(rast)").first().getStruct(0).toSeq - val width = metadata(2).asInstanceOf[Double].toInt - val height = metadata(3).asInstanceOf[Double].toInt + val width = metadata(2).asInstanceOf[Int] + val height = metadata(3).asInstanceOf[Int] val values = Array.tabulate(width * height) { i => i * i } // Attach values as a new column to the dataframe @@ -1293,8 +1283,8 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen val df = sparkSession.read.format("binaryFile").load(resourceFolder + "raster/test1.tiff") val metadata = df.selectExpr("RS_Metadata(RS_FromGeoTiff(content))").first().getStruct(0).toSeq - val width = metadata(2).asInstanceOf[Double].toInt - val height = metadata(3).asInstanceOf[Double].toInt + val width = metadata(2).asInstanceOf[Int] + val height = metadata(3).asInstanceOf[Int] val result = df.selectExpr("RS_BandAsArray(RS_FromGeoTiff(content), 1)").first().getSeq(0) assertEquals(width * height, result.length) val resultOutOfBound = @@ -2505,13 +2495,14 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen val rasterDf = df.selectExpr("RS_Resample(raster, 6, 5, 1, -1, false, null) as raster") val rasterOutput = rasterDf.selectExpr("RS_AsMatrix(raster)").first().getString(0) val rasterMetadata = rasterDf.selectExpr("RS_Metadata(raster)").first().getStruct(0) + val rasterMetadataSeq = metadataStructToSeq(rasterMetadata) val expectedOutput = "| 1.0 1.0 2.0 3.0 3.0 5.0|\n" + "| 1.0 1.0 2.0 3.0 3.0 5.0|\n" + "| 4.0 4.0 5.0 6.0 6.0 9.0|\n" + "| 7.0 7.0 8.0 9.0 9.0 10.0|\n" + "| 7.0 7.0 8.0 9.0 9.0 10.0|\n" val expectedMetadata: Seq[Double] = Seq(-0.33333333333333326, 0.19999999999999996, 6, 5, 1.388888888888889, -1.24, 0, 0, 0, 1) assertEquals(expectedOutput, rasterOutput) for (i <- expectedMetadata.indices) { - assertEquals(expectedMetadata(i), rasterMetadata.getDouble(i), 1e-6) + assertEquals(expectedMetadata(i), rasterMetadataSeq(i), 1e-6) } } @@ -2522,12 +2513,13 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen val rasterDf = df.selectExpr("RS_Resample(raster, 1.2, -1.4, true, null) as raster") val rasterOutput = rasterDf.selectExpr("RS_AsMatrix(raster)").first().getString(0) val rasterMetadata = rasterDf.selectExpr("RS_Metadata(raster)").first().getStruct(0) + val rasterMetadataSeq = metadataStructToSeq(rasterMetadata) val expectedOutput = "| 1.0 1.0 2.0 3.0 3.0 5.0 5.0|\n" + "| 4.0 4.0 5.0 6.0 6.0 9.0 9.0|\n" + "| 4.0 4.0 5.0 6.0 6.0 9.0 9.0|\n" + "| 7.0 7.0 8.0 9.0 9.0 10.0 10.0|\n" + "| NaN NaN NaN NaN NaN NaN NaN|\n" val expectedMetadata: Seq[Double] = Seq(0, 0, 7, 5, 1.2, -1.4, 0, 0, 0, 1) assertEquals(expectedOutput, rasterOutput) for (i <- expectedMetadata.indices) { - assertEquals(expectedMetadata(i), rasterMetadata.getDouble(i), 1e-6) + assertEquals(expectedMetadata(i), rasterMetadataSeq(i), 1e-6) } } @@ -2539,13 +2531,14 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen val rasterDf = df.selectExpr("RS_Resample(raster, refRaster, true, null) as raster") val rasterOutput = rasterDf.selectExpr("RS_AsMatrix(raster)").first().getString(0) val rasterMetadata = rasterDf.selectExpr("RS_Metadata(raster)").first().getStruct(0) + val rasterMetadataSeq = metadataStructToSeq(rasterMetadata) val expectedOutput = "| 1.0 1.0 2.0 3.0 3.0 5.0 5.0|\n" + "| 1.0 1.0 2.0 3.0 3.0 5.0 5.0|\n" + "| 4.0 4.0 5.0 6.0 6.0 9.0 9.0|\n" + "| 7.0 7.0 8.0 9.0 9.0 10.0 10.0|\n" + "| 7.0 7.0 8.0 9.0 9.0 10.0 10.0|\n" val expectedMetadata: Seq[Double] = Seq(-0.20000000298023224, 0.4000000059604645, 7.0, 5.0, 1.2, -1.4, 0.0, 0.0, 0.0, 1.0) assertEquals(expectedOutput, rasterOutput) for (i <- expectedMetadata.indices) { - assertEquals(expectedMetadata(i), rasterMetadata.getDouble(i), 1e-6) + assertEquals(expectedMetadata(i), rasterMetadataSeq(i), 1e-6) } } @@ -2577,9 +2570,9 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen val expectedMetadata = Seq(4.9375, 50.9375, 80, 48, 0.125, -0.125, 0, 0, 0, 4) val actualMetadata = rasterDf.selectExpr("RS_Metadata(raster) as metadata").first().getStruct(0) - + val actualMetadataSeq = metadataStructToSeq(actualMetadata) for (i <- expectedMetadata.indices) { - assertEquals(expectedMetadata(i), actualMetadata.getDouble(i), 1e-6) + assertEquals(expectedMetadata(i), actualMetadataSeq(i), 1e-6) } val expectedFirstVal = 60.95357131958008 @@ -2595,10 +2588,9 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen val expectedMetadata = Seq(4.9375, 50.9375, 80, 48, 0.125, -0.125, 0, 0, 0, 4) val actualMetadata = rasterDf.selectExpr("RS_Metadata(raster) as metadata").first().getStruct(0) - - for (i <- expectedMetadata.indices) { - assertEquals(expectedMetadata(i), actualMetadata.getDouble(i), 1e-6) - } + val actualMetadataSeq = metadataStructToSeq(actualMetadata) + for (i <- expectedMetadata.indices) + assertEquals(expectedMetadata(i), actualMetadataSeq(i), 1e-6) val expectedFirstVal = 60.95357131958008 val actualFirstVal = @@ -2628,18 +2620,22 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen // Extract the expected metadata struct val expectedMetadataStruct = expectedDf.selectExpr(expectedCol).first().getStruct(0) - // Function to convert Struct to Seq[Double] - def structToSeq(struct: Row): Seq[Double] = { - (0 until struct.size).map(struct.getDouble) - } - // Convert Structs to Seqs - val actualMetadata = structToSeq(actualMetadataStruct).slice(0, 9) - val expectedMetadata = structToSeq(expectedMetadataStruct).slice(0, 9) + val actualMetadata = metadataStructToSeq(actualMetadataStruct).slice(0, 9) + val expectedMetadata = metadataStructToSeq(expectedMetadataStruct).slice(0, 9) // Compare the actual and expected metadata assert( actualMetadata == expectedMetadata, s"Expected: $expectedMetadata, but got: $actualMetadata") } + + private def metadataStructToSeq(struct: Row): Seq[Double] = { + (0 until struct.length).map { k => + struct(k) match { + case value: Int => value.toDouble + case value: Double => value + } + } + } }