WorldWindJava
WorldWindJava copied to clipboard
Coordinate problem with ProjectionMercator
The new 2D support is very nice. Thanks for this!
But unfortunately there seems to be a coordinate transformation issue probably related to the mercator projection. When I put a PointPlacemark into a 2D map using ProjectionMercator from a mouse listener the actual point of the icon on the screen seems to be systematically moved to the north (at least with german coordinates around 50.7, 7). This occurs also when moving the map around and when turning the map (the screen point is always shifted to the north). Since the distance shift seems to be constant this can best be seen using a small map scale.
There is no error when using ProjectionEquirectangular or ProjectionSinusoidal.
Version: 2.1.0
-- edit -- The following "pseudo" code produces coordinates with a distance error of around 50 meters.
`GeographicProjection projection = new ProjectionMercator(); double latitude = 50.7; double longitude = 7.017;
Globe globe = new EarthFlat();
Vec4 offset = Vec4.ZERO;
Vec4 v = projection.geographicToCartesian(globe, Angle.fromDegrees(latitude), Angle.fromDegrees(longitude), 0.,
offset);
LOGGER.info("v = {}", v);
Position pos = projection.cartesianToGeographic(globe, v, offset);
LOGGER.info("Position = {}", pos);
double dist = new GeoPosition(latitude, longitude, 0.).getDistanceOnEllipsoid(new GeoPosition(pos.getLatitude().degrees, pos.getLongitude().degrees, 0.), WGS84.WGS84);
LOGGER.info("dist = {}", dist);
assertEquals(0., dist, 1.e-1);`
This happens to me as well if I use the default elevation model without any elevation data turned on. I think officially only the ZeroElevationModel is supported in 2d mode.
Try adding this to your code -
globe.setElevationModel(new ZeroElevationModel());
Actually the ZeroElevationModel is used already so this does not seem to be the problem.
The problem seems to be in the reverse mercator projection. If I replace the reverse function cartesianToGeographic with a traditional iteration approach everything is fine. So the problem seems to be in the optimized formulas or the series expansion used for computational efficiency has to be extended?
Here the traditional iteration code:
`@Override public Position cartesianToGeographic(Globe globe, Vec4 cart, Vec4 offset) { double xOffset = offset != null ? offset.x : 0;
double t = Math.exp(-cart.y / globe.getEquatorialRadius());
double lat = Math.PI / 2. - 2. * Math.atan(t);
double ecc = Math.sqrt(globe.getEccentricitySquared());
double ecc_2 = 0.5 * ecc;
final int MAX_ITERATIONS = 15;
final double TOLERANCE = 1.e-10;
for (int i = 0; i < MAX_ITERATIONS; i++)
{
double con = ecc * Math.sin(lat);
double nextLat = Math.PI / 2. - 2. * Math.atan(t * Math.pow((1. - con) / (1. + con), ecc_2));
if (Math.abs(lat - nextLat) <= TOLERANCE)
{
lat = nextLat;
break;
}
lat = nextLat;
}
return Position.fromRadians(lat, (cart.x - xOffset) / globe.getEquatorialRadius(), cart.z);
} `
@helgekoch thanks for the psuedo code example, I see the same issue.
Looking at the Google book version of the source document, it looks like series 3-5 from page 45 was identified as equation schema 3-38 from page 19, but it actually looks like 3-34. That's my two cents, or, am I misreading things?
So
double chi = Math.PI / 2 - 2 * Math.atan(t);
double A = ecc2 / 2 + 5 * ecc4 / 24 + ecc6 / 12 + 13 * ecc8 / 360;
double B = 7 * ecc4 / 48 + 29 * ecc6 / 240 + 811 * ecc8 / 11520;
double C = 7 * ecc6 / 120 + 81 * ecc8 / 1120;
double D = 4279 * ecc8 / 161280;
double Ap = A - C;
double Bp = 2 * B - 4 * D;
double Cp = 4 * C;
double Dp = 8 * D;
double s2c = Math.sin(2 * chi);
double c2c = Math.cos(2 * chi);
double lat = chi + s2c * (Ap + c2c * (Bp + c2c * (Cp + Dp * c2c)));
I think that that's how it should look... ProjectionMercator.java, lines 124 to 138