R/TheiaCollection.R

#' A collection of tiles from Theia
#'
#' Generate and manage collection of tiles from Theia. This collection can be
#' created either from a cart file ('.meta4') downloaded from Theia website,
#' from a \code{\link{TheiaQuery}} object or from a list of
#' \code{\link{TheiaTile}} (not implemented yet).
#'
#' @name TheiaCollection
#'
#' @section Usage:
#' \preformatted{
#'    c <- TheiaCollection$new(cart.path = NULL,
#'                             tiles     = NULL,
#'                             query     = NULL,
#'                             dir.path  = NULL,
#'                             check     = TRUE)
#'
#'    c$download(auth, overwrite = FALSE)
#'    c$check()
#'    c$status
#'    c$extract(overwrite = FALSE, dest.dir = NULL)
#'    c$read(bands)
#' }
#'
#' @section Arguments:
#'
#' \describe{
#'    \item{c:}{A \code{TheiaCollection} object}
#'    \item{dir.path:}{The path to the directory containing zip files}
#'    \item{check:}{Whether or not to check existing files on collection's creation}
#'    \item{tiles:}{A list of TheiaTile objects}
#'    \item{cart:}{An XML cart parsed from a 'meta4' file downloaded from Theia}
#'    website. Used only if Collection is created from a cart
#'    \item{query:}{A TheiaQuery object, used only if collection is created
#'    from a TheiaQuery object. Can also be a list with search terms. In this
#'    case, it will create a `TheiaQuery` object from it. See
#'    \code{\link{TheiaQuery}} for details on query syntax}
#'    \item{auth:}{A character string giving the file path to Theia credentials.
#'    Or a \code{\link{TheiaAuth}} object}
#'    \item{overwrite:}{Overwrite existing tiles (default to `FALSE`)}
#'    \item{bands:}{A character vector of bands to load from tiles}
#'  }
#'
#' @section Details:
#'    \code{TheiaCollection$new()} Create a new instance of the class
#'
#'    \code{c$download(overwrite = FALSE)} Download the tiles of the collection
#'    and check the resulting files
#'
#'    \code{$ccheck()} Check the tiles of the collection
#'
#'    \code{c$status} Return the status of each tile of the collection
#'
#'    \code{c$extract(overwrite = FALSE, dest.dir = NULL)} Extract archives to
#'    dest.dir if supplied, or to the same directory as the archives otherwise
#'
#'    \code{c$read(bands)} Read requested bands, apply corrections on values
#'    (as specified in Theia's product information), and return a list of
#'    RasterStack objects (one stack per tile)
#'
#' @examples
#'
#' \donttest{
#' # Create a collection from a query
#' ## Create a query to Theia database, looking for tiles from Sentinel2
#' ## satellite around Grenoble, between 2018-07-01 and 2018-07-06.
#'
#' query <- list(collection = "SENTINEL2",
#'               town       = "Grenoble",
#'               start.date = "2018-07-01",
#'               end.date   = "2018-07-06")
#'
#' ## Create a collecion of tiles from this query
#' mycollection <- TheiaCollection$new(query = query, dir.path = ".")
#' 
#' print(mycollection)
#' }
#'
#' # Alternatively, you can create a collection from a cart file (that you can
#' # download from Theia's website)
#' cart.path <- system.file("extdata", "cart.meta4", package = "theiaR")
#' 
#' mycollection <- TheiaCollection$new(cart.path = cart.path,
#'                                     dir.path  = ".")
#' 
#' print(mycollection)
#'
#' \dontrun{
#' # Download the tiles in the collection
#' mycollection$download()
#' }
#'
#' \dontrun{
#' # Finally, you can extract zip archives containing the tiles
#' mycollection$extract(overwrite = FALSE)
#' }
#'
NULL


#' @export

TheiaCollection <-
  R6Class("TheiaCollection",
          # public -------------------------------------------------------------
          public =
            list(cart       = NULL,
                 tiles      = NULL,
                 query      = NULL,
                 collection = NA,
                 dir.path   = NULL,

                 initialize = function(cart.path  = NULL,
                                       tiles      = NULL,
                                       query      = NULL,
                                       dir.path   = NULL,
                                       check      = TRUE)
                 {
                   .TheiaCollection_initialize(self, cart.path, tiles, query, dir.path, check)
                 },

                 print = function(...)
                 {
                   .TheiaCollection_print(self)
                 },

                 check = function()
                 {
                   .TheiaCollection_check(self)
                 },

                 download = function(auth, overwrite = FALSE)
                 {
                   .TheiaCollection_download(self, auth, overwrite)
                 },

                 extract = function(overwrite = FALSE, dest.dir = NULL)
                 {
                   .TheiaCollection_extract(self, private, overwrite, dest.dir)
                 },
                  
                 read = function(bands)
                 {
                   .TheiaCollection_read(self, private, bands)
                 }),

            # active -----------------------------------------------------------
            active =
              list(status = function()
                   {
                     .TheiaCollection_status(self)
                   })
  )


