根据经度/纬度确定 UTM 区域(要转换)

发布于 2025-01-03 01:33:13 字数 395 浏览 1 评论 0 原文

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

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

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

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

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

干杯。

I'm writing a program which expects a number of lat/long points, and I convert them internally to UTM in order to do some calculations in metres.

The range of the lat/long points themselves is quite small -- about 200m x 200m. They can be relied on almost always to be within a single UTM zone (unless you get unlucky and are across the border of a zone).

However, the zone that the lat/longs are in is unrestricted. One day the program might be run for people in Australia (and oh, how many zones does even a single state lie across, and how much pain has that caused me already...), and another day for people in Mexico.

My question is -- is there a way to determine which zone a particular long/lat is in so that it may be fed into a conversion library (I currently use proj4 and also the R package rgdal).

My language is R, but the answer doesn't have to be -- maybe it's just a simple calculation, or maybe I can embed a system call to the proj exectuable.

cheers.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

回忆凄美了谁 2025-01-10 01:33:13

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


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

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

因此,假设在您的数据中,本初子午线以西的经度被编码为从 - 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。

Edit: For (non-R) code that works for all non-polar areas on earth, see here or here.


Unless you are dealing with data from a couple of exceptional areas (Svalbard and parts of Norway), this is a simple enough calculation that you might as well just do it yourself in R. Here is Wikipedia's description of how longitude relates to UTM Zone number:

The UTM system divides the surface of Earth between 80°S and 84°N latitude into 60 zones, each 6° of longitude in width. Zone 1 covers longitude 180° to 174° W; zone numbering increases eastward to zone 60 that covers longitude 174 to 180 East.

So, assuming that in your data longitudes to the west of the Prime Meridian are encoded as running from -180 to 0 degrees, here's an R-code version of the above:

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

That expression could obviously be simplified a bit, but I think in this form the logic underlying its construction is most clear. The %% 60 bit is in there just in case some of your longitudes are greater than 180 or less than -180.

风追烟花雨 2025-01-10 01:33:13

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

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

I made this function for me using the previous answers.
Maybe it is useful to someone here =)

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
苯莒 2025-01-10 01:33:13

我不知道 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;

I don't know r-code but I suppose this PL/SQL code can help you with the exceptions:

   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;
苹果你个爱泡泡 2025-01-10 01:33:13

所以我今天遇到了这个问题,我需要从纬度/经度找到全球各地点的 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)

So I had this problem today, that I needed to find the UTM zone from lat/long for points all over the globe. The trouble is that there's all these curly edge cases like Svalbard, Norway, and the poles:UTM curly edge cases (shown in red on this map) which will catch you out if you assume it's all regular!

Here's my R function to find UTM zones from lat/long pairs, with tests at the end for all of the curly edge cases.

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)
}

Example of use

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))

Test that it worked:

testthat::expect_equal(locs2$utm_zone, locs2$desired_utm_zone)
清风挽心 2025-01-10 01:33:13

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}`);
}

Version for TypeScript, based on Luiz Bondis summary:

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}`);
}
叹倦 2025-01-10 01:33:13

Python版本:

def get_utm_fromLatLon(lat, lon):
    #Special Cases for Norway and Svalbard
    if (lat > 55 and lat < 64 and lon > 2 and lon < 6):
        return 32
    elif (lat > 71 and lon >= 6 and lon < 9):
        return 31
    elif (lat > 71 and ((lon >= 9 and lon < 12) or (lon >= 18 and lon < 21))):
        return 33
    elif (lat > 71 and ((lon >= 21 and lon < 24) or (lon >= 30 and lon < 33))):
        return 35
    # Rest of the world
    elif (lon >= -180 and lon <= 180):
        return (math.floor((lon + 180) / 6) % 60) + 1
    else:
        raise ValueError('Cannot figure out UTM zone from given Lat: {0}, Lon: {1}.'.format(lat, lon))

Python version:

def get_utm_fromLatLon(lat, lon):
    #Special Cases for Norway and Svalbard
    if (lat > 55 and lat < 64 and lon > 2 and lon < 6):
        return 32
    elif (lat > 71 and lon >= 6 and lon < 9):
        return 31
    elif (lat > 71 and ((lon >= 9 and lon < 12) or (lon >= 18 and lon < 21))):
        return 33
    elif (lat > 71 and ((lon >= 21 and lon < 24) or (lon >= 30 and lon < 33))):
        return 35
    # Rest of the world
    elif (lon >= -180 and lon <= 180):
        return (math.floor((lon + 180) / 6) % 60) + 1
    else:
        raise ValueError('Cannot figure out UTM zone from given Lat: {0}, Lon: {1}.'.format(lat, lon))

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文