操作地图图块数据以与R中的栅格数据对齐

时间:2014-08-27 11:52:21

标签: r raster rgl

我正在尝试使用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)

enter image description here

plot_3d_tile(z1, xlims, ylims, zscale=1/3000, zoom=10, crs=wgs84)

enter image description here

plot_3d_tile(z1, xlims, ylims, zscale=1/3000, zoom=11, crs=wgs84)

enter image description here

正如您所看到的,随着OSM缩放级别的增加,开始看起来不错的内容会逐渐变形。我担心就翻转和旋转而言,我遇到了一些问题,但这是迄今为止我所取得的最接近的组合。我知道一个特定的问题,但代码可能对其他人有用,所以我在这里发帖。提前谢谢。

1 个答案:

答案 0 :(得分:3)

我找到了一个解决方法。而不是将颜色信息提供给rgl.surface,而是可以给它的texture参数提供一个png。这可能意味着我的代码使表面光栅与瓷砖的尺寸相匹配有点多余,尽管如果表面分辨率低得多,它仍然可以使插值更平滑。工作职能:

enter image description here

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)