-
Notifications
You must be signed in to change notification settings - Fork 364
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
GridExtent rounding issues #3248
Comments
👋 I put a test tif (thanks @notthatbreezy) at import $ivy.`org.locationtech.geotrellis::geotrellis-raster:3.3.0`
import $ivy.`org.locationtech.geotrellis::geotrellis-s3:3.3.0`
import $ivy.`org.locationtech.geotrellis::geotrellis-vector:3.3.0`
import geotrellis.raster._
import geotrellis.vector._
import geotrellis.raster.geotiff._
def viableCellSizes(
rs: RasterSource,
baseCellSize: CellSize,
sizes: List[CellSize],
target: Long
): List[CellSize] = {
val width = rs.cols
val height = rs.rows
val isGood: CellSize => Boolean = (cs: CellSize) => {
val cellCount = width / (cs.width / baseCellSize.width) * (height / (cs.height / baseCellSize.height))
println(s"Cell count for $cs: $cellCount")
cellCount < target
}
sizes.filter(isGood)
}
val rsSb = GeoTiffRasterSource("trl-transformed-cog.tif")
val viableSb = viableCellSizes(rsSb, rsSb.cellSize, rsSb.resolutions, 400000)
viableSb.headOption map { res => println(s"Single band 1: ${rsSb.gridExtent.withResolution(res)}") }
viableSb.lastOption map { res => println(s"Single band 2: ${rsSb.gridExtent.withResolution(res)}") } The error to expect is:
|
@jisantuc I downloaded the test tiff and copied your ammonite script and was able to reproduce the issue there using geotrellis 3.3.0. I then loaded up it("should not crash in withResolution") {
def viableCellSizes(rs: RasterSource,
baseCellSize: CellSize,
sizes: List[CellSize],
targetCellCount: Long): List[CellSize] = {
val width = rs.cols
val height = rs.rows
val isGood: CellSize => Boolean = (cs: CellSize) => {
val cellCount = width / (cs.width / baseCellSize.width) * (height / (cs.height / baseCellSize.height))
println(s"Cell count for $cs: $cellCount")
cellCount < targetCellCount
}
sizes.filter(isGood)
}
val path = baseGeoTiffPath("failing-withResolutions.tif")
val rsSb = GeoTiffRasterSource(path)
val viableSb = viableCellSizes(rsSb, rsSb.cellSize, rsSb.resolutions, 400000)
viableSb.headOption map { res => println(s"Single band 1: ${rsSb.gridExtent.withResolution(res)}") }
viableSb.headOption map { res => println(s"Single band 1: ${rsSb.gridExtent.withResolution(res)}") }
} In the absence of further information, I'm going to guess that at least one of the fixes in @pomadchin's #3252 addressed this issue. |
@CloudNiner are you sure about that? It fails for me on the master branch: git reset --hard cf6e8596a0b21c4d3598525080b98dc087c8f898
HEAD is now at cf6e8596a Fix MosaicRasterSource, GDALRasterSource and GeoTiffResampleRasterSource behavior (#3252)
scala> viableSb.lastOption map { res => println(s"Single band 2: ${rsSb.gridExtent.withResolution(res)}") }
java.lang.IllegalArgumentException: requirement failed: Extent(4114885.5876404666, -770072.0469938816, 4129027.727803043, -758864.1346488822) at CellSize(64.57598247751807,64.41328933907688) does not match 219x175
at scala.Predef$.require(Predef.scala:281)
at geotrellis.raster.GridExtent.<init>(GridExtent.scala:48)
at geotrellis.raster.GridExtent.withResolution(GridExtent.scala:133)
at geotrellis.raster.GridExtent.withResolution(GridExtent.scala:144)
at geotrellis.raster.GridExtent.withResolution$mcJ$sp(GridExtent.scala:143)
at .$anonfun$res1$1(<console>:38)
at .$anonfun$res1$1$adapted(<console>:38)
at scala.Option.map(Option.scala:230)
... 36 elided In #3252 I intentionally didn't touch |
Whew. I can reproduce this now. Looks like I somehow ended up with an incorrect copy of the test case. |
Built from RasterSource in test case of #3248
Built from RasterSource in test case of #3248
Built from RasterSource in test case of #3248
Built from RasterSource in test case of #3248
@jisantuc The PR in #3250 should address this specific issue once merged, but here's some background on this issue in this PR comment: #3250 (comment) along with a discussion around how usage of |
* Test case for failing withResolution Built from RasterSource in test case of #3248 * Use [ceil|floor]WithTolerance methods consistently In the same manner as QGIS and GDAL in order to correctly compute rows, cols, and cell sizes for given extents. * Use math.round in GridExtent.withResolution So that when we construct new GridExtents in withResolution, there isn't a mismatch between the expectation in the constructor. Before, withResolution used ceil when constructor used round. A treatise on whether round is the right choice, and what withResolution should actually be doing, is left for future work. * Use GridExtent constructors in combine So that we're consistently using round to estimate cols and rows based on cell size. Remove use of ceilWithTolerance as it's now unclear if it helps or hinders us in the places its still used. It can always be re-added in case we hit edge cases that still fail later. * Add GridExtent.withResolution docstrings Also fixup scaladoc refs in file. Update CHANGELOG
In the
GridExtent
funtions we use floors, ceils and rounds pretty inconsistently.QGIS and GDAL use ceils and floors with some tolerance that helps to handle corner cases better.
This task is about doublecheking how we work with rounding floating numbers, and consider usage of the
ceilWithTolerance
as well (a long with the floorWithTolerance function we already use).The text was updated successfully, but these errors were encountered: