Home > Software engineering >  Convert lat/long to UTM (zone 27)
Convert lat/long to UTM (zone 27)

Time:10-12

I am struggling to convert my lat and long columns to UTM (zone 27). I found the below function in another post but I believe I am running into an issue due to not all my sites not having spatial data. When I run the below function it does not change my lat long. When I run specific lines I get an error on the first line of the function for the coordinates().

#data

brazil_legacy_data <- structure(list(site = c("1 water", "2 water", "3 water", "4 water", 
"5 water", "6 water", "7 water", "8 water", "9 water", "10 water", 
"11 water", "lago angelim water", "lago anta water", "lago minutal water", 
"lago sede water", "poça temporária water", "trilha water", 
"1 land", "2 land", "3 land", "4 land", "5 land", "6 land", "7 land", 
"8 land", "9 land", "10 land", "11 land", "lago angelim land", 
"lago anta land", "lago minutal land", "lago sede land", "poça temporária land", 
"trilha land"), lat = c(-23.340813, -23.342987, -23.343694, -23.340738, 
-23.332042, -23.324259, -23.327646, -23.313991, NA, -23.386967, 
NA, NA, NA, NA, NA, NA, NA, -23.340744, -23.343771, -23.343741, 
-23.341032, -23.331908, -23.324572, -23.326528, -23.31427, NA, 
-23.387007, NA, NA, NA, NA, NA, NA, NA), long = c(-45.149414, 
-45.144503, -45.129222, -45.117734, -45.099698, -45.089126, -45.133222, 
-45.120015, NA, -45.187918, NA, NA, NA, NA, NA, NA, NA, -45.150486, 
-45.144043, -45.128388, -45.117835, -45.097041, -45.094422, -45.132481, 
-45.124575, NA, -45.186547, NA, NA, NA, NA, NA, NA, NA), region = c("santa virginia", 
"santa virginia", "santa virginia", "santa virginia", "santa virginia", 
"santa virginia", "santa virginia", "santa virginia", "santa virginia", 
"santa virginia", "santa virginia", "santa virginia", "santa virginia", 
"santa virginia", "santa virginia", "santa virginia", "santa virginia", 
"santa virginia", "santa virginia", "santa virginia", "santa virginia", 
"santa virginia", "santa virginia", "santa virginia", "santa virginia", 
"santa virginia", "santa virginia", "santa virginia", "santa virginia", 
"santa virginia", "santa virginia", "santa virginia", "santa virginia", 
"santa virginia"), location = c("brazil", "brazil", "brazil", 
"brazil", "brazil", "brazil", "brazil", "brazil", "brazil", "brazil", 
"brazil", "brazil", "brazil", "brazil", "brazil", "brazil", "brazil", 
"brazil", "brazil", "brazil", "brazil", "brazil", "brazil", "brazil", 
"brazil", "brazil", "brazil", "brazil", "brazil", "brazil", "brazil", 
"brazil", "brazil", "brazil")), row.names = c(NA, -34L), class = c("tbl_df", 
"tbl", "data.frame"))

# convert to utm
long2utm <- function(long)  {
  (floor((long   180)/6) %% 60)  1
}

LongLatToUTM <- function(brazil_legacy_sites){
    ## Args: df, data frame must have x and y columns. Should be from same UTM zone.
    ## Create a spatial dataframe
    coordinates(brazil_legacy_sites) <- ~lat long
    proj4string(brazil_legacy_sites) <- CRS(" proj=longlat  datum=WGS84")  

    ## Get zones for all the points in the data frame. 
    ## Stop if more than one zone is present. 
    ## You can write your own code for handling cases where your 
    ## data comes from different UTM zones.

    zone <- long2UTM(brazil_legacy_sites$lat)
    if (length(unique(zone)) > 1) stop("values from different UTM zones")
    zone <- unique(zone)

    ## Change CRS of the spatial data frame and convert to data frame
    res <- spTransform(brazil_legacy_sites, CRS(paste0(" proj=utm  zone=", zone, " datum=WGS84")))
    return(as.data.frame(res))
}

CodePudding user response:

With these data you only need zone 23

b <- as.data.frame(brazil_legacy_data)
long2utm(b$long) |> unique()
#[1] 23 NA

So I will skip the loop

library(terra)
v <- vect(b, c("long", "lat"), crs=" proj=longlat")
u <- terra::project(v, " proj=utm  zone=23")
utm <- crds(u)

head(utm)
#            x        y
#[1,] 484726.5 -2581256
#[2,] 485228.8 -2581497
#[3,] 486790.9 -2581573
#[4,] 487964.9 -2581245
#[5,] 489808.0 -2580281
#[6,] 490888.2 -2579419

All together

i <- which(!is.na(b$long))
b[i, c("x", "y")] <- utm

head(b)
#     site       lat      long         region location        x        y
#1 1 water -23.34081 -45.14941 santa virginia   brazil 484726.5 -2581256
#2 2 water -23.34299 -45.14450 santa virginia   brazil 485228.8 -2581497
#3 3 water -23.34369 -45.12922 santa virginia   brazil 486790.9 -2581573
#4 4 water -23.34074 -45.11773 santa virginia   brazil 487964.9 -2581245
#5 5 water -23.33204 -45.09970 santa virginia   brazil 489808.0 -2580281
#6 6 water -23.32426 -45.08913 santa virginia   brazil 490888.2 -2579419

This was not working for you because you had "rgdal" loaded after "terra" and then you get

rgdal::project(v, " proj=utm  zone=23")
#Error in rgdal::project(v, " proj=utm  zone=23") : xy not numeric
  • Related