将纬度和经度点转换为UTM

15

我找到了一个相当简单的例子来演示如何做这件事,但我无法让它为我工作。我对R比较陌生。

library(rgdal) 
xy <- cbind(c(118, 119), c(10, 50)) 
project(xy, "+proj=utm +zone=51 ellps=WGS84") 
          [,1]    [,2] 
[1,] -48636.65 1109577 
[2,] 213372.05 5546301

但这只是示例数字。我有成千上万个坐标需要转换,但我无法弄清如何将它们从我的表格导入此脚本。

我的数据集有3列:ID、X和Y。我该如何使用这个方程进行转换?我被困在这个问题上已经几周了。


如果您不提供一些无效的数字(以及可能存储它们的格式的描述),那么帮助您将会很困难。此外,您是否知道您所有的经纬度坐标都在单个UTM区域内? - Josh O'Brien
其实不是因为我没有输入数字,所以数字不起作用。我需要脚本从数千个坐标的表格中读取它。我只是不知道该怎么做。dd <- read.csv(file.choose(), header = T)X <- dd["X"]Y <- dd["Y"]xy <- cbind(c(X), c(Y))project(xy, "+proj=utm +zone=51 ellps=WGS84")甚至不确定这个方程是否有意义,但它无法运行。 "xy not numeric"而且我不知道所有我的坐标是否都在一个UTM区域内。我讨厌听起来像个白痴,但这对我来说是新的,我不知道这是什么意思。 - Colin
什么样的表格?(它是存储在文本文件中的吗?CSV?关系数据库?Excel文件?等等等等)看起来你现在真正问的是如何将数据读入R。如果是这种情况,请尝试使用Google或在上面的SO搜索栏中进行搜索,然后如果您无法弄清楚,请再次询问。 - Josh O'Brien
我知道如何读取数据。它是一个csv文件。上面的示例是示例数字。我的问题是,在从表中读取X(经度)和Y(纬度)之后,该数据如何适用于示例脚本? - Colin
5个回答

26
为了确保与坐标相关的适当投影元数据在每个步骤都与其关联,我建议尽早将点转换为 SpatialPointsDataFrame 对象。请参见 ?"SpatialPointsDataFrame-class" 以了解如何将简单的 data.frame 或矩阵转换为 SpatialPointsDataFrame 对象。
library(sp)
library(rgdal)

xy <- data.frame(ID = 1:2, X = c(118, 119), Y = c(10, 50))
coordinates(xy) <- c("X", "Y")
proj4string(xy) <- CRS("+proj=longlat +datum=WGS84")  ## for example

res <- spTransform(xy, CRS("+proj=utm +zone=51 ellps=WGS84"))
res
#            coordinates ID
# 1 (-48636.65, 1109577)  1
# 2    (213372, 5546301)  2

## For a SpatialPoints object rather than a SpatialPointsDataFrame, just do: 
as(res, "SpatialPoints")
# SpatialPoints:
#              x       y
# [1,] -48636.65 1109577
# [2,] 213372.05 5546301
# Coordinate Reference System (CRS) arguments: +proj=utm +zone=51
# +ellps=WGS84 

“SP”在spTransform()调用中是什么变量?如果我将其更改为“xy”,则不会得到与该调用下方显示的相同输出。 - stackoverflowuser2010
@stackoverflowuser2010 -- 哎呀,我的错。那个SP是留下来的,因为我的初始答案中涉及到了一个SpatialPoints对象而不是一个SpatialPointsDataFrame。供您参考,您可以通过点击编辑后答案直接下面的“edited ... ago”链接来查看SO答案的早期版本。感谢你发现这个问题。 - Josh O'Brien

19

将纬度和经度点转换为UTM

library(sp)
library(rgdal)

#Function
LongLatToUTM<-function(x,y,zone){
 xy <- data.frame(ID = 1:length(x), X = x, Y = y)
 coordinates(xy) <- c("X", "Y")
 proj4string(xy) <- CRS("+proj=longlat +datum=WGS84")  ## for example
 res <- spTransform(xy, CRS(paste("+proj=utm +zone=",zone," ellps=WGS84",sep='')))
 return(as.data.frame(res))
}

# Example
x<-c( -94.99729,-94.99726,-94.99457,-94.99458,-94.99729)
y<-c( 29.17112, 29.17107, 29.17273, 29.17278, 29.17112)
LongLatToUTM(x,y,15)

6

在您的问题中,您并没有清楚地说明您是否已经将数据集读入到数据框或矩阵中。因此,在接下来的内容中,我假设您的数据集保存在一个文本文件中:

# read in data
dataset = read.table("dataset.txt", header=T)

