Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The end of the world ... how to deal with it? #929

Open
mtennekes opened this issue Aug 30, 2024 · 13 comments
Open

The end of the world ... how to deal with it? #929

mtennekes opened this issue Aug 30, 2024 · 13 comments
Labels
compat v3 to v4 transition help wanted

Comments

@mtennekes
Copy link
Member

One of the very few features in v3 that is not (yet) in v4:

tm_shape(World, projection = "+proj=eck4") + tm_polygons() + tm_style("natural")

image

This "natural" style has a tmap option earth.boundary set to TRUE.

The v3 implementation is beyond ugly, so I'm looking for a more elegant solution. The main problem was/is that the 'boundary' of the earth is not simply the longlat bounding of -180 - 180 and -90 - 90. A crs with the center at the Pacific or at one of the poles has different earth boundaries.

Does someone know an elegant solution to find the outline of a crs? @Nowosad @edzer @mdsumner

@mtennekes mtennekes added help wanted compat v3 to v4 transition labels Aug 30, 2024
@edzer
Copy link
Contributor

edzer commented Aug 30, 2024

Is this not an issue that could/would be solved at the level of PROJ?

@mdsumner
Copy link

gdal_footprint looks pretty good

library(terra)
r <- project(setValues(rast(), 1), "+proj=eck4")
writeRaster(r, tf <- tempfile(fileext = ".tif"), overwrite = TRUE)
system(sprintf("gdal_footprint %s %s", tf, out <- tempfile(fileext = ".fgb")))

plot(vect(out))

I tried running that with the osgeo.gdal api but don't really have the fortitude for that rn.

@mtennekes
Copy link
Member Author

Nice pragmatic approach @mdsumner

In the PROJ issue the function proj_trans_bounds was suggested. Is this function available or could this become available in one of the r-spatial packages (sf, PROJ, ...)?

@mdsumner
Copy link

Certainly in PROJ, I'll have a try at some point, but don't have much capacity atm.

@edzer
Copy link
Contributor

edzer commented Aug 30, 2024

See r-spatial/sf#2415

> st_bbox(st_as_stars()) |> st_transform("+proj=eck4")
     xmin      ymin      xmax      ymax 
-16921203  -8460601  16921203   8460601 
...
> st_bbox(vect(out))
     xmin      ymin      xmax      ymax 
-16921203  -8424632  16908719   8460601 

Or the longer path:

> st_bbox(st_as_stars()) |> 
    st_as_sfc() |> 
    st_set_crs(NA) |> 
    st_segmentize(1) |> 
    st_set_crs("OGC:CRS84") |> 
    st_transform("+proj=eck4") -> x
> st_bbox(x)
     xmin      ymin      xmax      ymax 
-16921203  -8460601  16921203   8460601 

where the hoop through NA_crs_ is needed to get the zero distance lines at the poles.

@mdsumner
Copy link

mdsumner commented Aug 30, 2024

I didn't think that was what was being asked (right?), and I think Even misunderstood too. I was surprised to see that proj_trans_bounds returns just the 4 numbers. Confirmed with

library(reticulate)
pyproj <- import("pyproj")

## I have to fix this somewhere back up
pyproj$datadir$set_data_dir("/usr/local/share/proj")
trans <- Transformer$from_crs("EPSG:4326", "+proj=eck4")
trans$transform_bounds(left = -180, bottom = -90, right = 180, top = 90, direction = pyproj$enums$TransformDirection$FORWARD)

[[1]]
[1] -8460601

[[2]]
[1] -8323299

[[3]]
[1] 8460601

[[4]]
[1] 8323299

edit: heck though the numbers are different, unsure ...

It's the same as raster::projectExtent and reproj::reproj_extent, it's not the visible region boundary, just a fleshed out projected extent. fwiw, I use this every day, it's impossible to exist without it.

reproj::reproj_extent(c(-180, 180, -90, 90), "+proj=eck4", source = "EPSG:4326")
[1] -16921203  16921203  -8460601   8460601

@mtennekes
Copy link
Member Author

Yes, that is correct @mdsumner : I'm looking for the visible boundary, expecting a polygon rather than a box.

@edzer
Copy link
Contributor

edzer commented Aug 30, 2024