# Functions definitions --------------------------------------------------------

.TheiaCollection_print <- function(self)
{
  # Special method to print
  cat("An collection of tiles from Theia\n\n")

  cat("Number of tiles:", length(self$tiles), "\n")
  cat("Directory path : '", self$dir.path, "'\n", sep = "")

  if (!is.null(self$query)) {
    cat("\n")

    cat("Obtained from query\n")
  } 

  if (!is.null(self$cart)) {
    cat("\n")

    cat("Obtained from cart file\n")
  }

  return(invisible(self))
}


.TheiaCollection_initialize <- function(self, cart.path, tiles, query, dir.path, check)
{
  # fill dir.path field
  self$dir.path <- check_dir(dir.path)

  if (!(is.null(cart.path))) {
    # build collection from cart file ------------------------------------------
    # parse xml data contained in '.meta4' cart file
    self$cart <- XML::xmlToList(XML::xmlParse(cart.path))

    # create needed TheiaTile objects
    self$tiles <-
      lapply(self$cart[-1],
             function(x) {
               TheiaTile$new(file.path = paste0(self$dir.path, as.character(x$.attrs)),
                             file.hash = as.character(x$hash),
                             url       = as.character(x$url$text),
                             tile.name = as.character(x$.attrs),
                             check)
             })

  } else if (!(is.null(tiles))) {
    # TODO: Implement building from a list of tiles
    # build from list of tiles

  } else if (!(is.null(query))) {
    # build collection from a TheiaQuery object --------------------------------
    if (is.list(query)) {
      # automatically build TheiaQuery object if needed
      self$query <- TheiaQuery$new(query)
    } else {
      # clone TheiaQuery object
      self$query <- query$clone()
    }

    # create needed TheiaTile objects
    self$tiles <-
      apply(self$query$tiles, 1,
            function(x) {
              TheiaTile$new(file.path = paste0(self$dir.path, x[1]),
                            file.hash = as.character(x[3]),
                            url       = as.character(x[6]),
                            tile.name = as.character(x[1]),
                            check)
            })

  }

  # give names to the tiles
  names(self$tiles) <- lapply(self$tiles, function(x) x$tile.name)

  # fill collection field
  self$collection <- self$tiles[[1]]$collection

  return(invisible(self))
}


.TheiaCollection_check <- function(self)
{
  # check all the tiles
  lapply(self$tiles, function(x) x$check())

  return(invisible(self))
}


.TheiaCollection_download <- function(self, auth, overwrite)
{
  if (is.character(auth)) {
    # create authentification system if not supplied
    auth <- TheiaAuth$new(auth.file = auth)
  }

  # download needed tiles
  lapply(self$tiles,
         function(x, auth, overwrite) {
           x$download(auth, overwrite = overwrite)
         },
         auth = auth, overwrite = overwrite)

  return(invisible(self))
}


.TheiaCollection_status <- function(self)
{
  status <- lapply(self$tiles,
                   function(x)
                   {
                     c(x$file.path, unlist(x$status))
                   })
  status <- do.call(rbind, status)
  status <- as.data.frame(status)
  colnames(status) <- c("tile", "exists", "checked", "correct", "extracted")
  rownames(status) <- NULL

  # format tiles names
  status$tile <- gsub(self$dir.path, "", status$tile)
  status$tile <- gsub(".zip$", "", status$tile)

  return(status)
}


.TheiaCollection_extract <- function(self, private, overwrite, dest.dir)
{
  # extract all tiles
  file.path <- lapply(self$tiles,
                      function(x, overwrite, dest.dir) {
                        x$extract(overwrite = overwrite, dest.dir = dest.dir)
                      }, overwrite = overwrite, dest.dir = dest.dir)

  return(invisible(unlist(file.path)))
}


.TheiaCollection_read <- function(self, private, bands)
{
  # read bands from tiles and return a list of RasterStack objects
  tiles.list <- lapply(self$tiles, function(x) x$read(bands))

  return(tiles.list)
}

Try the theiaR package in your browser

Any scripts or data that you put into this service are public.

theiaR documentation built on May 2, 2019, 11:22 a.m.