## see discussion on R-Sig-Geo
## https://stat.ethz.ch/pipermail/r-sig-geo/2018-February/026328.html
## GDAL details here http://www.gdal.org/frmt_wms.html
library(raster)
## Loading required package: sp
yesterday <- Sys.Date() - 1
TileLevel <- 3
xml_specification <-
paste0('<GDAL_WMS>
<Service name="TMS">
<ServerUrl>
https://gibs.earthdata.nasa.gov/wmts/epsg3413/best/MODIS_Aqua_CorrectedReflectance_Bands721/default/',
format(yesterday, "%Y-%m-%d"),
'/250m/${z}/${y}/${x}.jpg</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-4194304</UpperLeftX>
<UpperLeftY>4194304</UpperLeftY>
<LowerRightX>4194304</LowerRightX>
<LowerRightY>-4194304</LowerRightY>
<TileLevel>', TileLevel, '</TileLevel>
<TileCountX>2</TileCountX>
<TileCountY>2</TileCountY>
<YOrigin>top</YOrigin>
</DataWindow>
<Projection>EPSG:3413</Projection>
<BlockSizeX>512</BlockSizeX>
<BlockSizeY>512</BlockSizeY>
<BandsCount>3</BandsCount>
</GDAL_WMS>
')
## raster is *lazy* here, we only get metadata
rastersource <- raster(xml_specification)
localproj <- projection(rastersource)
llproj <- "+init=epsg:4326"
## this is not meaningful, because the truly polar extent of
## the source means this wraps to the entire extent
#local_ex <- projectExtent(raster(extent(c(-135, 170), c(52, 75)),
# crs = llproj), localproj)
## we can crop in index space (note that it's a different orientation
## to the usual xmin/xmax/ymin/ymax
## r1, r2, c1, c2, representing the first and last row and column number)
## and note that any subsetting means the "lazy-ness" contract above
## is broken and data is actually read
rc <- c(1, 150, 1, 200)
## this works!!
r <- crop(rastersource, extent(rastersource, rc[1], rc[2], rc[3], rc[4]))
plot(r)

## see in context
plot(extent(rastersource), asp = 1)
plot(extent(rastersource, rc[1], rc[2], rc[3], rc[4]), add = TRUE)
plot(r, add = TRUE)
data("wrld_simpl", package = "maptools")
plot(sp::spTransform(wrld_simpl, projection(rastersource)), add = TRUE)

## use what we learned to drive rgdal more direclty
## so we can extract at a given level-of-detail, not just
## a slice subset
## note (y,x) from raster and rgdal::readGDAL orientation
dm <- c(nrow(rastersource), ncol(rastersource))
subfact <- 16
outdim <- trunc(dm/subfact)
offs <- c(0, 0)
rs <- rgdal::readGDAL(xml_specification, offset = offs, region.dim = dm, output.dim = outdim)
## <GDAL_WMS>
## <Service name="TMS">
## <ServerUrl>
## https://gibs.earthdata.nasa.gov/wmts/epsg3413/best/MODIS_Aqua_CorrectedReflectance_Bands721/default/2018-02-08/250m/${z}/${y}/${x}.jpg</ServerUrl>
## </Service>
## <DataWindow>
## <UpperLeftX>-4194304</UpperLeftX>
## <UpperLeftY>4194304</UpperLeftY>
## <LowerRightX>4194304</LowerRightX>
## <LowerRightY>-4194304</LowerRightY>
## <TileLevel>3</TileLevel>
## <TileCountX>2</TileCountX>
## <TileCountY>2</TileCountY>
## <YOrigin>top</YOrigin>
## </DataWindow>
## <Projection>EPSG:3413</Projection>
## <BlockSizeX>512</BlockSizeX>
## <BlockSizeY>512</BlockSizeY>
## <BandsCount>3</BandsCount>
## </GDAL_WMS>
## has GDAL driver WMS
## and has 8192 rows and 8192 columns
## there we have it, a 512x512 level-of-detail read of the entire
## map
## beware, do not print the rgdal object
## just convert to raster and move on
rs <- raster(rs)
plot(rs, col = viridis::viridis(64))
plot(sp::spTransform(wrld_simpl, projection(rastersource)), add = TRUE)

## compare the lazy source at native resolution ...
rastersource
## class : RasterLayer
## band : 1 (of 3 bands)
## dimensions : 8192, 8192, 67108864 (nrow, ncol, ncell)
## resolution : 1024, 1024 (x, y)
## extent : -4194304, 4194304, -4194304, 4194304 (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
## data source : <GDAL_WMS>
## <Service name="TMS">
## <ServerUrl>
## https://gibs.earthdata.nasa.gov/wmts/epsg3413/best/MODIS_Aqua_CorrectedReflectance_Bands721/default/2018-02-08/250m/${z}/${y}/${x}.jpg</ServerUrl>
## </Service>
## <DataWindow>
## <UpperLeftX>-4194304</UpperLeftX>
## <UpperLeftY>4194304</UpperLeftY>
## <LowerRightX>4194304</LowerRightX>
## <LowerRightY>-4194304</LowerRightY>
## <TileLevel>3</TileLevel>
## <TileCountX>2</TileCountX>
## <TileCountY>2</TileCountY>
## <YOrigin>top</YOrigin>
## </DataWindow>
## <Projection>EPSG:3413</Projection>
## <BlockSizeX>512</BlockSizeX>
## <BlockSizeY>512</BlockSizeY>
## <BandsCount>3</BandsCount>
## </GDAL_WMS>
## names : GDAL_WMS.
## values : 0, 255 (min, max)
## ... with the subsampled, in-memory, collected object
rs
## class : RasterLayer
## dimensions : 512, 512, 262144 (nrow, ncol, ncell)
## resolution : 16384, 16384 (x, y)
## extent : -4194304, 4194304, -4194304, 4194304 (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
## data source : in memory
## names : band1
## values : 0, 235 (min, max)
## here's an experimental collect() method
#if (!exists("collect") && is.function(collect)) {
collect <- function(x, ...) {
UseMethod("collect")
}
#}
collect.BasicRaster <- function(x, ..., nrows = 512, ncols = nrows) {
dm <- c(raster::nrow(x), raster::ncol(x))
if (nrows != dm[1] || ncols != dm[2]) {
message(sprintf("%s is %ix%i, collecting output of %ix%i \n %s",
deparse(substitute(x)), dm[1], dm[2], nrows, ncols,
"use 'nrows = , ncols = ' to customize output size"))
}
outdim <- c(nrows, ncols)
outdim <- c(min(dm[1], nrows), min(dm[2], ncols))
offs <- c(0, 0)
if (raster::inMemory(x)) {
warning(sprintf("%s is already in-memory ... any resampling will be approximate", deparse(substitute(x))))
rs <- raster::aggregate(x, fact = dm/outdim)
} else {
rs <- rgdal::readGDAL(x@file@name, offset = offs, region.dim = dm, output.dim = outdim, silent = TRUE)
rs <- raster::raster(rs)
}
rs
}
collect(rastersource, nrows = 768, ncols = 768)
## rastersource is 8192x8192, collecting output of 768x768
## use 'nrows = , ncols = ' to customize output size
## class : RasterLayer
## dimensions : 768, 768, 589824 (nrow, ncol, ncell)
## resolution : 10922.67, 10922.67 (x, y)
## extent : -4194304, 4194304, -4194304, 4194304 (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
## data source : in memory
## names : band1
## values : 0, 243 (min, max)
## in-memory catch
#r <- raster(volcano)
#collect(r, nrows = 5, ncols = 16)
#collect(r)