There are "bugs" in multiple APIs handling of 180.
1. GeometryEngine.Project when converting to Web Mercator returns NaN for +/-180. It should return +/-pi*EarthWGS84Radius
2. Polyline graphics that span across the 180 line are connected the "long" way instead of the "short" way: a short line becomes one that spans the globe.
For problem 2, I understand there is a theoretical ambiguity as to which way to connect the lines. In most cases, picking the shortest path is likely to be the correct answer.
I've worked through many of the issues by just avoiding the GeometryEngine and using my own implementations instead. To make lines connect correctly, I test if a simple planar connect would be too long and if so, I adjust the "left" point to be the right by adding the width of the WebMercator projection before supplying the points to the runtime.
Hi,
Could you provide simple reproducers for all the issues that you find with the geometry engine and attach them to this chain?
cheers,
Antti
Hi Antti, I'll provide some examples below. There's more. I've written more than a thousand lines of workarounds last week and it is hard to keep track of it all! Another strange behavior I uncovered was the map view extent going null when the map center is set to NaN. Granted, NaN is nonesense, but SetViewAsync should complain/throw right away instead. The NaN made it to the map view because of innocent looking code like this:
static async void TestExtentAndSetView(MapView map, MapPoint point)
{
var p = Project(NormalizeCentralMeridian(point), map.SpatialReference);
var extent = NormalizeCentralMeridian(map.Extent);
if (!Within(p, extent))
{
try { await map.SetViewAsync(point, TimeSpan.FromSeconds(1.5)); }
catch (Exception ex) { /*log the error*/ }
}
}
I have since switched over to my own "envelope" and "projection" code that is easier to use and get right.
static MapPoint EsriProject(double lat, double lon)
{
return (MapPoint)GeometryEngine.Project(new MapPoint(lon, lat, SpatialReferences.Wgs84), SpatialReferences.WebMercator);
}
static MapPoint EsriUnProject(double x, double y)
{
return (MapPoint)GeometryEngine.Project(new MapPoint(x, y, SpatialReferences.WebMercator), SpatialReferences.Wgs84);
}
public void Test()
{
Action<double> xNaN = lon => Assert.IsTrue(double.IsNaN(EsriProject(0, lon).X));
xNaN(-180);
xNaN(180);
xNaN(-179.99999);
xNaN(179.99999);
}
const double Wgs84EarthSemiMajorRadiusMeters = 6378137;
const double webMercatorMaxX = Wgs84EarthSemiMajorRadiusMeters * System.Math.PI;
var p1 = EsriUnProject(webMercatorMaxX, 0);
var p2 = EsriUnProject(-webMercatorMaxX, 0);
System.Console.WriteLine(p1); // prints MapPoint[X=NaN, Y=NaN, Wkid=4326]
System.Console.WriteLine(p2); // prints MapPoint[X=NaN, Y=NaN, Wkid=4326]
Envelope unions do simple min/max and do not handle the wrap around. That means that the a union operation may connect the long way across the world when the intent is the short way. I've written my own "GeoRect" code that has a well defined left and right and can handle the wraparound. In other places, I do something like this:
static void FixXsForEsri(ref double x1, ref double x2, double y1, double y2, double expectedLength)
{
var distSqd = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
bool simpleConnectWouldBeTheLongWayAcrossTheWorld = distSqd > expectedLength * expectedLength * 2.0;
if (simpleConnectWouldBeTheLongWayAcrossTheWorld)
{
// Map X on negative side of the projection origin to the right.
if (x2 < 0.0)
x2 += GeoRectMaxBounds.WebMercator.Width;
else if (x1 < 0.0)
x1 += GeoRectMaxBounds.WebMercator.Width;
}
}
I can see how the way Envelope behaves could be more renderer friendly. Simple min/max-ing is less "branchy" than the wrap test code. From a map API user's view, it is quite unfriendly.
Simple Repro:
var p1 = new MapPoint(179, 0, SpatialReferences.Wgs84);
var p2 = GeometryEngine.GeodesicMove(p1, 1e3, LinearUnits.Kilometers, 90);
var e1 = new Envelope(p1, p1);
var e2 = new Envelope(p2, p2);
System.Console.WriteLine(e1.Union(e2).Width); // prints 351.016847158805 degrees !!
Hi,
I'm investigating your questions with our geometry team.
Cheers
Mike