# ... or use example data
dataset = read.table(text="ID X Y
1 118 10
2 119 50
3 100 12
4 101 12", header=T, sep=" ")

# create a matrix from columns X & Y and use project as in the question
project(as.matrix(dataset[,c("X","Y")]), "+proj=utm +zone=51 ellps=WGS84")
#             [,1]    [,2]
# [1,]   -48636.65 1109577
# [2,]   213372.05 5546301
# ...

更新:

评论中提到问题源于将project()应用于数据框。因为project()检查是否是数值型,所以不适用于数据框。因此,您需要像我上面的示例一样将数据转换为矩阵。如果您想继续使用cbind()的代码,则必须执行以下操作:

 X <- dd[,"X"]
 Y <- dd[,"Y"]
 xy <- cbind(X,Y) 
dd["X"]dd[,"X"]之间的不同在于后者不会返回一个data.frame,因此cbind()将生成一个矩阵而不是data.frame。

2
谢谢。这似乎产生了一些结果,这让我感到宽慰!输出是以米为单位吗?我的大多数坐标现在看起来像-9596387 -5670257,-9597204 -5666367等。这是否正确?有些人提到了UTM区域。从谷歌上看,我建议它似乎分布在39L、39K和38k之间,如果这有意义的话。这是否需要在脚本中考虑到?就像我说的,我只是复制了在网上找到的一个例子。如果我听起来像个白痴,我很抱歉,我只是想理解这个问题。再次感谢。 - Colin

4

根据上面的代码,我还添加了一个区域和半球检测的版本(解决了一些评论中描述的转换问题)+ CRS字符串的速记和回转换到WSG86:

library(dplyr)
library(sp)
library(rgdal)
library(tibble)

find_UTM_zone <- function(longitude, latitude) {

 # Special zones for Svalbard and Norway
    if (latitude >= 72.0 && latitude < 84.0 ) 
        if (longitude >= 0.0  && longitude <  9.0) 
              return(31);
    if (longitude >= 9.0  && longitude < 21.0)
          return(33)
    if (longitude >= 21.0 && longitude < 33.0)
          return(35)
    if (longitude >= 33.0 && longitude < 42.0) 
          return(37)

    (floor((longitude + 180) / 6) %% 60) + 1
}


find_UTM_hemisphere <- function(latitude) {

    ifelse(latitude > 0, "north", "south")
}

# returns a DF containing the UTM values, the zone and the hemisphere
longlat_to_UTM <- function(long, lat, units = 'm') {

    df <- data.frame(
        id = seq_along(long), 
        x = long, 
        y = lat
    )
    sp::coordinates(df) <- c("x", "y")

    hemisphere <- find_UTM_hemisphere(lat)
    zone <- find_UTM_zone(long, lat)

    sp::proj4string(df) <- sp::CRS("+init=epsg:4326") 
    CRSstring <- paste0(
        "+proj=utm +zone=", zone,
        " +ellps=WGS84",
        " +", hemisphere,
        " +units=", units)
    if (dplyr::n_distinct(CRSstring) > 1L) 
        stop("multiple zone/hemisphere detected")

    res <- sp::spTransform(df, sp::CRS(CRSstring[1L])) %>%
        tibble::as_data_frame() %>%
        dplyr::mutate(
            zone = zone,
            hemisphere = hemisphere
        )

    res
}

UTM_to_longlat <- function(utm_df, zone, hemisphere) {

    CRSstring <- paste0("+proj=utm +zone=", zone, " +", hemisphere)
    utmcoor <- sp::SpatialPoints(utm_df, proj4string = sp::CRS(CRSstring))
    longlatcoor <- sp::spTransform(utmcoor, sp::CRS("+init=epsg:4326"))
    tibble::as_data_frame(longlatcoor)
}

CRS("+init=epsg:4326")CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0")的简写。

查找UTM区参考:http://www.igorexchange.com/node/927


1
关于这个例子,给定坐标的默认UTM区域是50。不建议将坐标投影到远离的区域。您可以使用NOAA的NCAT工具检查转换。
下面的代码使用sf包进行转换。
library(sf)
library(tidyverse)

# Coordinate examples with expected UTM values
coord_sample <- data.frame(
  "Northing" = c(1105578.589, 5540547.370),
  "Easting" = c(609600.773, 643329.124),
  "Latitude" = c(10, 50),
  "Longitude" = c(118, 119))

#' Find UTM EPSG code from Latitude and Longitude coordinates (EPSG 4326 WGS84)
#' (vectorised)
#' Source: https://geocompr.robinlovelace.net/reproj-geo-data.html
#' Source: https://gis.stackexchange.com/questions/13291/computing-utm-zone-from-lat-long-point
LatLonToUTMEPSGCode <- function(lat, lon) {

  zone_number <- (floor((lon + 180) / 6) %% 60) + 1

  # Special zones for Norway
  cond_32 <- lat >= 56.0 & lat < 64.0 & lon >= 3.0 & lon < 12.0
  zone_number[cond_32] <- 32

  # Special zones for Svalbard
  cond_lat <- lat >= 72.0 & lat < 84.0

  cond_31 <- cond_lat & lon >= 0.0 & lon <  9.0
  zone_number[cond_31] <- 31

  cond_33 <- cond_lat & lon >= 9.0 & lon < 21.0
  zone_number[cond_33] <- 33

  cond_35 <- cond_lat & lon >= 21.0 & lon < 33.0
  zone_number[cond_35] <- 35

  cond_37 <- cond_lat & lon >= 33.0 & lon < 42.0
  zone_number[cond_37] <- 37

  # EPSG code
  utm <- zone_number
  utm[lat > 0] <- utm[lat > 0] + 32600
  utm[lat <= 0] <- utm[lat <= 0] + 32700

  return(utm)
}

sf_sample <- sf::st_as_sf(coord_sample, coords = c("Longitude", "Latitude"),
                          crs = 4326)

sf_sample %>%
  do(cbind(., st_coordinates(.))) %>%
  mutate(EPSG = LatLonToUTMEPSGCode(lat = Y, lon = X)) %>%
  group_by(EPSG) %>%
  do(cbind(as.data.frame(.) %>% select(Northing, Easting),
           st_coordinates(st_transform(., crs = head(.$EPSG, 1))))) %>%
  ungroup()



您可以通过与预期值进行比较来检查转换结果:
# A tibble: 2 x 5
   EPSG Northing Easting      X       Y
  <dbl>    <dbl>   <dbl>  <dbl>   <dbl>
1 32650  1105579  609601 609601 1105579
2 32650  5540547  643329 643329 5540547

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接