toRad = function(x) x * pi / 180
toDeg = function(x) x * 180 / pi
rotate = function(lonlat, lon0, lat0, north = TRUE) {
# https://gis.stackexchange.com/questions/10808/manually-transforming-rotated-lat-lon-to-regular-lat-lon/14445 , by Miha!
lon0 = toRad(lon0)
lat0 = toRad(lat0)
if (north) {
lat0 = -lat0
lon0 = pi + lon0
}
lonlat = toRad(lonlat)
lon = lonlat[,1]
lat = lonlat[,2]
vartheta = -(pi/2 + lat0)
varphi = -lon0
toDeg(cbind(
atan2(sin(lon), tan(lat) * sin(vartheta) +
cos(lon) * cos(vartheta)) - varphi,
asin(cos(vartheta) * sin(lat) - cos(lon) * sin(vartheta) * cos(lat))
))
}
#' @export
st_rotate = function(.x, lon0, lat0, north, ...) UseMethod("st_rotate")
#' Transform rotated pole long/lat regular grid to unrotated curvilinear grid
#'
#' Transform rotated long/lat regular grid to unrotated curvilinear grid
#' @param .x object of class \code{stars}
#' @param lon0 longitude of the rotated pole in degrees
#' @param lat0 latitude of the rotated pole in degrees
#' @param north logical; if \code{TRUE} the pole refers to the North pole, otherwise the South pole
#' @param ... ignored
#' @returns curvilinear stars object with coordinates in regular long/lat (North pole at lat=90)
#' @export
#' @name st_rotate
#' @examples
#' if (require("starsdata") && require("maps")) {
#' # data downloaded from https://esgf-data.dkrz.de/search/cosmo-rea/
#' nc = "netcdf/ts_EUR-6km_ECMWF-ERAINT_REA6_r1i1p1f1_COSMO_v1_mon_201801-201812.nc"
#' f = system.file(nc, package = "starsdata")
#' m = read_mdim(f, "ts")
#' print(m)
#' # NOTE this function is obsolete when reading m as
#' # m = read_mdim(f, "ts", curvilinear = c("longitude", "latitude"))
#' if (require(RNetCDF)) {
#' x = open.nc(f)
#' lon = att.get.nc(x, "rotated_latitude_longitude", "grid_north_pole_longitude")
#' lat = att.get.nc(x, "rotated_latitude_longitude", "grid_north_pole_latitude")
#' close.nc(x)
#' print(c(lon = lon, lat = lat))
#' } else {
#' lon = -162
#' lat = 39.25
#' }
#' m1 = st_rotate(m, lon, lat)
#' print(m1)
#' h = function() maps::map(add = TRUE)
#' plot(m1, downsample = c(10, 10, 5), axes = TRUE, hook = h, mfrow = c(1, 2))
#' # curvilinear grid: downsample for plotting speed
#' m2 = st_warp(m1, crs = st_crs("OGC:CRS84"), threshold = .1)
#' plot(m2, hook = h, mfrow = c(3, 4)) # regular grid: plots fast
#' }
st_rotate.stars = function(.x, lon0, lat0, north = TRUE, ...) {
stopifnot(is.na(st_crs(.x)) || st_is_longlat(.x),
!is_curvilinear(.x),
is.logical(north),
!is.na(north),
lat0 <= 90,
lat0 >= -90,
length(list(...)) == 0)
if (has_sfc(.x))
st_set_dimensions(.x, which_sfc(.x), values = rotate(st_geometry(.x), lon0, lat0, north))
else {
.x = st_upfront(.x)
d = dim(.x)
ccr = rotate(st_coordinates(st_dimensions(.x)[1:2]), lon0, lat0, north)
st_as_stars(.x, curvilinear = setNames(list(matrix(ccr[,1], d[1], d[2]),
matrix(ccr[,2], d[1], d[2])), names(d)[1:2]))
}
}
#' @name st_rotate
#' @export
st_rotate.sfc = function(.x, lon0, lat0, north = TRUE, ...) {
r = rapply(.x, rotate, how = "replace", lon0 = lon0, lat0 = lat0, north = north)
st_set_crs(st_sfc(r, recompute_bbox = TRUE), NA_crs_)
}
#' @name st_rotate
#' @export
st_rotate.sf = function(.x, lon0, lat0, north = TRUE, ...) {
st_set_geometry(.x, st_rotate(st_geometry(.x), lon0, lat0, north))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.