在世界许多地方,经纬度点绕1公里


11

我有数百个纬度长点分布在世界各地,并且必须在它们周围创建半径为1000米的圆多边形。我知道必须先将点从度数(经度)投影到具有米单位的东西,但是如何在不手动搜索和定义每个点的UTM区域的情况下做到这一点呢?

这是芬兰第一个重点。

library(sp)
library(rgdal)
library(rgeos)
the.points.latlong <- data.frame(
  Country=c("Finland", "Canada", "Tanzania", "Bolivia", "France"),
  lat=c(63.293001, 54.239631, -2.855123, -13.795272, 48.603949),
  long=c(27.472918, -90.476303, 34.679950, -65.691146, 4.533465))
the.points.sp <- SpatialPointsDataFrame(the.points.latlong[, c("long", "lat")], data.frame(ID=seq(1:nrow(the.points.latlong))), proj4string=CRS("+proj=longlat +ellps=WGS84 +datum=WGS84"))

the.points.projected <- spTransform(the.points.sp[1, ], CRS( "+init=epsg:32635" ))  # Only first point (Finland)
the.circles.projected <- gBuffer(the.points.projected, width=1000, byid=TRUE)
plot(the.circles.projected)
points(the.points.projected)

the.circles.sp <- spTransform(the.circles.projected, CRS("+proj=longlat +ellps=WGS84 +datum=WGS84"))

但是第二点(加拿大)则不起作用(因为错误的UTM区域)。

the.points.projected <- spTransform(the.points.sp[2, ], CRS( "+init=epsg:32635" ))

如何在不手动获取和指定每个点UTM区域点的情况下完成此操作?每点我没有更多的信息。

更新:

使用和组合来自AndreJ和Mike T的出色答案,这是版本和图解的代码。它们在小数点后四位左右是不同的,但是两个答案都很好!

gnomic.buffer <- function(p, r) {
  stopifnot(length(p) == 1)
  gnom <- sprintf("+proj=gnom +lat_0=%s +lon_0=%s +x_0=0 +y_0=0",
                  p@coords[[2]], p@coords[[1]])
  projected <- spTransform(p, CRS(gnom))
  buffered <- gBuffer(projected, width=r, byid=TRUE)
  spTransform(buffered, p@proj4string)
}

custom.buffer <- function(p, r) {
  stopifnot(length(p) == 1)
  cust <- sprintf("+proj=tmerc +lat_0=%s +lon_0=%s +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs", 
                  p@coords[[2]], p@coords[[1]])
  projected <- spTransform(p, CRS(cust))
  buffered <- gBuffer(projected, width=r, byid=TRUE)
  spTransform(buffered, p@proj4string)
}

test.1 <- gnomic.buffer(the.points.sp[2,], 1000)
test.2 <- custom.buffer(the.points.sp[2,], 1000)

library(ggplot2)
test.1.f <- fortify(test.1)
test.2.f <- fortify(test.2)
test.1.f$transf <- "gnomic"
test.2.f$transf <- "custom"
test.3.f <- rbind(test.1.f, test.2.f)

p <- ggplot(test.3.f, aes(x=long, y=lat, group=transf))
p <- p + geom_path()
p <- p + facet_wrap(~transf)
p

(不确定如何将图解添加到更新中)。


1
手动搜索部分的可能解决方案:如果您获得UTM区域网格并将其与点相交,从而将适当的区域添加为属性,该怎么办?该属性可以是区域名称,也可以是EPSG代码,但是可以将其作为变量输入以自动为每个点选择正确的CRS。
克里斯W

1
我对“恰好1000m”和短语“圆形多边形”有疑问。您的圆多边形需要无穷大的段精确到 1000m,而转换为UTM(或任何其他平面系统)将引入更多的误差。使用“精确”时要小心。
Spacedman 2014年

是的,我不应该表达不同的意思。我的意思是1100m或900m太高了,圆上大约20个路段还可以。
克里斯(Chris)

Answers:


9

与@AndreJ相似,但是使用动态gnomic投影,我的意思是动态方位角等距投影以获得更高的准确性。以每个点为中心的AEQ投影将在所有方向(例如缓冲圆)上投影相等的距离。(墨卡托投影会围绕圆柱体的侧面,因此在北部和东部方向会有些变形。)

因此,对于您在芬兰的第一点,PROJ.4字符串将如下所示:

+proj=aeqd +lat_0=63.293001 +lon_0=27.472918 +x_0=0 +y_0=0

因此,您可以使用R函数进行此动态投影:

aeqd.buffer <- function(p, r)
{
    stopifnot(length(p) == 1)
    aeqd <- sprintf("+proj=aeqd +lat_0=%s +lon_0=%s +x_0=0 +y_0=0",
                    p@coords[[2]], p@coords[[1]])
    projected <- spTransform(p, CRS(aeqd))
    buffered <- gBuffer(projected, width=r, byid=TRUE)
    spTransform(buffered, p@proj4string)
}

然后对加拿大执行以下操作(项目2):

aeqd.buffer(the.points.sp[2,], 1000)

1
在Wikipedia页面上:“在切点处不会发生变形,但是变形会迅速增加”。您是否进行了样本偏移量计算?也许en.wikipedia.org/wiki/Azimuthal_equidistant_projection更适合。
2014年

2
任何在圆的原点具有正确比例并且在该位置上是保形的投影都可以正常工作,仅因为1000m是如此之小。但是,对于更大的半径,Gnomonic投影将是可怕的。您可能打算规定等距投影。
ub

2
很好的反馈,AEQ投影显然对这项技术有更好的表现,所以我选择了基因组学。AEQP还将保持更大的距离,例如在10,000+公里范围内。
Mike T

1
我可能对代码有误解,但在任何AEQD投影中,您只需要构建一次缓冲区多边形(中心始终为零,最小值坐标始终为-1k,最大值始终为+ 1k。然后使用AEQD集中在获取经度/纬度值所需的每个点上……
mkennedy 2014年

2
@mkennedy,你有一个好点。projected的确确实总是(0,0),并且bufferedxy方向上的点为±1000 m 。如果优化它至关重要,则只需将缓冲区的简单笛卡尔版本从动态AEQD转换为WGS84。
Mike T

4

您可以为每个点创建自定义的横向墨卡托投影,而不用搜索正确的UTM区域。

+proj=tmerc +lat_0=.... +lon_0=... +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs

在该投影中绘制圆。投影的圆顶点坐标将始终相同,因此您只需创建一次即可。对于以下内容,只需为其分配新的自定义CRS。

将圆重新投影到EPSG:4326以便进一步使用。

在1000m的范围内,圆圈几乎是精确的。如果不是(或较大的圆圈),请使用aeqd代替tmerc


0

如果您采取在每个点周围都在EPSG:4326中创建1000米的方法,该怎么办。然后将EPSG:4326转换为其他坐标系?投影点的优点是,您不必担心使用EPSG:4326的地球曲率。


1
您将如何精确地从EPSG:4326创建1000 m缓冲区,其长度单位为度?
麦克T

我采用的一种方法是在EPSG:32635中创建一个1000米的缓冲区。将其转换为EPSG:4326,现在您将拥有所需的号码。
格雷格2014年

1
这与问题中描述的方法相同,但存在这种技术的局限性。
Mike T
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.