Skip to content

Commit b67049a

Browse files
committed
Extract bits should throw on non-integral cell types
Signed-off-by: Jason T. Brown <[email protected]>
1 parent abb7add commit b67049a

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

core/src/main/scala/org/locationtech/rasterframes/expressions/transformers/ExtractBits.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ object ExtractBits{
8686
new Column(ExtractBits(tile.expr, startBit.expr, numBits.expr))
8787

8888
def apply(tile: Tile, startBit: Int, numBits: Int): Tile = {
89+
assert(!tile.cellType.isFloatingPoint, "ExtractBits operation requires integral CellType")
8990
// this is the last `numBits` positions of "111111111111111"
9091
val widthMask = Int.MaxValue >> (63 - numBits)
9192
// map preserving the nodata structure

core/src/test/scala/org/locationtech/rasterframes/RasterFunctionsSpec.scala

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,37 @@ class RasterFunctionsSpec extends TestEnvironment with RasterMatchers {
11791179
checker("qa_cconf", cirrus, 1) //low cloud conf
11801180
checker("qa_circonf", cirrus, 3) //high cirrus conf
11811181
}
1182+
it("should extract bits from different cell types") {
1183+
import org.locationtech.rasterframes.expressions.transformers.ExtractBits
1184+
1185+
case class TestCase[N: Numeric](cellType: CellType, cellValue: N, bitPosition: Int, numBits: Int, expectedValue: Int) {
1186+
def testIt(): Unit = {
1187+
val tile = projectedRasterTile(3, 3, cellValue, TestData.extent, TestData.crs, cellType)
1188+
val extracted = ExtractBits(tile, bitPosition, numBits)
1189+
all(extracted.toArray()) should be (expectedValue)
1190+
}
1191+
}
1192+
1193+
Seq(
1194+
TestCase(BitCellType, 1, 0, 1, 1),
1195+
TestCase(ByteCellType, 127, 6, 2, 1), // 7th bit is sign
1196+
TestCase(ByteCellType, 127, 5, 2, 3),
1197+
TestCase(ByteCellType, -128, 6, 2, 2), // 7th bit is sign
1198+
TestCase(UByteCellType, 255, 6, 2, 3),
1199+
TestCase(UByteCellType, 255, 10, 2, 0), // shifting beyond range of cell type results in 0
1200+
TestCase(ShortCellType, 32767, 15, 1, 0),
1201+
TestCase(ShortCellType, 32767, 14, 2, 1),
1202+
TestCase(ShortUserDefinedNoDataCellType(0), -32768, 14, 2, 2),
1203+
TestCase(UShortCellType, 65535, 14, 2, 3),
1204+
TestCase(UShortCellType, 65535, 18, 2, 0), // shifting beyond range of cell type results in 0
1205+
TestCase(IntCellType, 2147483647, 30, 2, 1),
1206+
TestCase(IntCellType, 2147483647, 29, 2, 3)
1207+
).foreach(_.testIt)
1208+
1209+
// floating point types
1210+
an [AssertionError] should be thrownBy TestCase[Float](FloatCellType, Float.MaxValue, 29, 2, 3).testIt()
1211+
1212+
}
11821213
it("should mask by QA bits"){
11831214
val result = df
11841215
.withColumn("fill_no", rf_mask_by_bit($"data", $"mask", 0, true))

0 commit comments

Comments
 (0)