[英]Manipulating map tile data to align with raster data in R
我正在嘗試使用rgl在3D表面上繪制地圖圖塊,但無法弄清楚如何正確對齊數據。 這可能與R在矩陣和柵格之間進行轉換時添加90度旋轉的行為有關,但我也發現需要在代碼中添加翻轉以獲得正確的結果。 工作流程有點棘手,所以我把它變成了一個函數來顯示結果與輸入變量的關系。 展示:
require(raster)
require(akima)
require(OpenStreetMap)
require(rgl)
wgs84 = '+proj=longlat +datum=WGS84'
plot_3d_tile = function(z, xlims, ylims, zscale=1, zoom, crs, plot_rasters=F, ...){
# specify raster's spatial info
extent(z) = c(xlims, ylims); crs(z) = crs
# extend range slightly to crop back to rect after reproj
osm_x = extendrange(r=xlims); osm_y = extendrange(r=ylims)
# get OSM map tile & reproject to wgs84
m = raster(openproj(openmap(c(osm_y[2],osm_x[1]), c(osm_y[1],osm_x[2]), zoom=zoom)))
m = crop(flip(m,'y'), extent(z)) # FLIPPED
if(plot_rasters) plotRGB(m)
# coerce to lists of points for akima::interp
pts_m = rasterToPoints(m); pts_z = rasterToPoints(z)
# resizes z to match tile
intp = interp(x=pts_z[,1], y=pts_z[,2], z=pts_z[,3],
xo=unique(pts_m[,1]), yo=unique(pts_m[,2]))
# get matrix of interpolated z values and convert back to spatial
z2 = flip(raster(apply(intp$z, 1, rev)),'y') # FLIPPED AND ROTATED
cat("dimensions match? ", dim(z2) == dim(raster(m))) # check dimensions match up
extent(z2) = extent(xlims, ylims); crs(z2) = crs # spatialise
if(plot_rasters) plot(z2, asp=T)
pts_z2 = rasterToPoints(z2)
# create hex colour vector from tile values
col_data = getValues(m)
cols = rgb(col_data[,1], col_data[,2], col_data[,3], maxColorValue = 255)
# plot 3d extruded map tile
rgl.open(); bg3d("white")
rgl.surface(unique(pts_z2[,1]), unique(pts_z2[,2]), pts_z2[,3]*zscale,
color=cols, specular="black", back="lines", asp=T, ...)
results <<- list(z=z, z2=z2, m=m, intp=intp, pts_m=pts_m, pts_z=pts_z, pts_z2=pts_z2)
}
z1 = raster(volcano)
xlims = c(-0.24, -0.1)
ylims = c(51.4, 51.58)
現在測試一下:
plot_3d_tile(z1, xlims, ylims, zscale=1/3000, zoom=9, crs=wgs84)
plot_3d_tile(z1, xlims, ylims, zscale=1/3000, zoom=10, crs=wgs84)
plot_3d_tile(z1, xlims, ylims, zscale=1/3000, zoom=11, crs=wgs84)
正如您所看到的,隨着OSM縮放級別的增加,開始看起來不錯的內容會逐漸變形。 我擔心就翻轉和旋轉而言,我遇到了一些問題,但這是迄今為止我所取得的最接近的組合。 我知道一個特定的問題,但代碼可能對其他人有用,所以我在這里發帖。 提前致謝。
我找到了一個解決方法。 不是將顏色信息提供給rgl.surface
而是可以為其texture
參數提供png。 這可能意味着我的代碼使表面光柵與瓷磚的尺寸相匹配有點多余,盡管如果表面分辨率低得多,它仍然可以使插值更平滑。 工作職能:
plot_3d_tile = function(z, xlims, ylims, zscale=1, zoom, crs, plot_rasters=F, ...){
# specify raster's spatial info
extent(z) = c(xlims, ylims); crs(z) = crs
if(plot_rasters) plot(z, asp=T, main='z')
# extend range slightly to crop back to rect after reproj
osm_x = extendrange(r=xlims); osm_y = extendrange(r=ylims)
# get OSM map tile & reproject to wgs84
m = raster(openproj(openmap(c(osm_y[2],osm_x[1]), c(osm_y[1],osm_x[2]), zoom=zoom)))
m = crop(flip(m,'y'), extent(z)) # FLIPPED
if(plot_rasters) plotRGB(m, asp=T, main='m')
png('plot.png', width=ncol(m), height=nrow(m))
plotRGB(m)
dev.off()
# coerce to lists of points for akima::interp
pts_m = rasterToPoints(m); pts_z = rasterToPoints(z)
# resizes z to match tile
intp = interp(x=pts_z[,1], y=pts_z[,2], z=pts_z[,3],
xo=unique(pts_m[,1]), yo=unique(pts_m[,2]))
# get matrix of interpolated z values and convert back to spatial
z2 = raster(apply(intp$z, 1, rev)) # ROTATED
cat("dimensions match? ", dim(z2) == dim(raster(m))) # check dimensions match up
extent(z2) = extent(xlims, ylims); crs(z2) = crs # spatialise
if(plot_rasters) plot(z2, asp=T, main='z2')
pts_z2 = rasterToPoints(z2)
# plot 3d extruded map tile
bg3d("white")
rgl.surface(unique(pts_z2[,1]), unique(pts_z2[,2]), pts_z2[,3]*zscale,
texture='plot.png', specular="black", back="lines", asp=T, ...)
results <<- list(z=z, z2=z2, m=m, intp=intp, pts_m=pts_m, pts_z=pts_z, pts_z2=pts_z2)
}
rgl.open()
plot_3d_tile(z1, xlims, ylims, zscale=1/3000, zoom=12, crs=wgs84, plot_rasters=T)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.