Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ConstantTile with nodata: support correct celltype conversion #3552

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Dependecies update & fix "not found: type Serializable" compiler bug [#3535](https://github.com/locationtech/geotrellis/pull/3535)
- Update GDAL up to 3.9.x [#3540](https://github.com/locationtech/geotrellis/pull/3540)
- Fix reprojection with downsampling for GeotiffRasterSource and tile RDDs. Reprojection outside the valid projection bounds may now throw a GeoAttrsError. [#3541](https://github.com/locationtech/geotrellis/issues/3541)
- ConstantTile: fix 'convert' method when the constant value is nodata. [#3525](https://github.com/locationtech/geotrellis/issues/3525)

## [3.7.1] - 2024-01-08

Expand Down
41 changes: 40 additions & 1 deletion raster/src/main/scala/geotrellis/raster/ConstantTile.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package geotrellis.raster
import geotrellis.vector.Extent

import java.nio.ByteBuffer

import spire.syntax.cfor._


Expand Down Expand Up @@ -83,6 +82,7 @@ abstract class ConstantTile extends Tile {
*/
def convert(newType: CellType): Tile = {
newType match {
case ct: CellType if dVal.isNaN => ConstantTile.empty(newType, cols, rows)
case BitCellType => new BitConstantTile(if (iVal == 0) false else true, cols, rows)
case ct: ByteCells => ByteConstantTile(iVal.toByte, cols, rows, ct)
case ct: UByteCells => UByteConstantTile(iVal.toByte, cols, rows, ct)
Expand Down Expand Up @@ -243,6 +243,45 @@ object ConstantTile {
case ct: FloatCells => FloatConstantTile.fromBytes(bytes, cols, rows, ct)
case ct: DoubleCells => DoubleConstantTile.fromBytes(bytes, cols, rows, ct)
}

/**
* Create a [[ConstantTile]] that is set to the nodata value of the given celltype or to the default nodata value if
* the celltype does not have a nodata. BitCells are set to 'false'.
*
* @param t The [[CellType]] of the new [[ConstantTile]].
* @param cols The number of columns that the new [[ConstantTile]] should have
* @param rows The number of rows that the new [[ConstantTile]] should have
* @return The new [[ConstantTile]]
*/
def empty(t: CellType, cols: Int, rows: Int): Tile = {
t match {
case _: BitCells => BitConstantTile(false, cols, rows)
case ct: ByteUserDefinedNoDataCellType => ByteConstantTile(ct.noDataValue ,cols, rows, ct)
pomadchin marked this conversation as resolved.
Show resolved Hide resolved
case ct: ByteConstantNoDataCellType.type => ByteConstantTile(ct.noDataValue ,cols, rows, ct)
case ct: ByteCellType.type => ByteConstantTile(byteNODATA ,cols, rows, ct)
case ct: UByteConstantNoDataCellType.type => UByteConstantTile(ct.noDataValue ,cols, rows, ct)
case ct: UByteUserDefinedNoDataCellType => UByteConstantTile(ct.noDataValue ,cols, rows, ct)
case ct: UByteCellType.type => UByteConstantTile(ubyteNODATA ,cols, rows, ct)
case ct: ShortUserDefinedNoDataCellType => ShortConstantTile(ct.noDataValue ,cols, rows, ct)
case ct: ShortConstantNoDataCellType.type => ShortConstantTile(ct.noDataValue ,cols, rows, ct)
case ct: ShortCellType.type => ShortConstantTile(shortNODATA ,cols, rows, ct)
case ct: UShortUserDefinedNoDataCellType => UShortConstantTile(ct.noDataValue ,cols, rows, ct)
case ct: UShortConstantNoDataCellType.type => UShortConstantTile(ct.noDataValue ,cols, rows, ct)
case ct: UShortCellType.type => UShortConstantTile(ushortNODATA ,cols, rows, ct)
case ct: IntUserDefinedNoDataCellType => IntConstantTile(ct.noDataValue ,cols, rows, ct)
case ct: IntConstantNoDataCellType.type => IntConstantTile(ct.noDataValue ,cols, rows, ct)
case ct: IntCellType.type => IntConstantTile(NODATA ,cols, rows, ct)
case ct: FloatUserDefinedNoDataCellType => FloatConstantTile(ct.noDataValue ,cols, rows, ct)
case ct: FloatConstantNoDataCellType.type => FloatConstantTile(ct.noDataValue ,cols, rows, ct)
case ct: FloatCellType.type => FloatConstantTile(floatNODATA ,cols, rows, ct)
case ct: DoubleUserDefinedNoDataCellType => DoubleConstantTile(ct.noDataValue ,cols, rows, ct)
case ct: DoubleConstantNoDataCellType.type => DoubleConstantTile(ct.noDataValue ,cols, rows, ct)
case ct: DoubleCellType.type => DoubleConstantTile(doubleNODATA ,cols, rows, ct)
}
}



}

/**
Expand Down
26 changes: 26 additions & 0 deletions raster/src/test/scala/geotrellis/raster/ConstantTileSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,30 @@ class ConstantTileSpec extends AnyFunSpec with Matchers with RasterMatchers with
int.combine(dt)(_ + _).cellType shouldBe int.cellType.union(dt.cellType)
}
}

describe("celltype conversion") {
it("should convert ByteConstantTile with nodata") {
val t = ByteConstantTile(byteNODATA, cols = 1, rows = 1)
assert(t.isNoDataTile)
assert(t.convert(t.cellType).isNoDataTile)
}

it("should convert ByteConstantTile") {
val t = ByteConstantTile(10, cols = 1, rows = 1)
assert(t.convert(FloatConstantNoDataCellType).getDouble(0,0) === 10.0)
}

it("should convert empty IntConstantTile ") {
val t = ConstantTile.empty(IntCellType, 1, 1)
assert(t.isNoDataTile)
assert(t.convert(IntUserDefinedNoDataCellType(3)).isNoDataTile)
}

it("should convert empty FloatConstantTile ") {
val t = ConstantTile.empty(FloatCellType, 1, 1)
assert(t.isNoDataTile)
val converted: Tile = t.convert(FloatUserDefinedNoDataCellType(3.0f))
assert(converted.isNoDataTile)
}
}
}