Converting Latitude and Longitude Points to Utm

Converting latitude and longitude data to UTM with points from multiple UTM zones in R

UPDATE

Here is a much faster and elegant workaround using dplyr and spTransfrom

Augmented data (60k+ rows):

test_coordinates <- data.frame(x = c(13.637398, -3.58627, -5.178889), y = c(41.30736, 40.72913, 40.17528), x_correct = c(385936, 450492, 314480), y_correct = c(4573773, 4508854, 4449488 ),  zone = c(33, 30, 30), key = c(1, 2, 3), country = c("italy", "spain", "spain"))
test_coordinates = rbind(test_coordinates, test_coordinates[rep(1,60*1000),]) # simulate big data
library(dplyr)
library(sp)

get_utm <- function(x, y, zone, loc){
points = SpatialPoints(cbind(x, y), proj4string = CRS("+proj=longlat +datum=WGS84"))
points_utm = spTransform(points, CRS(paste0("+proj=utm +zone=",zone[1]," +ellps=WGS84")))
if (loc == "x") {
return(coordinates(points_utm)[,1])
} else if (loc == "y") {
return(coordinates(points_utm)[,2])
}
}

test_coordinates %<>%
mutate(zone2 = (floor((x + 180)/6) %% 60) + 1, keep = "all"
) %>%
group_by(zone2) %>%
mutate(utm_x = get_utm(x, y, zone2, loc = "x"),
utm_y = get_utm(x, y, zone2, loc = "y"))

Output (5 rows only)

test_coordinates


# A tibble: 603 × 10
# Groups: zone2 [2]
x y x_correct y_correct zone key country zone2 utm_x utm_y
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <dbl> <dbl> <dbl>
1 13.6 41.3 385936 4573773 33 1 italy 33 385936. 4573773.
2 -3.59 40.7 450492 4508854 30 2 spain 30 450492. 4508854.
3 -5.18 40.2 314480 4449488 30 3 spain 30 314480. 4449488.
4 13.6 41.3 385936 4573773 33 1 italy 33 385936. 4573773.
5 13.6 41.3 385936 4573773 33 1 italy 33 385936. 4573773.

ORIGINAL RESPONSE

Replace:

data.frame(t(sapply(converted_points,c)))  #Makes this list into a dataframe

With:

test_coordinates$utm_x <- unlist(converted_points)[c(T,F)]
test_coordinates$utm_y <- unlist(converted_points)[c(F,T)]
          x        y x_correct y_correct zone key country    utm_x   utm_y
1 13.637398 41.30736 385936 4573773 33 1 italy 385935.7 4573773
2 -3.586270 40.72913 450492 4508854 30 2 spain 450492.4 4508854
3 -5.178889 40.17528 314480 4449488 30 3 spain 314479.5 4449488

Convert lat long to utm NAD83 zone 20

I got this code from an online source (don't have the reference handy):

LongLatToUTM<-function(x,y,zone){
require(sp)
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))
}

Note that this is for WGS84.

Converting latitude and longitude to UTM coordinates in pyspark

Something like this,

import pyspark.sql.functions as F
import utm
from pyspark.sql.types import *

utm_udf_x = F.udf(lambda x,y: utm.from_latlon(x,y)[0], FloatType())
utm_udf_y = F.udf(lambda x,y: utm.from_latlon(x,y)[1], FloatType())

df = df.withColumn('UTM_x',utm_udf_x(F.col('lat'), F.col('lon')))
df = df.withColumn('UTM_y',utm_udf_y(F.col('lat'), F.col('lon')))

Although I am not sure why did you write [1] at the end.

using boost::geometry to convert from Latitude and longitude to UTM

I just spent an embarrassing amount of time looking for this (multiple hours).

It seems like everything spherical (SRS) is just ... not documented at all. Perhaps there's something broken with the documentation generator.

Regardless, several tedious searches through test code further I stumbled on a working answer.

Here's examples

  • Amsterdam (UTM 629144.77 Easting 5803996.66 Northing in zone 31U)
  • Barcelona (UTM 430887.56 Easting, 4581837.85 Northing, zone 31T)

With even more stumbling I found the corresponding EPSG code on https://epsg.io/?q=UTM+31N: Sample Image

Live On Compiler Explorer

#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/geometries/point_xy.hpp>

#include <boost/geometry/srs/epsg.hpp>
#ifdef COLIRU
#include <boost/geometry/srs/projection.hpp>
#endif

namespace bg = boost::geometry;
namespace bm = bg::model::d2;
namespace srs = bg::srs;

using LongLat = bm::point_xy<double, bg::cs::geographic<bg::degree> >;
using UTM = bm::point_xy<double/*, srs::static_epsg<3043>*/>;

constexpr LongLat Amsterdam() { return { 4.897, 52.371}; }
constexpr LongLat Barcelona() { return { 2.1734, 41.3851 }; }

void report(LongLat src, auto const& prj) {
UTM r {};
prj.forward(src, r);
std::cout << std::fixed << bg::wkt(src) << " -> " << bg::wkt(r) << "\n";
}

int main() {
#ifndef COLIRU
// dynamic projection factory too heavy on Coliru
srs::projection<> zone31 = srs::proj4("+proj=utm +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5 +zone=31");
report(Amsterdam(), zone31);
report(Barcelona(), zone31);
#endif

srs::projection<srs::static_epsg<3043> > epsg3043;
report(Amsterdam(), epsg3043);
report(Barcelona(), epsg3043);
}

Prints

POINT(4.897000 52.371000) -> POINT(629144.771310 5803996.656944)
POINT(2.173400 41.385100) -> POINT(430887.564331 4581837.853239)
POINT(4.897000 52.371000) -> POINT(629144.771310 5803996.656944)
POINT(2.173400 41.385100) -> POINT(430887.564331 4581837.853239)

Disclaimer:

I'm not actually convinced that the UTM point type I defined makes much sense. I think any point type that can receive 2 coordinates will do. At least the srs::... as the coordinate system doesn't seem to do anything - bg::convert, bg::assign and friends don't magically know how to apply the projection anyways. I think the "doxygen_z_article09" link you included is just badly out of date/not how things were eventually implemented.

Determining UTM zone (to convert) from longitude/latitude

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.



Related Topics



Leave a reply



Submit