30

我正在编写一个程序,它需要一些纬度/经度点,我在内部将它们转换为 UTM,以便以米为单位进行一些计算。

纬度/经度点本身的范围非常小——大约 200m x 200m。它们几乎总是可以依赖于单个 UTM 区域内(除非你不走运并且跨越区域的边界)。

但是,纬度/经度所在的区域不受限制。有一天,该计划可能会为澳大利亚的人们运行(哦,即使是一个州也有多少个区域,这已经给我带来了多少痛苦......),另一天为墨西哥的人们运行。

我的问题是——有没有办法确定特定的经纬度位于哪个区域,以便可以将其输入转换库(我目前使用 proj4 以及 R 包rgdal)。

我的语言是 R,但答案不一定是 - 也许它只是一个简单的计算,或者我可以将系统调用嵌入到proj可执行文件中。

干杯。

4

5 回答 5

47

编辑:对于适用于地球上所有非极地地区的(非 R)代码,请参见此处此处


除非您正在处理来自几个特殊区域(斯瓦尔巴群岛和挪威部分地区)的数据,否则这是一个足够简单的计算,您不妨自己在 R 中进行计算。这是Wikipedia 对经度与 UTM 区域编号的关系的描述:

UTM 系统将地球表面在 80°S 和 84°N 纬度之间划分为 60 个区域,每个区域的宽度为 6°经度。1 区覆盖经度 180° 至 174° W;区域编号向东增加至覆盖东经 174 至 180 的区域 60。

因此,假设在您的数据中,本初子午线以西的经度编码为从 -180 到 0 度,这里是上述的 R 代码版本:

long2UTM <- function(long) {
    (floor((long + 180)/6) %% 60) + 1
}

# Trying it out for San Francisco, clearly in UTM Zone 10 
# in the figure in the Wikipedia article linked above
SFlong <- -122.4192
long2UTM(SFlong)
# [1] 10

该表达式显然可以简化一点,但我认为在这种形式下,其构造背后的逻辑是最清楚的。该%% 60位在其中以防万一您的某些经度大于 180 或小于 -180。

于 2012-02-08T06:55:06.590 回答
3

我不知道 r 代码,但我想这个 PL/SQL 代码可以帮助您处理例外情况:

   UTMZone := Trunc((lon - Zone0WestMeridian) / d);
    --Special Cases for Norway & Svalbard
    CASE 
    WHEN (lat > 55) AND (UTMZone = 31) AND (lat < 64) AND (lon >  2) THEN UTMZone := 32;
    WHEN (lat > 71) AND (UTMZone = 32) AND (lon <  9) THEN UTMZone := 31;
    WHEN (lat > 71) AND (UTMZone = 32) AND (lon >  8) THEN UTMZone := 33;
    WHEN (lat > 71) AND (UTMZone = 34) AND (lon < 21) THEN UTMZone := 33;
    WHEN (lat > 71) AND (UTMZone = 34) AND (lon > 20) THEN UTMZone := 35; 
    WHEN (lat > 71) AND (UTMZone = 36) AND (lon < 33) THEN UTMZone := 35;
    WHEN (lat > 71) AND (UTMZone = 36) AND (lon > 32) THEN UTMZone := 37;
    ELSE UTMZone := UTMZone;  
    END CASE;
于 2013-09-13T11:38:31.910 回答
3

我使用以前的答案为我制作了这个功能。也许对这里的某人有用=)

utmzone <- function(lon,lat) {
## Special Cases for Norway & Svalbard
if (lat > 55 & lat < 64 & lon > 2 & lon < 6){ 
    band <- 32
  } else {
if (lat > 71 & lon >= 6 & lon < 9){
    band <- 31
  } else {
if (lat > 71 & lon >= 9 & lon < 12){
    band <- 33
  } else {
if (lat > 71 & lon >= 18 & lon < 21){
    band <- 33
  } else {
if (lat > 71 & lon >= 21 & lon < 24){
    band <- 35
  } else {
if (lat > 71 & lon >= 30 & lon < 33){
    band <- 35
  } else {
## Rest of the world
if (lon >= -180 & lon <= 180){
    band <- (floor((lon + 180)/6) %% 60) + 1
  } else {
    band <- "something is wrong"
    }}}}}}}
return(band)
}

