Skip to content
Open
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 @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed
- MinResample should ignore Int NODATA values [#3590](https://github.com/locationtech/geotrellis/pull/3590)
- Empty (NoData) ConstantTile objects are now correctly converted to empty ConstantTile objects of the desired CellType

## [3.8.0] - 2025-04-23

Expand Down
33 changes: 23 additions & 10 deletions raster/src/main/scala/geotrellis/raster/ConstantTile.scala
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,22 @@ abstract class ConstantTile extends Tile {
* @param newType The type of cells that the result should have
* @return The new Tile
*/
def convert(newType: CellType): Tile =
newType match {
case BitCellType => new BitConstantTile(if (iVal == 0) false else true, cols, rows)
case ct: ByteCells => ByteConstantTile(i2b(iVal), cols, rows, ct)
case ct: UByteCells => UByteConstantTile(iVal.toByte, cols, rows, ct)
case ct: ShortCells => ShortConstantTile(i2s(iVal), cols, rows, ct)
case ct: UShortCells => UShortConstantTile(i2us(iVal) , cols, rows, ct)
case ct: IntCells => IntConstantTile(iVal, cols, rows, ct)
case ct: FloatCells => FloatConstantTile(d2f(dVal), cols, rows, ct)
case ct: DoubleCells => DoubleConstantTile(dVal, cols, rows, ct)
def convert(newType: CellType): Tile = {
if (isNoDataTile) {
ConstantTile.empty(newType, cols, rows)
} else {
newType match {
case BitCellType => new BitConstantTile(if (iVal == 0) false else true, cols, rows)
case ct: ByteCells => ByteConstantTile(i2b(iVal), cols, rows, ct)
case ct: UByteCells => UByteConstantTile(iVal.toByte, cols, rows, ct)
case ct: ShortCells => ShortConstantTile(i2s(iVal), cols, rows, ct)
case ct: UShortCells => UShortConstantTile(i2us(iVal) , cols, rows, ct)
case ct: IntCells => IntConstantTile(iVal, cols, rows, ct)
case ct: FloatCells => FloatConstantTile(d2f(dVal), cols, rows, ct)
case ct: DoubleCells => DoubleConstantTile(dVal, cols, rows, ct)
}
}
}

def interpretAs(newCellType: CellType): Tile =
withNoData(None).convert(newCellType)
Expand Down Expand Up @@ -218,6 +223,14 @@ abstract class ConstantTile extends Tile {
}
tile
}

override def isNoDataTile: Boolean = {
if (cellType.isFloatingPoint) {
!isData(getDouble(0, 0))
} else {
!isData(get(0, 0))
}
Comment on lines +227 to +232
Copy link
Copy Markdown
Member

@pomadchin pomadchin Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 interesting; what if the 0, 0 is Data?
Or on the contrary, the 0, 0 is NoData, but the rest of the tile is filled in with smth.

}
}

object ConstantTile {
Expand Down
38 changes: 38 additions & 0 deletions raster/src/test/scala/geotrellis/raster/ConstantTileSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -150,5 +150,43 @@ class ConstantTileSpec extends AnyFunSpec with Matchers with RasterMatchers with
}
}

describe("conversion of empty tiles of CellTypes that support NoData should result in NoData tiles") {
List(
// BitCellType,
ByteUserDefinedNoDataCellType(1.toByte),
ByteConstantNoDataCellType,
// ByteCellType,
UByteConstantNoDataCellType,
UByteUserDefinedNoDataCellType(1.toByte),
// UByteCellType,
ShortUserDefinedNoDataCellType(1.toShort),
ShortConstantNoDataCellType,
// ShortCellType,
UShortUserDefinedNoDataCellType(1.toShort),
UShortConstantNoDataCellType,
// UShortCellType,
IntUserDefinedNoDataCellType(1),
IntConstantNoDataCellType,
// IntCellType,
FloatUserDefinedNoDataCellType(1.0f),
FloatConstantNoDataCellType,
// FloatCellType,
DoubleUserDefinedNoDataCellType(1.0),
DoubleConstantNoDataCellType,
// DoubleCellType
).foreach { cellType =>
it(s"should convert an empty tile of $cellType to an empty tile of the new cell type") {
val tile = ConstantTile.empty(cellType, 1, 1)
assert(tile.isNoDataTile)
assert(tile.cellType == cellType)
val newCellType = FloatUserDefinedNoDataCellType(666.0f)
val convertedNoDataTile = tile.convert(newCellType)
assert(convertedNoDataTile.isNoDataTile)
assert(convertedNoDataTile.cellType == newCellType)
}
}
}


private def getClassName[T](obj: T): String = obj.getClass.getName.split("\\.").last
}
Loading