R:以公制格式计算沿子午线的长距离

时间:2019-03-27 14:53:40

标签: r distance r-raster map-projections

我想计算从5弧分分钟分辨率的全局栅格中的所有像素到赤道的距离。结果距离应以米为单位,并考虑到地球的曲率,并且不应因地图投影而失真。

在小区域(例如单个国家)上的应用程序通常通过选择非常适合给定区域的EPSG代码来克服地图投影引起的变形的威胁。由于我的应用程序遍及全球,因此此技巧无效。但是,我并不需要一张可以在各个方面充分显示地球的地图。我只需要一个不会扭曲每个像素与赤道最近点之间距离的投影,即一个不会沿子午线扭曲距离的投影。就我而言,PlateCarrée投影("+proj=longlat +datum=WGS84")满足此条件。鉴于此信息,我尝试了以下代码:

r_res <- 1/12
r <- raster(resolution = c(r_res, r_res), crs = "+proj=longlat +datum=WGS84")
p <- as(r, "SpatialPoints")
equator <- st_sfc(st_point(c(-180,0)), st_point(c(0,0)), st_point(c(180,0))) %>% st_combine() %>% st_cast(., "LINESTRING") %>% st_sf(., crs = 4326) %>% st_transform(crs = "+proj=longlat +datum=WGS84") %>% as(., "Spatial")
d <- gDistance(p, equator, byid = T)
dmin <- apply(d, 2, min)
r[] <- dmin 

不幸的是,在此示例中计算的距离是以度表示的,而不是以米表示的,这是由投影的longlat格式引起的。此外,我找不到关于rgeos::gDistance()是否考虑了行星曲率的任何信息。根据相关文章,gDistance()甚至不应该应用于longlat数据。

或者,我将网格投影到另一个以米为单位的投影(Mollweide)中:

r_res <- 1/12
r <- raster(resolution = c(r_res, r_res), crs = "+proj=longlat +datum=WGS84")
r <- projectRaster(r, crs="+proj=moll +ellps=WGS84")
p <- as(r, "SpatialPoints")
equator <- st_sfc(st_point(c(-180,0)), st_point(c(0,0)), st_point(c(180,0))) %>% st_combine() %>% st_cast(., "LINESTRING") %>% st_sf(., crs = 4326) %>% st_transform(crs="+proj=moll +ellps=WGS84") %>% as(., "Spatial")
d <- gDistance(p, equator, byid = T)
dmin <- apply(d, 2, min)
r[] <- dmin 

但是,在这种情况下,我不确定gDistance()是否校正了Mollweide投影所隐含的距离失真。

我知道可以使用经验法则latitude * 111 km计算距赤道的距离。但是,对于我需要更高精度功能的应用程序来说,这种近似值太不精确了。

如果有人可以提供一些建议,那将是很棒的。随意依赖gDistance()以外的距离函数。只要距离不失真,以米为单位,并且考虑到地球的曲率,我对任何函数都可以,例如sfgdistanceraster,{ {1}},geosphere或任何其他软件包。

1 个答案:

答案 0 :(得分:2)

这是一种方法(对于很大的栅格来说,这不是内存安全的)

library(raster)
r_res <- 1/12
r <- raster(resolution = c(r_res, r_res), crs = "+proj=longlat +datum=WGS84")
# latitudes for one column
lats <- cbind(0, yFromRow(r, 1:nrow(r)))
#distances (in km) for one column
dist <- pointDistance(lats, cbind(0,0), lonlat=TRUE) / 1000
# assign to all cells
d <- setValues(r, rep(dist, each=ncol(r)))

这会将“拇指法则”设置为mean(dist/abs(lats[,2])) = 110.8032 km /纬度

这是一种内存安全(但效率低下)的方法:

x <- init(r, "y")
f <- function(i) { pointDistance(cbind(0, i), cbind(0,0), lonlat=TRUE) / 1000} 
z <- calc(x, fun=f)