getTile.R 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #' Get MODIS Tile ID(s)
  2. #'
  3. #' @description
  4. #' Get MODIS tile ID(s) for a specific geographic area.
  5. #'
  6. #' @param x Extent information, see Details. Ignored if \code{tileH} and
  7. #' \code{tileV} are specified.
  8. #' @param tileH,tileV \code{numeric} or \code{character}. Horizontal and
  9. #' vertical tile number(s) of the
  10. #' \href{https://nsidc.org/data/docs/daac/mod10_modis_snow/landgrid.html}{MODIS Sinusoidal grid}
  11. #' (e.g., \code{tileH = 1:5}). If specified, no cropping is performed and the
  12. #' full tile(s) (if more than one then also mosaicked) is (are) processed!
  13. #'
  14. #' @return
  15. #' A \code{MODISextent} object.
  16. #'
  17. #' @author
  18. #' Matteo Mattiuzzi, Florian Detsch
  19. #'
  20. #' @seealso
  21. #' \code{\link{extent}}, \code{\link{map}}, \code{\link{search4map}}.
  22. #'
  23. #' @note
  24. #' \strong{MODIS} does no longer support the tile identification and automated
  25. #' download of MERIS and SRTM data. At least as far as the latter is concerned,
  26. #' easy data access is granted through \code{\link{getData}}.
  27. #'
  28. #' @details
  29. #' If \code{x} is of class (see Examples for use cases)
  30. #' \tabular{ll}{
  31. #' \code{missing}:\cr
  32. #' \tab If 'tileH,tileV' are specified, 'x' will be ignored. If no such tile
  33. #' indices are provided and 'x' is missing, a viewer window pops up that
  34. #' allows interactive tile selection from the global MODIS Sinusoidal grid.\cr
  35. #' \cr
  36. #' \code{character}:\cr
  37. #' \tab Either the country name of a \code{map} object (see \code{\link{map}})
  38. #' or a valid file path of a raster image or ESRI shapefile (shp). The former
  39. #' approach also supports pattern matching via regular expressions.\cr
  40. #' \cr
  41. #' \code{Raster*}:\cr
  42. #' \tab Spatial extent, resolution, and projection of the specified
  43. #' \code{Raster*} are determined automatically. This information is used by
  44. #' \code{\link{runGdal}} to create perfectly matching files. If the
  45. #' \code{Raster*} comes with no valid CRS,
  46. #' \href{http://spatialreference.org/ref/epsg/wgs-84/}{EPSG:4326} is assumed.\cr
  47. #' \cr
  48. #' \code{Extent}:\cr
  49. #' \tab Boundary coordinates from \code{Extent} objects are assumed to be in
  50. #' \href{http://spatialreference.org/ref/epsg/wgs-84/}{EPSG:4326} as well as
  51. #' such objects have no projection information attached.\cr
  52. #' \cr
  53. #' Other:\cr
  54. #' \tab \code{Spatial}, \code{sf}, or \code{map} object.
  55. #' }
  56. #'
  57. #' @examples
  58. #' \dontrun{
  59. #' # ex 1 ############
  60. #' # interactive tile selection
  61. #' getTile()
  62. #'
  63. #' # ex 2: Spatial (taken from ?rgdal::readOGR) ############
  64. #' dsn <- system.file("vectors/Up.tab", package = "rgdal")[1]
  65. #' Up <- rgdal::readOGR(dsn, "Up")
  66. #' getTile(Up)
  67. #'
  68. #' # ex 3: sf ############
  69. #' library(mapview)
  70. #' getTile(franconia)
  71. #'
  72. #' # ex 4: tileH,tileV ############
  73. #' getTile(tileH = 18:19, tileV = 4)
  74. #'
  75. #' # ex 5: Raster* with valid CRS ############
  76. #' rst1 <- raster(xmn = 9.2, xmx = 17.47, ymn = 46.12, ymx = 49.3)
  77. #' getTile(rst1)
  78. #'
  79. #' # this also works for projected data
  80. #' rst3 <- projectExtent(rst1, crs = "+init=epsg:32633")
  81. #' getTile(rst3)
  82. #'
  83. #' # ex 6: Raster* without CRS or, alternatively, Extent -> treated as EPSG:4326 ############
  84. #' mat2 <- matrix(seq(180 * 360), byrow = TRUE, ncol = 360)
  85. #' rst2 <- raster(mat2)
  86. #' getTile(rst2)
  87. #' getTile(extent(rst1))
  88. #'
  89. #' # ex 7: map names as returned by search4map() ############
  90. #' getTile("Austria")
  91. #' getTile(c("Austria", "Germany"))
  92. #'
  93. #' # or search for specific map name patterns (use with caution):
  94. #' m1 <- search4map("Per")
  95. #' getTile(m1)
  96. #'
  97. #' # or use 'map' objects directly (remember to use map(..., fill = TRUE)):
  98. #' m2 <- map("state", region = "new jersey", fill = TRUE)
  99. #' getTile(m2)
  100. #' }
  101. #'
  102. #' @export getTile
  103. #' @name getTile
  104. getTile <- function(x = NULL, tileH = NULL, tileV = NULL) {
  105. # if 'x' is a Raster*/Spatial* and has a different CRS, the information is added here
  106. target <- NULL
  107. if (all(!is.null(tileH), !is.null(tileV))) {
  108. if (!is.numeric(tileH)) tileH <- as.numeric(tileH)
  109. if (!is.numeric(tileV)) tileV <- as.numeric(tileV)
  110. tt <- tiletable[(tiletable$ih %in% tileH) &
  111. (tiletable$iv %in% tileV) & (tiletable$xmin >- 999), ]
  112. x <- raster::extent(c(min(tt$xmin), max(tt$xmax), min(tt$ymin), max(tt$ymax)))
  113. tt$iv <- sprintf("%02d", tt$iv)
  114. tt$ih <- sprintf("%02d", tt$ih)
  115. tileH <- sprintf("%02d",tileH)
  116. tileV <- sprintf("%02d",tileV)
  117. tilesSUB <- as.character(apply(tt,1, function(x) {
  118. paste0("h", x[2], "v", x[1])
  119. }))
  120. tiles <- as.character(sapply(tileH, function(x){paste0("h", x, "v", tileV)}))
  121. if (!all(tiles %in% tilesSUB)) # all possible tiles vs all available
  122. {
  123. rem <- paste0(tiles[!tiles %in% tilesSUB],collapse=", ")
  124. cat(paste0("The following 'tiles' do not exist:\n",rem,"\n"))
  125. tiles <- tilesSUB
  126. tileH <- unique(tt$ih)
  127. tileV <- unique(tt$iv)
  128. }
  129. } else {
  130. fromMap <- FALSE
  131. prj <- sp::CRS("+init=epsg:4326")
  132. # if 'x' is null, do mapSelect. Output class extent.
  133. if (is.null(x)) {
  134. x <- mapSelect()
  135. }
  136. # filename string to Raster/vector conversion
  137. if(inherits(x,"character") & length(x)==1) # lengh>1 it should be only a mapname for maps:::map
  138. {
  139. if (raster::extension(x)=='.shp')
  140. {
  141. x <- shapefile(x)
  142. } else
  143. {
  144. if (file.exists(x))
  145. {
  146. x <- raster(x)
  147. }
  148. }
  149. }
  150. # character (country name of MAP) to maps::map conversion
  151. if (inherits(x, "character"))
  152. {
  153. try(testm <- maps::map("worldHires", x, plot = FALSE),silent = TRUE)
  154. if (!exists("testm"))
  155. {
  156. stop(paste0("Country name not valid. Check availability/spelling, i.e. try if it works with: map('worldHires,'",x, "'), or use '?search4map' function"))
  157. }
  158. x <- maps::map("worldHires", x, plot = FALSE, fill=TRUE)
  159. }
  160. # maps::map (from mapdata/maps) to SpatialPolygons
  161. if (inherits(x, "map")) {
  162. x = maptools::map2SpatialPolygons(x, x$names, prj, checkHoles = TRUE)
  163. }
  164. # this needs to be done in order to use rgdal:::over to intersect geometies
  165. if (inherits(x, c("Raster", "Spatial"))) {
  166. target <- list(outProj = raster::projection(x)
  167. , extent = raster::extent(x)
  168. , pixelSize = NULL)
  169. if (inherits(x, "Raster"))
  170. target$pixelSize <- raster::res(x)
  171. # if required, spTransform() extent object
  172. if (!raster::compareCRS(x, prj) & !is.na(target$outProj)) {
  173. x <- if (inherits(x, "Raster")) {
  174. raster::extent(raster::projectExtent(x, prj))
  175. } else {
  176. sp::spTransform(x, prj)
  177. }
  178. } else if (is.na(target$outProj)) {
  179. raster::projection(x) <- prj
  180. }
  181. # sf method
  182. } else if (inherits(x, "sf")) {
  183. target <- list(outProj = sf::st_crs(x)$proj4string
  184. , extent = raster::extent(sf::st_bbox(x)[c(1, 3, 2, 4)])
  185. , pixelSize = NULL)
  186. if (!raster::compareCRS(target$outProj, prj)) {
  187. x <- sf::st_transform(x, prj@projargs)
  188. }
  189. }
  190. # if (inherits(x, 'Extent')) {
  191. # x <- as(x, 'SpatialPolygons')
  192. # sp::proj4string(x) <- prj
  193. # }
  194. if (inherits(x, "sf"))
  195. x <- methods::as(x, "Spatial")
  196. ## capture errors related to orphaned holes and self-intersection
  197. if (inherits(x, 'Spatial')) {
  198. isValid = try(rgeos::gIsValid(x, reason = TRUE), silent = TRUE)
  199. if (inherits(isValid, "try-error")) {
  200. x = fixOrphanedHoles(x)
  201. } else if (inherits(isValid, "character")) {
  202. if (grepl("Self-intersection", isValid)) {
  203. x = suppressWarnings(
  204. rgeos::gBuffer(x, byid = TRUE, width = 0)
  205. )
  206. }
  207. }
  208. }
  209. selected <- raster::crop(sr, x)
  210. tileH <- unique(selected@data$h)
  211. tileV <- unique(selected@data$v)
  212. tiles <- as.character(apply(selected@data,1,function(x) {paste("h",sprintf("%02d",x[2]),"v",sprintf("%02d",x[3]),sep="")}))
  213. }
  214. result = methods::new("MODISextent"
  215. , tile = tiles
  216. , tileH = as.integer(tileH)
  217. , tileV = as.integer(tileV)
  218. , extent = x
  219. , system = "MODIS"
  220. , target = target)
  221. return(result)
  222. }
  223. mapSelect <- function() {
  224. grd <- sf::st_as_sf(sr, quiet = TRUE)
  225. sel <- mapedit::selectFeatures(grd)
  226. return(sel)
  227. }