utmzone(-43,-22)
#[1] 23
于 2020-12-16T19:24:15.663 回答
1

所以我今天遇到了这个问题,我需要从 lat/long 找到全球各地的点的 UTM 区域。麻烦的是,有所有这些卷曲的边缘情况,如斯瓦尔巴群岛、挪威和两极:(UTM 卷边案例在这张地图上以红色显示)如果你认为它们都是正常的,它们会抓住你的!

这是我的 R 函数,用于从纬度/经度对中查找 UTM 区域,最后对所有卷曲边缘情况进行测试。

require(tidyverse)
require(purrr)
require(testthat)

find_one_utm_zone <- function(longitude, latitude) {

  # Special zones for Svalbard
  if (latitude >= 72.0 && latitude <= 84.0 ) {
    if (longitude >= 0.0  && longitude <  9.0)
      return("31X");
    if (longitude >= 9.0  && longitude < 21.0)
      return("33X")
    if (longitude >= 21.0 && longitude < 33.0)
      return("35X")
    if (longitude >= 33.0 && longitude < 42.0)
      return("37X")
  }
  # Special zones for Norway
  if (latitude >= 56.0 && latitude < 64.0 ) {
    if (longitude >= 0.0  && longitude <  3.0)
      return("31V");
    if (longitude >= 3.0  && longitude < 12.0)
      return("32V")
  }

  # North + South Poles

  if (latitude > 84.0){
    if ((longitude+180)%%360-180 < 0) {return("Y")}
    if ((longitude+180)%%360-180 > 0) {return("Z")}
  } else if (latitude < -80.0){
    if ((longitude+180)%%360-180 < 0) {return("A")}
    if ((longitude+180)%%360-180 > 0) {return("B")}
  }

  # Everything in the middle

  if ( (latitude>-80.0) && (latitude<=84.0) ){

    mid_zones <- LETTERS[c(3:8,10:14,16:24)] # C to X, skip I and O
    utm_letter <- mid_zones[ min(floor( (latitude + 80) / 8 )+1 , 20) ]
    utm_number <- (floor( (longitude + 180) / 6 ) %% 60) + 1 # modulo in case longitude is 0 to 360 instead of -180 to 180
    utm_zone <- paste0(utm_number, utm_letter)
    return(utm_zone)

  } else {
      stop("lat long not valid (or something else broke)")
    }
}
find_utm_zone <- function(lon, lat){
  purrr::map2_chr(.x = lon, .y = lat, .f = find_one_utm_zone)
}

使用示例

locs <-
  tibble(lon = c(-100,30,150, 4, 7, 22, 0, 12, -34, -20),
         lat = c(-45, 85, 12, 57, 81, 83, 5, -81, 85, 83),
         desired_utm_zone = c("14G","Z","56P", "32V" ,"31X","35X","31N", "B","Y","27X"))

locs2 <-
  locs %>%
  mutate(utm_zone = find_utm_zone(lon = lon,lat = lat))

测试它是否有效:

testthat::expect_equal(locs2$utm_zone, locs2$desired_utm_zone)
于 2021-08-10T10:58:27.393 回答
0

TypeScript 版本,基于Luiz Bondis 摘要

export function utmZoneFromLatLng(lat: number, lon: number) {
  // Special Cases for Norway & Svalbard
  if (lat > 55 && lat < 64 && lon > 2 && lon < 6) {
    return 32;
  }
  if (lat > 71 && lon >= 6 && lon < 9) {
    return 31;
  }
  if (lat > 71 && ((lon >= 9 && lon < 12) || (lon >= 18 && lon < 21))) {
    return 33;
  }
  if (lat > 71 && ((lon >= 21 && lon < 24) || (lon >= 30 && lon < 33))) {
    return 35;
  }
  // Rest of the world
  if (lon >= -180 && lon <= 180) {
    return (Math.floor((lon + 180) / 6) % 60) + 1;
  }

  throw new Error(`utmZoneFromLatLng: Cannot figure out UTM zone from give Lat: ${lat}, Lng: ${lon}`);
}
于 2021-12-13T18:35:03.250 回答