#==============================================================================
#' @title Get URL of CDED NTS tile
#'
#' @param NTS character NTS string in format DDDLDD or DDDL (d=digit, L=letter)
#' e.g 075M05 or 014K
#'
#' @return character path to CDED DEM tile for selected NTS sheet
#'
#' @export
#'
#' @keywords internal
#===============================================================================
CDEDGetTilePath <- function(NTS){
NTS <- tolower(NTS)
resolution <- switch(as.character(nchar(NTS)), "6" = "50k_dem", "4" = "250k_dem")
basepath <- "http://ftp.geogratis.gc.ca/pub/nrcan_rncan/archive/elevation/geobase_cded_dnec" ### these files don't always tile properly at 250k
ftp_path <- paste(basepath, resolution, substr(NTS, 1, 3), NTS, sep = "/")
ftp_path <- paste0(ftp_path, ".zip")
return(ftp_path)
}
#==============================================================================
#' @title Get URL of CDEM NTS tile
#'
#' @param NTS character, NTS string in format DDDLDD or DDDL (D=digit, L=letter)
#' e.g 075M05 or 014K
#'
#' @param product character string specifying which data product to get (one of
#' "CDEM', 'CDED', 'CDSM')
#'
#' @return character path to CDED DEM tile for selected NTS sheet
#'
#' @export
#'
#' @keywords internal
#==============================================================================
CDEMGetTilePath <- function(NTS, product="CDEM"){
NTS <- toupper(NTS)
basepath <- "http://ftp.geogratis.gc.ca/pub/nrcan_rncan/elevation/cdem_mnec"
DEM_name <- paste("cdem_dem", NTS, "tif.zip", sep = "_")
ftp_path <- paste(basepath, substr(NTS, 1, 3), DEM_name, sep = "/")
return(ftp_path)
}
#==============================================================================
#' @title Get FTP path for NTS DEM tile
#'
#' @param NTS character, NTS tile name in format DDDLDD or DDDL (d=digit,
#' L=letter) e.g 075M05 or 014K
#'
#' @param product character string specifying which data product to get (one of
#' 'CDEM', 'CDED', 'CDSM')
#'
#' @return character, FTP path to desired NTS tile
#==============================================================================
GetNTSDEMTilePath <- function(NTS, product="CDED"){
NTS <- tolower(NTS)
resolution <- switch(as.character(nchar(NTS)), "6" = "50k_dem", "4" = "250k_dem")
# base URL for each data product
basepath <- switch(product,
"CDED" = "http://ftp.geogratis.gc.ca/pub/nrcan_rncan/archive/elevation/geobase_cded_dnec", # these files don't tile properly at 250k
"CDEM" = "http://ftp.geogratis.gc.ca/pub/nrcan_rncan/elevation/cdem_mnec",
"CDSM" = "http://ftp.geogratis.gc.ca/pub/nrcan_rncan/elevation/cdsm_mnsc")
# construct ftp path depending on which data product is to be used
ftp_path <- switch(product,
"CDED" = paste(basepath, resolution, substr(NTS, 1, 3), NTS, sep = "/"),
"CDEM" = paste(basepath, substr(NTS, 1, 3),
paste("cdem_dem",
toupper(NTS), "tif", sep = "_"), sep = "/"),
"CDSM" = paste(basepath,
substr(NTS, 1, 3),
paste0(toupper(NTS), "_cdsm_final"), sep = "/"))
ftp_path <- paste0(ftp_path, ".zip")
return(ftp_path)
}
#==============================================================================
#' @title Download DEM Sheet
#'
#' @param NTS character string, name of NTS tile (e.g. '075C' or '014D03') or
#' USGS NED tile. If specified as a 250k tile (4 characters), a 250k tile will
#' be downloaded. If specified as a 50k tile (6 character) then a 50k tile will
#' be downloaded.
#'
#' @param DEM_dir character string, path to directory where DEM tiles are stored.
#' This function creates a nested file hierarchy that matches that of the FTP site
#'
#' @param replace logical, degaults to FALSE, whether or not files should be
#' re-downloaded if they already exist in the DEM_dir directory
#'
#' @param product character string specifying which data product to get (one of
#' 'CDEM', 'CDED', 'CDSM', or 'NED')
#'
#' @description downloads DEM tiles from
#' "http://ftp.geogratis.gc.ca/pub/nrcan_rncan/elevation" and unzips
#' them to a directory
#'
#' @details CDED and CDEM are from NRCAN. NED uses USGS National Elevation Dataset.
#'
#' @return a vector of file paths to downloaded DEM files
#'
#' @export
#==============================================================================
DownloadSingleDEM <- function(DEM_id, DEM_dir, replace=F, product="CDED"){
output <- T
# construct ftp path to be queried
ftp_path <- switch(product,
"CDED" = GetNTSDEMTilePath(DEM_id, product = "CDED"),
"CDEM" = GetNTSDEMTilePath(DEM_id, product = "CDEM"),
"CDSM" = GetNTSDEMTilePath(DEM_id, product = "CDSM"),
"NED" = USGSTileURL(name = DEM_id),
"ADEM" = ARCTICTileURL(name = DEM_id))
# create appropriate file name / directory structure based on ftp path
file_paths <- rev(rev(strsplit(ftp_path, "/")[[1]])[1:3])
dir.create(file.path(DEM_dir, paste(file_paths[1:2], collapse = "/")),
showWarnings = F, recursive = T)
destfile <- file.path(DEM_dir, paste(file_paths, collapse = "/"))
if (grepl("tar\\.gz", destfile)){
dest_dir <- gsub("\\.tar\\.gz", "", destfile)
}else{
dest_dir <- gsub("\\.zip", "", destfile)
}
# Check to see if file already exists
if (!replace & dir.exists(dest_dir)){
cat(sprintf("%s exists locally and was not downloaded\n\n", DEM_id))
}else{
output <- DownloadAndUnzip(url = ftp_path, destfile = destfile, exdir = dest_dir)
}
# If an appropriate file was downloaded, return the corresponding file paths
if (output){
pattern <- switch(product,
"CDED" = "dem[ew_].*(\\<tif\\>|\\<dem\\>)$",
"CDEM" = "dem[ew_].*(\\<tif\\>|\\<dem\\>)$",
"CDSM" = ".*_cdsm_final_[ew]\\.tif",
"NED" = "flt$",
"ADEM" = "reg_dem\\.tif$")
dem <- list.files(path = dest_dir, pattern = pattern, full.names = T)
return(dem)
}else{
return(c(NA, NA))
}
}
#==============================================================================
#' @title Download and unzip a file
#'
#' @description Downloads a zipfile from a URL and unzips it to a target
#' directory.
#'
#' @details Runs as a subroutine of \link{DownloadSingleDEM}
#'
#' @param url character url path
#'
#' @param destfile character, filepath of output zipfile
#'
#' @param exdir character, the directory to which files are extracted
#'
#' @param rmzip logical, whether or not to remove zipfile after extraction.
#' Defaults to TRUE.
#==============================================================================
DownloadAndUnzip <- function(url, destfile, exdir, rmzip=T){
output <- tryCatch({
download.file(url = url, destfile = destfile,
quiet = FALSE, mode = "wb", cacheOK = TRUE)
if (grepl("tar\\.gz", destfile)){
untar(tarfile = destfile, exdir = exdir)
}else{
unzip(zipfile = destfile, exdir = exdir)
}
if (rmzip){
file.remove(destfile)
}
return(TRUE)
},
error = function(e){
message(paste("Fauly DEM path or NTS tile does not exist"))
return(FALSE)
},
warning = function(w){
message(paste("Fauly DEM path or NTS tile does not exist"))
return(FALSE)
})
}
#==============================================================================
#' @title Download Multiple DEM files
#'
#' @description a wrapper for \link{DownloadSingleDEM} that allows a vector of
#' NTS sheets
#' or USGS DEM tile names to be specified
#'
#' @param DEM character string, name of DEM tile (e.g. '075C' or '014D03'). If
#' specified as
#' a 250k tile (4 characters), a 250k tile will be downloaded. If specified as a
#' 50k tile (6 character)
#' then a 50k tile will be downloaded.
#'
#' @param DEM_dir character string, path to directory where DEM tiles are stored.
#' This function creates a nested
#' file hierarchy that matches that of the FTP site.
#'
#' @param force50k logical, returns 50k tiles instead of 250k tiles even if the
#' tiles are specified as 250k tiles.
#' e.g. using "075C" would use 075C01, 075C02, 075C03 and so on.
#'
#' @param product either 'CDEM' or 'CDED'. Which dataset to download
#'
#' @export
#==============================================================================
DownloadMultipleDEM <- function(DEM, DEM_dir, force50k=F, product="CDED"){
# sanity check - make sure NTS names are well-formed
if (toupper(product) %in% c("CDED", "CDEM", "CDSM") &
!all(grepl("^\\d{3}[[:alpha:]](\\d{2})?$", DEM))){
stop("Bad format for one or more NTS strings")
}
if (force50k & product %in% c("CDED", "CDSM")){
DEM <- unlist(lapply(DEM, function(x)
paste0(x, sprintf("%02d", seq(1, 16)))))
}
# download each DEM file using the apply function
files <- t(sapply(DEM, DownloadSingleDEM, DEM_dir = DEM_dir,
replace = F, product = product))
files <- as.character(na.omit(files))
return(files)
}
#==============================================================================
#' @title Create DEM mosaic
#'
#' @description Downloads a set of DEM tiles and moasaicks them into one SAGA
#' grid file.
#'
#' @param DEM character vector, names of NTS tiles (e.g. '075C' or '014D03') or
#' USGS NED 1arc-sec tiles (e.g. 'n52e104'). If specified as a 250k NTS tile
#' (4 characters), a 250k NTS tile will be downloaded. If specified as a 50k
#' NTS tile (6 character) then a 50k NTS tile will be downloaded.
#'
#' @param DEM_dir character string, path to directory where DEM tiles are stored.
#' This function creates a nested file hierarchy that matches that of the
#' FTP site.
#'
#' @param output_dir character string specifying where output file should be saved
#'
#' @param force50k logical, returns 50k tiles instead of 250k tiles even if the
#' tiles are specified as 250k tiles. e.g. using "075C" would use 075C01, 075C02,
#' 075C03 and so on. Ignored if using 'NED' as data product.
#'
#' @param product character, which DEM product to use. One of ('CDED', 'CDEM',
#' 'NED')
#'
#' @return name of output DEM
#'
#' @examples
#'
#' CompileDEM("035D", "~", "~", "~/NTSmosaic.sdat", force50k = T)
#'
#' @export
#==============================================================================
CompileDEM <- function(DEM, DEM_dir, output_dir, force50k = F, product = "CDED"){
files <- DownloadMultipleDEM(DEM = DEM, DEM_dir = DEM_dir, force50k = force50k,
product = product)
dstfile <- file.path(output_dir, "NTS_mosaic.sdat")
gdal_mosaic(srcfiles = files[file.exists(files)], dstfile = dstfile,
of = "SAGA", srcnodata = -32767)
output <- gdal_warp2SAGA(dstfile, srcnodata = -32768,
output_crs = "+proj=aea +lat_1=50 +lat_2=70 +lat_0=40 +lon_0=-96
+x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs")
file.remove(dstfile)
return(output)
}
#==============================================================================
#' @title Create DEM mosaic to cover spatial object
#'
#' @description Covers a shape with a DEM grid
#'
#' @param geom1 An R Spatial* object to be covered with the DEM
#'
#' @param tileindex spatialpointspolygon of DEM tile indices or path to
#' shapefile of tile index
#'
#' @param DEM_dir directory where DEM tiles are stored
#'
#' @param output_dir where output DEM should be saved
#'
#' @param tileid_field Name of column in tileindex that gives DEM sheet number
#'
#' @param tol (optional) how wide should geom1 be buffered (metres) before
#' determining how big the DEM needs to be to cover it
#'
#' @param ... optional arguments passed to \link{CompileDEM}
#'
#' @details Builds a DEM from elevation dataset that either extends a fixed
#' distance on either side of a spatialobject (if a tol(erace) is specified) or
#' intersects the DEM index (if tileindex is specified)
#'
#' @return name of output DEM
#'
#' @export
#==============================================================================
OverlayDEM <- function(geom1, tileindex, DEM_dir, output_dir, tol,
product="CDED", tileid_field="NTS_SNRC", ...){
# get DEM names
if (!missing(tol)){
# use geometry points
if (product %in% c("CDED", "CDEM", "CDSM")){
atscale <- ifelse(toupper(product) == "CDEM", 1, 2)
tiles <- rcanvec::nts(bbox = ExpandBBox(geom1, tol), atscale = atscale)
# convert to a character vector
if (class(tiles) == "list"){
tile_names <- sapply(tiles, paste, collapse = "")
}else{
tile_names <- paste(tiles, collapse = "")
}
}else if (product == "NED"){
tile_names <- NEDcoverage(geom1, tol)
}
}else if (!missing(tileindex)){
# use tile index
tile_names <- TileIndex(geom1, tileindex, tileid_field)
}
# build and mosaic
grid <- CompileDEM(DEM = tile_names, DEM_dir = DEM_dir, output_dir = output_dir,
product = product, ...)
# return grid name
return(grid)
}
#==============================================================================
#' @title USGS Tile URL
#'
#' @description Returns the URL of a USGS NED elevation tile
#'
#' @param lon longitude in degrees as an integer
#'
#' @param lat latitude in degrees as an integer
#'
#' @param name (optional)
#'
#' @return file path
#==============================================================================
USGSTileURL <- function(lon, lat, name, test=TRUE){
baseURL <- "https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1/GridFloat/"
if (missing(name)){
name <- USGSTileName(lon, lat, fext = ".zip")
}else{
name <- paste0(name, ".zip")
}
fullpath <- sprintf("%s%s", baseURL, name)
if (test & http_error(fullpath)){
if (!missing(lon)){
name <- USGSTileName(lon, lat, fext = ".zip", v='2017')
fullpath <- sprintf("%s%s", baseURL, name)
}else{
fullpath <- sub(name, paste0("USGS_NED_1_",name), fullpath)
fullpath <- sub("\\.zip", "_GridFloat.zip", fullpath)
}
}
return(fullpath)
}
#==============================================================================
#' @title USGS Tile name from coordinates
#'
#' @description Returns the base file name of a USGS NED elevation tile that
#' covers a set of coordinates
#'
#' @param lon longitude in degrees as an integer
#'
#' @param lat latitude in degrees as an integer
#'
#' @param fext file extension to append to file name
#'
#' @return a character string of format "n00w000%s"
#==============================================================================
USGSTileName <- function(lon, lat, fext="", v="2013"){
if (v=="2013"){
name <- sprintf("n%0.2dw%0.3d%s", abs(lat), abs(lon), fext)
}else if (v=="2017"){
name <- sprintf("usgs_ned_1_n%0.2dw%0.3d_gridfloat%s", abs(lat), abs(lon), fext) # July 2018 update
}
return(name)
}
#==============================================================================
#' @title ARCTIC DEM Tile name from coordinates
#'
#' @description Returns the base file name of an ARCTIC DEM elevation tile
#'
#' @param lon longitude in degrees
#'
#' @param lat latitude in degrees
#'
#' @param fext file extension to append to file name
#'
#' @return a character string
#==============================================================================
ARCTICTileName <- function(lon, lat, fext=""){
# convert to NSIDC polar coords (epsg: 3413 )
pt <- SpatialPoints(data.frame(x=lon, y=lat), proj4string = CRS("+init=epsg:4326"))
pt <- sp::spTransform(pt, CRS("+init=epsg:3413"))
x <- pt@coords[1, 1]
y <- pt@coords[1, 2]
# find which band
ymin_band <- floor(y / 100000) * 100000
band <- 41 + ymin_band / 100000
# find which column
xmin_col <- floor(x / 100000) * 100000
col <- 41 + (xmin_col / 100000)
# find which sub-square
xc <- 1 + floor(x / 50000) %% 2
yc <- 1 + floor(y / 50000) %% 2
tile <- sprintf("%02d_%02d_%01d_%01d_5m_v2.0%s", band, col, xc, yc, fext)
return(tile)
}
#==============================================================================
#' @title ARCTIC DEM Tile URL
#'
#' @description Returns the URL of a ARCTIC DEM elevation tile
#'
#' @param lon longitude in degrees as an integer
#'
#' @param lat latitude in degrees as an integer
#'
#' @param name (optional) tilename
#'
#' @return file path
#==============================================================================
ARCTICTileURL <- function(lon, lat, name){
if (missing(name)){
name <- ARCTICTileName(lon, lat, fext = ".tar.gz")
}else{
name <- paste0(name, ".tar.gz")
}
return(sprintf("ftp://ftp.data.pgc.umn.edu/elev/dem/setsm/ArcticDEM/mosaic/v2.0/%s/%s", substr(name, 1, 5), name))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.