#------------------------------------------------
# if NULL then replace with chosen value, otherwise keep original value
#' @noRd
define_default <- function(x, default) {
if (is.null(x)) {
return(default)
} else {
return(x)
}
}
#------------------------------------------------
# if a single value is provided then expand to a vector of length n
#' @noRd
force_vector <- function(x, n) {
if (length(x) == 1) {
return(rep(x,n))
} else {
return(x)
}
}
# -----------------------------------
# ask user a yes/no question. Return TRUE/FALSE.
#' @noRd
user_yes_no <- function(x = "continue? (Y/N): ") {
user_choice <- NA
while (!user_choice %in% c("Y", "y" ,"N", "n")) {
user_choice <- readline(x)
}
return(user_choice %in% c("Y", "y"))
}
# -----------------------------------
# takes matrix as input, converts to list format for use within Rcpp code
#' @noRd
matrix_to_rcpp <- function(x) {
return(split(x, f = 1:nrow(x)))
}
# -----------------------------------
# takes list format returned from Rcpp and converts to matrix
#' @noRd
rcpp_to_matrix <- function(x) {
ret <- matrix(unlist(x), nrow = length(x), byrow = TRUE)
return(ret)
}
# -----------------------------------
# takes list format returned from Rcpp and converts to three-dimensional array.
# Array indexing is in the same order as the underlying list, for example
# x[i,j,k] is equivalent to l[[i]][[j]][[k]]
#' @noRd
rcpp_to_array <- function(x) {
ret <- array(unlist(x), dim = c(length(x[[1]][[1]]), length(x[[1]]), length(x)))
ret <- aperm(ret, perm = c(3,2,1))
return(ret)
}
#------------------------------------------------
# return 95% quantile
#' @importFrom stats quantile
#' @noRd
quantile_95 <- function(x) {
ret <- quantile(x, probs = c(0.025, 0.5, 0.975))
names(ret) <- c("Q2.5", "Q50", "Q97.5")
return(ret)
}
#------------------------------------------------
# sum logged values without underflow, i.e. do log(sum(exp(x)))
#' @noRd
log_sum <- function(x) {
if (all(is.na(x))) {
return(rep(NA, length(x)))
}
x_max <- max(x, na.rm = TRUE)
ret <- x_max + log(sum(exp(x - x_max)))
return(ret)
}
#------------------------------------------------
# update progress bar
# pb_list = list of progress bar objects
# name = name of this progress bar
# i = new value of bar
# max_i = max value of bar (close when reach this value)
# close = whether to close when reach end
#' @importFrom utils setTxtProgressBar
#' @noRd
update_progress <- function(pb_list, name, i, max_i, close = TRUE) {
setTxtProgressBar(pb_list[[name]], i)
if (i == max_i & close) {
close(pb_list[[name]])
}
}
#------------------------------------------------
#' @title Print unclassed object
#'
#' @description Print object after unclassing, thereby removing any custom print
#' method.
#'
#' @param x object to print in full.
#'
#' @export
print_full <- function(x) {
print(unclass(x))
}
#------------------------------------------------
#' @title Get great circle distance between spatial points
#'
#' @description Get great circle distance between spatial points, defined by a
#' vector of longitudes and latitudes. Distances are returned in a pairwise
#' distance matrix.
#'
#' @param long,lat vector of longitudes and latitudes.
#'
#' @export
get_spatial_distance <- function(long, lat) {
# check inputs
assert_vector(long)
assert_numeric(long)
assert_vector(lat)
assert_numeric(lat)
assert_same_length(long, lat)
# calculate distance matrix
ret <- apply(cbind(long, lat), 1, function(y) {lonlat_to_bearing(long, lat, y[1], y[2])$gc_dist})
ret <- as.dist(ret, upper = TRUE)
return(ret)
}
#------------------------------------------------
#' @title Calculate great circle distance and bearing between coordinates
#'
#' @description Calculate great circle distance and bearing between spatial
#' coordinates, defined by longitude and latitude of both origin and
#' destination points.
#'
#' @param origin_lon,origin_lat the origin longitude and latitude.
#' @param dest_lon,dest_lat the destination longitude and latitude
#'
#' @export
#' @examples
#' # one degree longitude should equal approximately 111km at the equator
#' lonlat_to_bearing(0, 0, 1, 0)
lonlat_to_bearing <- function(origin_lon, origin_lat, dest_lon, dest_lat) {
# check inputs
assert_vector(origin_lon)
assert_numeric(origin_lon)
assert_vector(origin_lat)
assert_numeric(origin_lat)
assert_vector(dest_lon)
assert_numeric(dest_lon)
assert_vector(dest_lat)
assert_numeric(dest_lat)
# convert input arguments to radians
origin_lon <- origin_lon*2*pi/360
origin_lat <- origin_lat*2*pi/360
dest_lon <- dest_lon*2*pi/360
dest_lat <- dest_lat*2*pi/360
# get change in lon
delta_lon <- dest_lon - origin_lon
# calculate bearing
bearing <- atan2(sin(delta_lon)*cos(dest_lat), cos(origin_lat)*sin(dest_lat) - sin(origin_lat)*cos(dest_lat)*cos(delta_lon))
# calculate great circle angle. Use temporary variable to avoid acos(>1) or
# acos(<0), which can happen due to underflow issues
tmp <- sin(origin_lat)*sin(dest_lat) + cos(origin_lat)*cos(dest_lat)*cos(delta_lon)
tmp <- ifelse(tmp > 1, 1, tmp)
tmp <- ifelse(tmp < 0, 0, tmp)
gc_angle <- acos(tmp)
# convert bearing from radians to degrees measured clockwise from due north,
# and convert gc_angle to great circle distance via radius of earth (km)
bearing <- bearing*360/(2*pi)
bearing <- (bearing+360)%%360
earth_rad <- 6371
gc_dist <- earth_rad*gc_angle
# return list
ret <-list(bearing = bearing,
gc_dist = gc_dist)
return(ret)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.