Skip to content

Instantly share code, notes, and snippets.

@mdsumner
Last active February 20, 2026 00:52
Show Gist options
  • Select an option

  • Save mdsumner/264b80cae0bb1e72d93b22b6edd19a27 to your computer and use it in GitHub Desktop.

Select an option

Save mdsumner/264b80cae0bb1e72d93b22b6edd19a27 to your computer and use it in GitHub Desktop.
##' ESRI Basemap Services
##'
##' Access ESRI ArcGIS Online basemap services via WMTS (preferred) or TMS XML fallback.
##'
##' @param name Character. Name of the basemap service. Use `esri_list()` to see available options.
##' @param url Character. For custom services, provide the MapServer base URL
##' (e.g., "https://services.arcgisonline.com/arcgis/rest/services/Ocean_Basemap/MapServer").
##' @param tile_level Integer. Maximum tile level for TMS XML (default 19).
##' @param bands Integer. Number of bands - 3 for RGB, 4 for RGBA (default 3).
##'
##' @return A GDAL-readable connection string (WMTS:...) or XML block for TMS.
##' @export
##'
##' @examples
##' # WMTS-enabled service (preferred, works with vrt:// etc where minidriver XML requires further indirection)
##' esri("World_Imagery")
##' # Custom service via TMS XML fallback
##' esri(url = "https://services.arcgisonline.com/arcgis/rest/services/Ocean/World_Ocean_Base/MapServer")
esri <- function(name = NULL, url = NULL, tile_level = 19L, bands = 3L) {
wmts <- c("World_Imagery", "World_Street_Map", "World_Topo_Map", "World_Terrain_Base",
"World_Shaded_Relief", "World_Physical_Map", "NatGeo_World_Map", "USA_Topo_Maps")
if (!is.null(name)) {
name <- match.arg(name, wmts)
sprintf("WMTS:https://services.arcgisonline.com/arcgis/rest/services/%s/MapServer/WMTS/1.0.0/WMTSCapabilities.xml,layer=%s", name, name)
} else if (!is.null(url)) {
url <- sub("/$", "", url)
sprintf('<GDAL_WMS><Service name="TMS"><ServerUrl>%s/tile/${z}/${y}/${x}</ServerUrl></Service><DataWindow><UpperLeftX>-20037508.34</UpperLeftX><UpperLeftY>20037508.34</UpperLeftY><LowerRightX>20037508.34</LowerRightX><LowerRightY>-20037508.34</LowerRightY><TileLevel>%d</TileLevel><TileCountX>1</TileCountX><TileCountY>1</TileCountY><YOrigin>top</YOrigin></DataWindow><Projection>EPSG:3857</Projection><BlockSizeX>256</BlockSizeX><BlockSizeY>256</BlockSizeY><BandsCount>%d</BandsCount><Cache/></GDAL_WMS>', url, tile_level, bands)
} else stop("Provide 'name' or 'url'")
}
##' Aspect ratio of dimension conflated with bbox
##'
##' Generate an appropriate dimension (shape, ncol,nrow) from an
##' input width(height). If heignt not specified we have a square.
##'
##' @param size seed dimension size
##' @param wh distance across dimension span/s
##'
##' @return description dimension `c(ncol, nrow)`
##' @examples
##' fit_dims(256, c(10, 20))
##' fit_dims(1024, c(102723, 1e5))
fit_dims <- function(size = 1024L, wh = c(size, size)) {
wh <- rep(wh, length.out = 2L)
w <- wh[1L]; h <- wh[2L];
as.integer(ceiling(size * c(w, h) / max(w, h)))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment