From dc58f04c9688de8c19f6119813ebe99cb271e8df Mon Sep 17 00:00:00 2001 From: Jacob Bouffard Date: Thu, 11 Jul 2019 09:35:08 -0400 Subject: [PATCH] Improved the reprojected logic so that it now checks to see if a reprojection can be skipped Signed-off-by: Jacob Bouffard Updated the CHANGELOG Signed-off-by: Jacob Bouffard Updated remaining reproject method Signed-off-by: Jacob Bouffard Fixed failing test Signed-off-by: Jacob Bouffard Renamed _reproject to reprojectInternal Signed-off-by: Jacob Bouffard Fixed spelling Signed-off-by: Jacob Bouffard Renamed the reprojectInternal method to reprojection Signed-off-by: Jacob Bouffard --- CHANGELOG.md | 2 ++ .../contrib/vlm/gdal/GDALRasterSource.scala | 2 +- .../contrib/vlm/gdal/GDALWarpOptionsSpec.scala | 2 +- .../contrib/vlm/MosaicRasterSource.scala | 12 ++++++------ .../geotrellis/contrib/vlm/RasterSource.scala | 17 ++++++++++++----- .../vlm/avro/GeotrellisRasterSource.scala | 2 +- .../avro/GeotrellisReprojectRasterSource.scala | 2 +- .../avro/GeotrellisResampleRasterSource.scala | 2 +- .../vlm/geotiff/GeoTiffRasterSource.scala | 2 +- .../geotiff/GeoTiffReprojectRasterSource.scala | 2 +- .../geotiff/GeoTiffResampleRasterSource.scala | 2 +- 11 files changed, 28 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f72cfc6e..1925ca71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - VLM: `GeoTiffRasterSource` reads are now thread safe - VLM: `GeoTiffRasterSource`s will now reuse a tiff instead of rereading it when possible. +- VLM: `RasterSource` will now short circut reprojection if the given + source is already in the target CRS. ### Removed - Summary: Subproject removed. The polygonal summary prototype was moved to GeoTrellis core for the 3.0 release. See: https://github.com/locationtech/geotrellis/blob/master/docs/guide/rasters.rst#polygonal-summary diff --git a/gdal/src/main/scala/geotrellis/contrib/vlm/gdal/GDALRasterSource.scala b/gdal/src/main/scala/geotrellis/contrib/vlm/gdal/GDALRasterSource.scala index 40c4332c..8887a396 100644 --- a/gdal/src/main/scala/geotrellis/contrib/vlm/gdal/GDALRasterSource.scala +++ b/gdal/src/main/scala/geotrellis/contrib/vlm/gdal/GDALRasterSource.scala @@ -70,7 +70,7 @@ case class GDALRasterSource( } } - def reproject(targetCRS: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): RasterSource = + def reprojection(targetCRS: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): RasterSource = GDALRasterSource(dataPath, options.reproject(gridExtent, crs, targetCRS, reprojectOptions)) def resample(resampleGrid: ResampleGrid[Long], method: ResampleMethod, strategy: OverviewStrategy): RasterSource = diff --git a/gdal/src/test/scala/geotrellis/contrib/vlm/gdal/GDALWarpOptionsSpec.scala b/gdal/src/test/scala/geotrellis/contrib/vlm/gdal/GDALWarpOptionsSpec.scala index 00de97a1..db1260d3 100644 --- a/gdal/src/test/scala/geotrellis/contrib/vlm/gdal/GDALWarpOptionsSpec.scala +++ b/gdal/src/test/scala/geotrellis/contrib/vlm/gdal/GDALWarpOptionsSpec.scala @@ -144,7 +144,7 @@ class GDALWarpOptionsSpec extends FunSpec with RasterMatchers with BetterRasterM val rs = GDALRasterSource(filePath) .reproject( - targetCRS = WebMercator, + crs = WebMercator, reprojectOptions = ReprojectOptions.DEFAULT.copy(targetCellSize = CellSize(10, 10).some), strategy = AutoHigherResolution ) diff --git a/vlm/src/main/scala/geotrellis/contrib/vlm/MosaicRasterSource.scala b/vlm/src/main/scala/geotrellis/contrib/vlm/MosaicRasterSource.scala index 0b2ed94d..a5712735 100644 --- a/vlm/src/main/scala/geotrellis/contrib/vlm/MosaicRasterSource.scala +++ b/vlm/src/main/scala/geotrellis/contrib/vlm/MosaicRasterSource.scala @@ -91,12 +91,12 @@ trait MosaicRasterSource extends RasterSource { * * @see [[geotrellis.contrib.vlm.RasterSource.reproject]] */ - def reproject(crs: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy) - : RasterSource = MosaicRasterSource( - sources map { _.reproject(crs, reprojectOptions, strategy) }, - crs, - gridExtent.reproject(this.crs, crs, reprojectOptions) - ) + def reprojection(crs: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): RasterSource = + MosaicRasterSource( + sources map { _.reproject(crs, reprojectOptions, strategy) }, + crs, + gridExtent.reproject(this.crs, crs, reprojectOptions) + ) def read(extent: Extent, bands: Seq[Int]): Option[Raster[MultibandTile]] = { val rasters = sources map { _.read(extent, bands) } diff --git a/vlm/src/main/scala/geotrellis/contrib/vlm/RasterSource.scala b/vlm/src/main/scala/geotrellis/contrib/vlm/RasterSource.scala index 39de9d78..23b2dd50 100644 --- a/vlm/src/main/scala/geotrellis/contrib/vlm/RasterSource.scala +++ b/vlm/src/main/scala/geotrellis/contrib/vlm/RasterSource.scala @@ -80,11 +80,15 @@ trait RasterSource extends CellGrid[Long] with Serializable { /** Raster pixel row count */ def rows: Long = gridExtent.rows + protected def reprojection(crs: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): RasterSource + /** Reproject to different CRS with explicit sampling reprojectOptions. * @see [[geotrellis.raster.reproject.Reproject]] * @group reproject */ - def reproject(crs: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): RasterSource + def reproject(crs: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): RasterSource = + if (crs == this.crs) this + else reprojection(crs, reprojectOptions, strategy) /** Sampling grid is defined over the footprint of the data at default resolution * @@ -94,7 +98,8 @@ trait RasterSource extends CellGrid[Long] with Serializable { * @group reproject */ def reproject(crs: CRS, method: ResampleMethod = NearestNeighbor, strategy: OverviewStrategy = AutoHigherResolution): RasterSource = - reproject(crs, Reproject.Options(method = method), strategy) + if (crs == this.crs) this + else reprojection(crs, Reproject.Options(method = method), strategy) /** Sampling grid and resolution is defined by given [[GridExtent]]. * Resulting extent is the extent of the minimum enclosing pixel region @@ -103,8 +108,8 @@ trait RasterSource extends CellGrid[Long] with Serializable { */ def reprojectToGrid(crs: CRS, grid: GridExtent[Long], method: ResampleMethod = NearestNeighbor, strategy: OverviewStrategy = AutoHigherResolution): RasterSource = if (crs == this.crs && grid == this.gridExtent) this - else if (crs == this.crs) resampleToGrid(grid) - else reproject(crs, Reproject.Options(method = method, parentGridExtent = Some(grid)), strategy) + else if (crs == this.crs) resampleToGrid(grid, method) + else reprojection(crs, Reproject.Options(method = method, parentGridExtent = Some(grid)), strategy) /** Sampling grid and resolution is defined by given [[RasterExtent]] region. * The extent of the result is also taken from given [[RasterExtent]], @@ -112,7 +117,9 @@ trait RasterSource extends CellGrid[Long] with Serializable { * @group reproject */ def reprojectToRegion(crs: CRS, region: RasterExtent, method: ResampleMethod = NearestNeighbor, strategy: OverviewStrategy = AutoHigherResolution): RasterSource = - reproject(crs, Reproject.Options(method = method, targetRasterExtent = Some(region)), strategy) + if (crs == this.crs && region == this.gridExtent) this + else if (crs == this.crs) resampleToRegion(region.asInstanceOf[GridExtent[Long]], method) + else reprojection(crs, Reproject.Options(method = method, targetRasterExtent = Some(region)), strategy) def resample(resampleGrid: ResampleGrid[Long], method: ResampleMethod, strategy: OverviewStrategy): RasterSource diff --git a/vlm/src/main/scala/geotrellis/contrib/vlm/avro/GeotrellisRasterSource.scala b/vlm/src/main/scala/geotrellis/contrib/vlm/avro/GeotrellisRasterSource.scala index 0e565c41..64ccc8b1 100644 --- a/vlm/src/main/scala/geotrellis/contrib/vlm/avro/GeotrellisRasterSource.scala +++ b/vlm/src/main/scala/geotrellis/contrib/vlm/avro/GeotrellisRasterSource.scala @@ -91,7 +91,7 @@ class GeotrellisRasterSource( override def readBounds(bounds: Traversable[GridBounds[Long]], bands: Seq[Int]): Iterator[Raster[MultibandTile]] = bounds.toIterator.flatMap(_.intersection(this.gridBounds).flatMap(read(_, bands))) - def reproject(targetCRS: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): RasterSource = { + def reprojection(targetCRS: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): RasterSource = { if (targetCRS != this.crs) { val (closestLayerId, targetGridExtent) = GeotrellisReprojectRasterSource.getClosestSourceLayer(targetCRS, sourceLayers, reprojectOptions, strategy) new GeotrellisReprojectRasterSource(attributeStore, dataPath, closestLayerId, sourceLayers, targetGridExtent, targetCRS, reprojectOptions, targetCellType) diff --git a/vlm/src/main/scala/geotrellis/contrib/vlm/avro/GeotrellisReprojectRasterSource.scala b/vlm/src/main/scala/geotrellis/contrib/vlm/avro/GeotrellisReprojectRasterSource.scala index 81dddb18..366bc576 100644 --- a/vlm/src/main/scala/geotrellis/contrib/vlm/avro/GeotrellisReprojectRasterSource.scala +++ b/vlm/src/main/scala/geotrellis/contrib/vlm/avro/GeotrellisReprojectRasterSource.scala @@ -97,7 +97,7 @@ class GeotrellisReprojectRasterSource( override def readBounds(bounds: Traversable[GridBounds[Long]], bands: Seq[Int]): Iterator[Raster[MultibandTile]] = bounds.toIterator.flatMap(_.intersection(this.gridBounds).flatMap(read(_, bands))) - def reproject(targetCRS: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): RasterSource = { + def reprojection(targetCRS: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): RasterSource = { if (targetCRS == sourceLayer.metadata.crs) { val resampleGrid = ResampleGrid.fromReprojectOptions(reprojectOptions).get val resampledGridExtent = resampleGrid(this.sourceLayer.gridExtent) diff --git a/vlm/src/main/scala/geotrellis/contrib/vlm/avro/GeotrellisResampleRasterSource.scala b/vlm/src/main/scala/geotrellis/contrib/vlm/avro/GeotrellisResampleRasterSource.scala index 9a7e3253..aeaf4318 100644 --- a/vlm/src/main/scala/geotrellis/contrib/vlm/avro/GeotrellisResampleRasterSource.scala +++ b/vlm/src/main/scala/geotrellis/contrib/vlm/avro/GeotrellisResampleRasterSource.scala @@ -93,7 +93,7 @@ class GeotrellisResampleRasterSource( .flatMap(read(_, bands)) } - def reproject(targetCRS: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): GeotrellisReprojectRasterSource = { + def reprojection(targetCRS: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): GeotrellisReprojectRasterSource = { val (closestLayerId, gridExtent) = GeotrellisReprojectRasterSource.getClosestSourceLayer(targetCRS, sourceLayers, reprojectOptions, strategy) new GeotrellisReprojectRasterSource(attributeStore, dataPath, layerId, sourceLayers, gridExtent, targetCRS, reprojectOptions, targetCellType) } diff --git a/vlm/src/main/scala/geotrellis/contrib/vlm/geotiff/GeoTiffRasterSource.scala b/vlm/src/main/scala/geotrellis/contrib/vlm/geotiff/GeoTiffRasterSource.scala index 4b418b9c..53a190ff 100644 --- a/vlm/src/main/scala/geotrellis/contrib/vlm/geotiff/GeoTiffRasterSource.scala +++ b/vlm/src/main/scala/geotrellis/contrib/vlm/geotiff/GeoTiffRasterSource.scala @@ -42,7 +42,7 @@ case class GeoTiffRasterSource( def bandCount: Int = tiff.bandCount def cellType: CellType = dstCellType.getOrElse(tiff.cellType) - def reproject(targetCRS: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): GeoTiffReprojectRasterSource = + def reprojection(targetCRS: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): GeoTiffReprojectRasterSource = GeoTiffReprojectRasterSource(dataPath, targetCRS, reprojectOptions, strategy, targetCellType, Some(tiff)) def resample(resampleGrid: ResampleGrid[Long], method: ResampleMethod, strategy: OverviewStrategy): GeoTiffResampleRasterSource = diff --git a/vlm/src/main/scala/geotrellis/contrib/vlm/geotiff/GeoTiffReprojectRasterSource.scala b/vlm/src/main/scala/geotrellis/contrib/vlm/geotiff/GeoTiffReprojectRasterSource.scala index 87145828..3387e6a7 100644 --- a/vlm/src/main/scala/geotrellis/contrib/vlm/geotiff/GeoTiffReprojectRasterSource.scala +++ b/vlm/src/main/scala/geotrellis/contrib/vlm/geotiff/GeoTiffReprojectRasterSource.scala @@ -121,7 +121,7 @@ case class GeoTiffReprojectRasterSource( }.map { convertRaster } } - def reproject(targetCRS: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): RasterSource = + def reprojection(targetCRS: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): RasterSource = GeoTiffReprojectRasterSource(dataPath, targetCRS, reprojectOptions, strategy, targetCellType, Some(tiff)) def resample(resampleGrid: ResampleGrid[Long], method: ResampleMethod, strategy: OverviewStrategy): RasterSource = diff --git a/vlm/src/main/scala/geotrellis/contrib/vlm/geotiff/GeoTiffResampleRasterSource.scala b/vlm/src/main/scala/geotrellis/contrib/vlm/geotiff/GeoTiffResampleRasterSource.scala index a40c9a68..206806a4 100644 --- a/vlm/src/main/scala/geotrellis/contrib/vlm/geotiff/GeoTiffResampleRasterSource.scala +++ b/vlm/src/main/scala/geotrellis/contrib/vlm/geotiff/GeoTiffResampleRasterSource.scala @@ -55,7 +55,7 @@ case class GeoTiffResampleRasterSource( @transient protected lazy val closestTiffOverview: GeoTiff[MultibandTile] = tiff.getClosestOverview(gridExtent.cellSize, strategy) - def reproject(targetCRS: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): GeoTiffReprojectRasterSource = + def reprojection(targetCRS: CRS, reprojectOptions: Reproject.Options, strategy: OverviewStrategy): GeoTiffReprojectRasterSource = new GeoTiffReprojectRasterSource(dataPath, targetCRS, reprojectOptions, strategy, targetCellType) { override lazy val gridExtent: GridExtent[Long] = reprojectOptions.targetRasterExtent match { case Some(targetRasterExtent) => targetRasterExtent.toGridType[Long]