I have an extent that I want to transform in order to change the ymax (i.e. limit the ymax to a new value):
library(terra)
# Set and extent
lulc.e <- ext(-830370, 787470, 117960, 2091060)
# Change the projection of the extent
lulc_4326 <- project(
x = lulc.e,
from = 'epsg:32198',
to = "epsg:4326"
)
# New northern limit
lulc_4326[4] <- 50.5
# Transformation to initial CRS
lulc_mer <- project(
x = lulc_4326,
from = "epsg:4326",
to = 'epsg:32198'
)
SpatExtent : -1258197.01421543, 1196121.64694709, 175176.718128633, 845351.049407211 (xmin, xmax, ymin, ymax)
Why is the coordinates not the same as the original? Is it a bug or there is a manipulation to the get the same results as the original values (except ymax)?
No, this is not a bug. Extent transformation is not point-by-point; meaning when you transform an extent, project() doesn't just transform the four corners coordinates, but it rather transforms the entire rectangular boundary and finds the new bounding box that encompasses all transformed points (which could be larger than the original extent). The transformation between these CRS is non-linear, so the rectangle in one becomes a curved shape in the other. Look at the results of crds(corners_4326) in the code below and the fact that x and y's (minimums and maximums) are not the same between the four corners;
library(terra)
#> terra 1.8.54
corners <- rbind(
c(-830370, 117960), # xmin, ymin
c(787470, 117960), # xmax, ymin
c(787470, 2091060), # xmax, ymax
c(-830370, 2091060) # xmin, ymax
)
corners_32198 <- vect(corners, crs = "epsg:32198")
corners_4326 <- project(corners_32198, "epsg:4326")
corners_4326
#> class : SpatVector
#> geometry : points
#> dimensions : 4, 0 (geometries, attributes)
#> extent : -84.40215, -53.3946, 44.51316, 62.10023 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84 (EPSG:4326)
crds(corners_4326)
#> x y
#> [1,] -78.94580 44.51316
#> [2,] -58.58680 44.56771
#> [3,] -53.39460 62.10023
#> [4,] -84.40215 62.01794
corners_back <- project(corners_4326, "epsg:32198")
corners_back
#> class : SpatVector
#> geometry : points
#> dimensions : 4, 0 (geometries, attributes)
#> extent : -830370, 787470, 117960, 2091060 (xmin, xmax, ymin, ymax)
#> coord. ref. : NAD83 / Quebec Lambert (EPSG:32198)
crds(corners_back)
#> x y
#> [1,] -830370 117960
#> [2,] 787470 117960
#> [3,] 787470 2091060
#> [4,] -830370 2091060
The best way (that I can think of) to achieve what you're seeking, with minimal effect on the other corners, is to create a point using vect in the interim CRS and project it back to the target one.
library(terra)
#> terra 1.8.54
lulc.e <- ext(-830370, 787470, 117960, 2091060)
# project just the ymax (x = -69 is approximately in the middle)
target_4326 <- vect(cbind(-69, 50.5), crs = "epsg:4326")
target_32198 <- project(target_4326, "epsg:32198")
new_ymax <- crds(target_32198)[2]
lulc_mer <- ext(lulc.e[1], lulc.e[2], lulc.e[3], new_ymax)
lulc_mer
#> SpatExtent : -830370, 787470, 117960, 721425.99533788 (xmin, xmax, ymin, ymax)
Created on 2025-08-16 with reprex v2.1.1