st_bbox(st_as_stars()) |> 
    st_as_sfc() |> 
    st_set_crs(NA) |> 
    st_segmentize(1) |> 
    st_set_crs("OGC:CRS84") |> 
    st_transform("+proj=eck4") |> 
    plot(axes = TRUE)

x

@mdsumner
Copy link

mdsumner commented Aug 30, 2024

that only works in this particular case where the normal boundary aligns with the target one, not every projected region is the outline of -180,180,-90,90 and it won't work for global laea at all (as just one example)

@mdsumner
Copy link

also @mtennekes I can't see how to distinguish the edge of the world from NA, in your above example there are missing values literally outside the boundary which is convenient for the footprint approach, but here for example the NAs are just arbitrarily applied

library(terra)
r <- rast("/vsicurl/https://noaadata.apps.nsidc.org/NOAA/G02135/south/daily/geotiff/2024/08_Aug/S_20240823_concentration_v3.0.tif")
pts <- reproj::reproj_xy(xyFromCell(r, 1:ncell(r)), "EPSG:4326", source = crs(r))

r[pts[,2] > -50] <- NA
writeRaster(r, tf <- tempfile(fileext = ".tif"), overwrite = TRUE)
system(sprintf("gdal_footprint %s %s", tf, out <- tempfile(fileext = ".fgb")))

plot(vect(out))

and, there are many projections that will simply repeat (it goes out to some factor of pi I noticed, and it's not symmetric in each direction but I'm not sure). So I'm not sure the question is entirely well defined.

this for example, it's nice that the warper now does this, but I think you're asking for a boundary that doesn't always exist, although I think you could reasonably expect something. 🙏

library(terra)
dsn <- "/vsicurl/https://gebco2023.s3.valeria.science/gebco_2023_land_cog.tif"
r <- project(rast(dsn), rast(ext(c(-1, 1, -1, 1) * 5e7), ncols = 1024, nrows = 1024, crs = "+proj=omerc +lonc=147 +alpha=15"), by_util = TRUE)
plot(r)

image

@mtennekes
Copy link
Member Author

st_bbox(st_as_stars()) |> 
    st_as_sfc() |> 
    st_set_crs(NA) |> 
    st_segmentize(1) |> 
    st_set_crs("OGC:CRS84") |> 
    st_transform("+proj=eck4") |> 
    plot(axes = TRUE)

x

Thx @edzer Something along these lines would be sufficient for compatibility with tmap3. However, a test with EPSG 3035 wasn't successful yet:

EU = st_transform(World, crs = 3035)

poly = st_bbox(st_as_stars()) |> 
	st_as_sfc() |> 
	st_set_crs(NA) |> 
	st_segmentize(1) |> 
	st_set_crs("OGC:CRS84") |> 
	st_transform(3035) |> 
	st_as_sf()

tm_shape(EU) + 
	tm_polygons() +
	tm_shape(poly) +
	tm_borders(col = "purple", lwd = 3)

image

Yes @mdsumner I'm fully aware that not every crs has such a visible boundary (not even WGS84/Mercator)

@DOSull
Copy link

DOSull commented Sep 1, 2024

Yes @mdsumner I'm fully aware that not every crs has such a visible boundary (not even WGS84/Mercator)

Especially not Mercator!

A tmap function that resolved this problem for even a fraction of common world projections would be a major achievement as it's very hard problem. A solution requires inferring for any given projection what it's boundary conditions look like. There simply isn't going to be a one-size fits all answer for that problem, at any rate not a simple one at the level I assume you are hoping for.

Finite cyclindrical rectangular projections or even pseudo-cylindrical projections, if you know their central meridian, would allow a solution similar to @edzer's with the great circle appropriately modified, but in many cases the underlying projection will be making such a mess of the world map that colouring in the 'world footprint' appropriately is the least of your problems!

World$geometry |> st_transform("+proj=moll +lon_0=120") |> plot()

image

That's a simple central meridian shift. Once you start working with oblique forms and shifting projection centres things get even messier. It's a problem that d3 does a much better job of than proj, but that implies a major overhaul of proj and even how we approach geospatial data!

If you do figure out an approach, sing it from the rooftops!

@edzer
Copy link
Contributor

edzer commented Sep 1, 2024

An attempt to cut out the visible part for orthographic projections is found here, but I'd admit it's pretty ugly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compat v3 to v4 transition help wanted
Projects
None yet
Development

No branches or pull requests

4 participants