-
Notifications
You must be signed in to change notification settings - Fork 301
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
problem with inverse projection of "ortho" #1729
Comments
Update: a colleague using a windows machine and an earlier |
It would be useful to have the output of |
Thanks. This is on my version (which fails). I'll ask my colleague, on which it worked, to do the same, and I'll report back on those results (likely not until tomorrow).
|
Here are test results with macOS R-4.1.0 sf-0.9.5 (@dankelley)
macOS R-4.1.0 sf-1.0.0 binary from CRAN (@dankelley)
macOS R-4.1.0 sf-1.0.1, built locally from CRAN tarball (@dankelley)
windows-10-x64 R-4.0.2 sf-0.9.5 (@clayton33)
ubuntu-18.04.5 R-4.1.0 sf-0.9.5 (@richardsc)
|
The problem is almost 100% the "new" ellipsoidal formulation of the orthographic projection. You can force the spherical version by using library(sf)
#> Linking to GEOS 3.8.1, GDAL 3.2.1, PROJ 7.2.1
proj <- "+proj=ortho +lat_0=-20 +R=6378137 +f=0"
proj0 <- "OGC:CRS84"
grid <- expand.grid(lon=seq(-180,180,2.5), lat=seq(-90,90,2.5))
lonlat <- cbind(grid$lon, grid$lat)
xy <- sf_project(proj0, proj, lonlat, keep=TRUE)
#> Warning in CPL_proj_direct(from_to, as.matrix(pts), keep, warn,
#> authority_compliant): one or more projected point(s) not finite
LONLAT <- sf_project(proj, proj0, xy, keep=TRUE)
ok <- is.finite(LONLAT[,1]) & is.finite(LONLAT[,2])
par(mar=c(3,3,1,1), mgp=c(2,0.7,0))
plot(xy[,1]/1e3, xy[,2]/1e3, asp=1,
xlab="Easting Coordinate [km]", ylab="Northing Coordinate [km]",
pch=20, cex=0.3, col=ifelse(ok, "red", "blue"))
grid() Created on 2021-07-16 by the reprex package (v0.3.0) |
As usual, Dewey is very smart, and very helpful!! I'm thinking that I'll be able to get a version to work without asking users to update a whole lot of things, just by adding a converter function, along the lines shown below. (I guess I'll want to add a test on the Oh, and thanks, @paleolimbot, for pointing out that neat trick of using projFix <- function(CRS) # FIXME: check sf version (?)
{
if (grepl("=ortho", CRS)) {
if (!grepl("+R=", CRS))
CRS <- paste(CRS, "+R=6378137")
if (!grepl("+f=", CRS))
CRS <- paste(CRS, "+f=0")
}
CRS
}
proj <- projFix("+proj=ortho +lat_0=-20 +datum=WGS84 +no_defs")
proj0 <- projFix("OGC:CRS84") # ? "+proj=longlat +datum=WGS84 +no_defs" |
It's equivalent to Thee thing I did is a workaround...this is a great catch of a bug in PROJ and should get reported there! |
Not a bug, a design decision to permit both spherical and ellipsoidal: OSGeo/PROJ@2e104e0. See also issue OSGeo/PROJ#397 and the mailing list thread from https://lists.osgeo.org/pipermail/proj/2016-July/007020.html, all based on http://www.hydrometronics.com/downloads/Ellipsoidal%20Orthographic%20Projection.pdf. The note on https://proj.org/operations/projections/ortho.html giving the work-around to retain legacy output is in the commit at OSGeo/PROJ@2e104e0. The PROJ 7.2.0 release states in Updates in NEWS:
PROJ does make breaking changes requiring downstream intervention to retain output consistency with earlier versions; this also happens when the values in |
I think regardless of ellipsoidal vs spherical, the output that @dankelley kindly provided is not intentional...the set of invert-able points should be roughly the same whether the earth is ellipsoidal or spherical, no? |
I think that to say this is a bug, an app-level reprex using first
Further, the problems are only for the inverse, as forward works as described, with no visible blue points if
Maybe Can anyone see how to use an environment variable to set the PJ_LOG_LEVEL to get the trace? |
It looks like the polar and equatorial versions are special-cased and that anything else has a convergence algorithm that starts at the centre point and quits after 20 iterations. https://github.com/OSGeo/PROJ/blob/master/src/projections/ortho.cpp#L233-L274 I wonder if 20 iterations is too few for a reasonable approximation? |
@dankelley Is the whole globe inverse ellipsoidal |
@rsbivand thanks for the question, and your comments on this issue. For my own case, looking mainly at world views, the difference between spherical and ellipsoidal models is not critical, and I can stick with the spherical view, for which it seems there is no problem. I cannot speak for others, of course, since it's difficult to predict what people will need in their work. Those who really need an inverse in the ellipsoidal case could always set up their own minimization code to find it, starting with the spherical inverse as a guess. When I've done that in the past, I've found simple schemes (e.g. Nelder-Meade) work reasonably well. Still, if I really needed the ellipsoidal inverse at the moment, I'd start by increasing the iteration limit that @paleolimbot pointed out. Admittedly, I've not examined |
So on balance should we raise an issue/create a PR to increase the limit? Or work around the difficulty by changing code to ensure that the legacy spherical code is used, which I think is the intention of the note in the documentation? |
I played with this a bit and can't find anything in ortho.cpp that is off...the inverse seems to work and seems to be unchanged since the implementation. You can recreate my adventures here: https://gist.github.com/paleolimbot/6cecbac456a21030b9c2aaf5214e5e82 . |
Very interesting! See also:
So is sf following a different path in instantiating the pipeline? Maybe not?
|
Looks like sf is using Line 272 in 370f934
...however, I get the same results when using a pipeline operation in sf: library(sf)
#> Linking to GEOS 3.8.1, GDAL 3.2.1, PROJ 7.2.1
phi0_deg <- -20
phi0 <- phi0_deg * pi / 180
proj <- sprintf("+proj=ortho +lat_0=%s +ellips=WGS84", phi0_deg)
proj0 <- "+proj=longlat"
coord_op_inverse <- sf_proj_pipelines(paste0(proj, " +type=crs"), paste0(proj0, " +type=crs"))$definition[1]
grid <- expand.grid(lon=seq(-180,180,2.5), lat=seq(-90,90,2.5))
lonlat <- cbind(grid$lon, grid$lat)
xy <- sf_project(proj0, proj, lonlat, keep=TRUE)
#> Warning in CPL_proj_direct(from_to, as.matrix(pts), keep, warn,
#> authority_compliant): one or more projected point(s) not finite
LONLAT <- sf_project(proj, proj0, xy, keep=TRUE)
#> Warning in CPL_proj_direct(from_to, as.matrix(pts), keep, warn,
#> authority_compliant): one or more projected point(s) not finite
LONLAT_pipeline <- sf::sf_project(coord_op_inverse, pts = xy, keep = TRUE)
#> Warning in CPL_proj_direct(from_to, as.matrix(pts), keep, warn,
#> authority_compliant): one or more projected point(s) not finite
identical(LONLAT, LONLAT_pipeline)
#> [1] TRUE
ok <- is.finite(LONLAT[,1]) & is.finite(LONLAT[,2])
ok2 <- is.finite(LONLAT_pipeline[,1]) & is.finite(LONLAT_pipeline[,2])
par(mar=c(3,3,1,1), mgp=c(2,0.7,0))
plot(xy[,1]/1e3, xy[,2]/1e3, asp=1,
xlab="Easting Coordinate [km]", ylab="Northing Coordinate [km]",
pch=20, cex=0.3, col=ifelse(ok2, "red", "blue"))
grid() Created on 2021-07-21 by the reprex package (v0.3.0) |
I can also confirm that this behaviour occurs in the latest released PROJ (8.1.0) |
On closer inspection, the results are identical in rgdal and sf: library(sf)
#> Linking to GEOS 3.8.1, GDAL 3.2.1, PROJ 7.2.1
phi0_deg <- -20
phi0 <- phi0_deg * pi / 180
proj <- sprintf("+proj=ortho +lat_0=%s +ellips=WGS84", phi0_deg)
proj0 <- "+proj=longlat"
coord_op_inverse <- sf_proj_pipelines(paste0(proj, " +type=crs"), paste0(proj0, " +type=crs"))$definition[1]
grid <- expand.grid(lon=seq(-180,180,2.5), lat=seq(-90,90,2.5))
lonlat <- cbind(grid$lon, grid$lat)
xy <- sf_project(proj0, proj, lonlat, keep=TRUE)
#> Warning in CPL_proj_direct(from_to, as.matrix(pts), keep, warn,
#> authority_compliant): one or more projected point(s) not finite
LONLAT <- sf_project(proj, proj0, xy, keep=TRUE)
#> Warning in CPL_proj_direct(from_to, as.matrix(pts), keep, warn,
#> authority_compliant): one or more projected point(s) not finite
LONLAT_rgdal <- rgdal::project(xy, proj, inv=TRUE)
#> Warning in project(bb, proj, inv = inv, use_aoi = FALSE): 2 projected point(s)
#> not finite
#> Warning in rgdal::project(xy, proj, inv = TRUE): 1821 projected point(s) not
#> finite
ok <- is.finite(LONLAT[,1]) & is.finite(LONLAT[,2])
ok2 <- is.finite(LONLAT_rgdal[,1]) & is.finite(LONLAT_rgdal[,2])
identical(ok, ok2)
#> [1] TRUE Created on 2021-07-21 by the reprex package (v0.3.0) |
Correct, I mistyped |
So can we conclude this is a feature of recent |
Yes, sf is correctly calling PROJ, where something that was probably not intended is happening. If I get a chance I will open an issue there. |
I may have encountered an
sf
problem with theortho
projection, in cases with a viewpoint that is not on the equatorial plane. I am on macOS Monterey (Version 12.0 beta (21A5268h).The reprex pasted below illustrates. The points are for a lon-lat grid transformed to x-y space using the
ortho
projection. Red dots are used if the point can be converted back from x-y to lon-lat, and blue otherwise. Thus, blue indicates a problem, and I see this in thin patches along the top "shoulders" of the view, and in larger patches along the sides of the bottom region.This problem shows up on my macOS system in three versions of
sf
:A colleague using an earlier version of
sf
revealed that it was ok in that system. I've also found that I get all red dots if usergdal::project()
for the computations.From these tests, it seems to me that there is something worth exploring. I hope my test is simple enough to be useful. Of course, I would be very happy to do further tests, if requested.
I hope this comment is of some use.
PS. more discussion of why I'm doing this is at dankelley/oce#1848, although it's not fully-explained, the issue being more in the form of a diary of an idea I'm trying for the
oce
package.Created on 2021-07-15 by the reprex package (v2.0.0)
The text was updated successfully, but these errors were encountered: