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 9f37aea6a9..2794f93a2c 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 @@ -53,6 +53,16 @@ public static int numBands(GridCoverage2D raster) { return raster.getNumSampleDimensions(); } + public static int getWidth(GridCoverage2D raster) { + return raster.getGridGeometry().getGridRange().getSpan(0); + } + + public static int getHeight(GridCoverage2D raster) { + return raster.getGridGeometry().getGridRange().getSpan(1); + } + + + public static Geometry envelope(GridCoverage2D raster) throws FactoryException { Envelope2D envelope2D = raster.getEnvelope2D(); 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 bca7d8c259..c47570c076 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 @@ -43,6 +43,12 @@ public void testNumBands() { assertEquals(1, RasterAccessors.numBands(oneBandRaster)); assertEquals(4, RasterAccessors.numBands(multiBandRaster)); } + @Test + public void testWidthAndHeight() throws FactoryException { + GridCoverage2D emptyRaster = RasterConstructors.makeEmptyRaster(1, 10, 20, 0, 0, 8); + assertEquals(20, RasterAccessors.getHeight(emptyRaster)); + assertEquals(10, RasterAccessors.getWidth(emptyRaster)); + } @Test public void testSrid() throws FactoryException { diff --git a/docs/api/sql/Raster-operators.md b/docs/api/sql/Raster-operators.md index 8a67125ed4..9157ccf852 100644 --- a/docs/api/sql/Raster-operators.md +++ b/docs/api/sql/Raster-operators.md @@ -1,3 +1,41 @@ +## Raster Accessors + +### RS_Height + +Introduction: Returns the height of the raster. + +Format: `RS_Height(raster: Raster)` + +Since: `1.5.0` + +Spark SQL example: +```sql +SELECT RS_Height(raster) FROM rasters +``` + +Output: +``` +512 +``` + +### RS_Width + +Introduction: Returns the width of the raster. + +Format: `RS_Width(raster: Raster)` + +Since: `1.5.0` + +Spark SQL example: +```sql +SELECT RS_Width(raster) FROM rasters +``` + +Output: +``` +517 +``` + ## Raster based operators ### RS_Envelope 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 5c4d08af3f..95473c0553 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 @@ -203,7 +203,9 @@ object Catalog { function[RS_Values](1), function[RS_Intersects](), function[RS_AsGeoTiff](), - function[RS_AsArcGrid]() + function[RS_AsArcGrid](), + function[RS_Width](), + function[RS_Height]() ) val aggregateExpressions: Seq[Aggregator[Geometry, Geometry, Geometry]] = Seq( diff --git a/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/RasterAccessors.scala b/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/RasterAccessors.scala index 57ea342351..13b477243f 100644 --- a/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/RasterAccessors.scala +++ b/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/raster/RasterAccessors.scala @@ -46,3 +46,15 @@ case class RS_Metadata(inputExpressions: Seq[Expression]) extends InferredExpres copy(inputExpressions = newChildren) } } + +case class RS_Width(inputExpressions: Seq[Expression]) extends InferredExpression(RasterAccessors.getWidth _) { + protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = { + copy(inputExpressions = newChildren) + } +} + +case class RS_Height(inputExpressions: Seq[Expression]) extends InferredExpression(RasterAccessors.getHeight _) { + 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 5d3bba69fb..11e75e6dab 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 @@ -285,6 +285,18 @@ class rasteralgebraTest extends TestBaseScala with BeforeAndAfter with GivenWhen assert(result == 1) } + it("Passed RS_Width with raster") { + val df = sparkSession.read.format("binaryFile").load(resourceFolder + "raster/test1.tiff") + val result = df.selectExpr("RS_Width(RS_FromGeoTiff(content))").first().getInt(0) + assertEquals(512, result) + } + + it("Passed RS_Height with raster") { + val df = sparkSession.read.format("binaryFile").load(resourceFolder + "raster/test1.tiff") + val result = df.selectExpr("RS_Height(RS_FromGeoTiff(content))").first().getInt(0) + assertEquals(517, result) + } + it("Passed RS_SetSRID should handle null values") { val result = sparkSession.sql("select RS_SetSRID(null, 0)").first().get(0) assert(result == null)