From 0a73ba0bd292d140f545cf7c2295c72e867da0b1 Mon Sep 17 00:00:00 2001 From: "Simeon H.K. Fitch" Date: Wed, 24 Apr 2019 11:22:00 -0400 Subject: [PATCH] Fixes #2907. --- .../raster/testkit/TileBuilders.scala | 19 +++++++++++++ .../scala/geotrellis/raster/ArrayTile.scala | 11 ++++++-- .../geotrellis/raster/ArrayTileSpec.scala | 27 +++++++++++++++++-- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/raster-testkit/src/main/scala/geotrellis/raster/testkit/TileBuilders.scala b/raster-testkit/src/main/scala/geotrellis/raster/testkit/TileBuilders.scala index c32387e34e..8be2b8496f 100644 --- a/raster-testkit/src/main/scala/geotrellis/raster/testkit/TileBuilders.scala +++ b/raster-testkit/src/main/scala/geotrellis/raster/testkit/TileBuilders.scala @@ -163,6 +163,25 @@ trait TileBuilders { CompositeTile(tiles.flatten.map(a => createTile(a, pixelCols, pixelRows)), layout) } + private + lazy val rng = new scala.util.Random(42) + + /** Return a copy of the given tile with `num` cells, at random indexes, replaced by the NoData value. */ + def injectNoData(num: Int)(t: Tile): Tile = { + val indexes = List.tabulate(t.size)(identity) + val targeted = rng.shuffle(indexes).take(num) + def filter(c: Int, r: Int) = targeted.contains(r * t.cols + c) + + val injected = if(t.cellType.isFloatingPoint) { + t.mapDouble((c, r, v) ⇒ (if(filter(c,r)) doubleNODATA else v): Double) + } + else { + t.map((c, r, v) ⇒ if(filter(c, r)) NODATA else v) + } + + injected + } + /** * 9x10 raster of 90 numbers between 1 - 100 in random order. */ diff --git a/raster/src/main/scala/geotrellis/raster/ArrayTile.scala b/raster/src/main/scala/geotrellis/raster/ArrayTile.scala index da94c1d6d0..d41487095a 100644 --- a/raster/src/main/scala/geotrellis/raster/ArrayTile.scala +++ b/raster/src/main/scala/geotrellis/raster/ArrayTile.scala @@ -232,7 +232,14 @@ trait ArrayTile extends Tile with Serializable { case ct: CroppedTile => ct.combine(this)((z1, z2) => f(z2, z1)) case t => - this.map((col, row, z) => f(z, t.get(col, row))) + this.map((col, row, z) => { + if (isNoData(z)) z + else { + val v = t.get(col, row) + if (isNoData(v)) v + else f(z, v) + } + }) } /** @@ -277,7 +284,7 @@ trait ArrayTile extends Tile with Serializable { case ct: CompositeTile => ct.combineDouble(this)((z1, z2) => f(z2, z1)) case t => - this.mapDouble((col, row, z) => f(z, t.get(col, row))) + this.mapDouble((col, row, z) => f(z, t.getDouble(col, row))) } } diff --git a/raster/src/test/scala/geotrellis/raster/ArrayTileSpec.scala b/raster/src/test/scala/geotrellis/raster/ArrayTileSpec.scala index 7f50d0a25c..449bb64986 100644 --- a/raster/src/test/scala/geotrellis/raster/ArrayTileSpec.scala +++ b/raster/src/test/scala/geotrellis/raster/ArrayTileSpec.scala @@ -166,7 +166,7 @@ class ArrayTileSpec extends FunSpec } it("should combine with non-standard tiles") { - withClue("IntArrayTile") { + withClue("constant IntArrayTile") { val at = IntArrayTile(Array.ofDim[Int](100*100).fill(50), 100, 100) val fauxTile = new DelegatingTile { override protected def delegate: Tile = IntConstantTile(0, 100, 100) @@ -175,7 +175,7 @@ class ArrayTileSpec extends FunSpec assertEqual(at.combine(fauxTile)((z1, z2) => z1 + z2), at) } - withClue("DoubleArrayTile") { + withClue("constant DoubleArrayTile") { val at = DoubleArrayTile(Array.ofDim[Double](100*100).fill(50), 100, 100) val fauxTile = new DelegatingTile { override protected def delegate: Tile = DoubleConstantTile(0.0, 100, 100) @@ -183,6 +183,29 @@ class ArrayTileSpec extends FunSpec assertEqual(at.combineDouble(fauxTile)((z1, z2) => z1 + z2), at) } + + withClue("IntArrayTile with NoData") { + val at = injectNoData(4)(createConsecutiveTile(10)) + .convert(DoubleUserDefinedNoDataCellType(98)) + val twice = at * 2 + val fauxTile = new DelegatingTile { + override protected def delegate: Tile = at + } + + assertEqual(at.combine(fauxTile)((z1, z2) => z1 + z2), twice) + } + + withClue("DoubleArrayTile with NoData") { + val at = injectNoData(4)(createValueTile(10, 10.2)) + .convert(DoubleUserDefinedNoDataCellType(33.2)) + val twice = at * 2 + val fauxTile = new DelegatingTile { + override protected def delegate: Tile = at + } + + assertEqual(at.combineDouble(fauxTile)((z1, z2) => z1 + z2), twice) + assertEqual(fauxTile.combineDouble(at)((z1, z2) => z1 + z2), twice) + } } } }