I'm trying to display some geometries that span the antimeridian in a WPF app. Ultimately, the geometries will be pulled from a map service, but I have a simple rectangle polygon that I'm testing with. This seems to be a pretty common issue, and I've read through all of the examples that I could find. Most of the examples I've seen are using the JS API, and I'm having trouble getting the same results in the .Net SDK.
The working JS example here (https://codepen.io/andygup/pen/QeyerP) appears to call geodesicUtils.geodesicDensify() to resolve the issue. I didn't see any reference to NormalizeCentralMeridian() in this example, like I've seen in other examples. Porting that to .Net didn't work, though.
This example converts to WebMercator then uses NormalizeCentralMeridian() (https://jsbin.com/xegicih/2/edit?html,output), but again is in JS.
This post (https://community.esri.com/t5/arcgis-runtime-sdk-for-net-questions/polyline-not-crossing-internation...) is in .Net and suggested adding 360 to the negative western longitudes. Doing this will put a box in the correct place, but with an extra line at 180 degrees. The JS examples don't have this issue.
Can the .Net SDK display a geometry the same way as the JS examples?
Here is a sample of the code I've been working with:
private void addGraphic(Geometry.Geometry geometry)
{
SimpleLineSymbol outlineSymbol =
new SimpleLineSymbol(SimpleLineSymbolStyle.Dash, Color.Green, 2);
Geometry.PointCollection points =
new Geometry.PointCollection(SpatialReferences.Wgs84)
{
new MapPoint(-178, -5),
new MapPoint(-178, 5),
new MapPoint(178, 5),
new MapPoint(178, -5)
};
Polygon polygon = new Polygon(points);
Geometry.Geometry g = GeometryEngine.NormalizeCentralMeridian(polygon);
esriMap.SetViewpointGeometryAsync(g, 50);
Graphic graphic = new Graphic(g, outlineSymbol);
_overlay.Graphics.Add(graphic);
}
Here's how I tried adding 360 to the longitudes. That got me a bit closer, but still not what I was looking for:
private void addGraphic(Geometry.Geometry geometry)
{
SimpleLineSymbol outlineSymbol =
new SimpleLineSymbol(SimpleLineSymbolStyle.Dash, Color.Green, 2);
Geometry.PointCollection points =
new Geometry.PointCollection(SpatialReferences.Wgs84)
{
new MapPoint(-178, -5),
new MapPoint(-178, 5),
new MapPoint(178, 5),
new MapPoint(178, -5)
};
Polygon polygon = new Polygon(points);
Polygon newPoly;
Geometry.PointCollection newPoints =
new Geometry.PointCollection(SpatialReferences.Wgs84);
foreach (ReadOnlyPart gp in polygon.Parts)
{
foreach (MapPoint pt in gp.Points)
{
double x = pt.X;
if(x<0){ x += 360; }
newPoints.Add(new MapPoint(x, pt.Y));
}
}
newPoly = new Polygon(newPoints);
//this puts a box in the correct place,
//but has an extra vertical line at 180
esriMap.SetViewpointGeometryAsync(newPoly.Extent, 50);
Graphic graphic = new Graphic(newPoly, outlineSymbol);
_overlay.Graphics.Add(graphic);
}
I have EXACTLY the same problem (although I'm coding in VB.NET). Did you ever get an answer? When I apply NormalizeCentralMeridian to my polygon, nothing happens. I don't get two polygons returned.
Would you believe that I can't remember? I usually post updates if I find answers, so it's possible that I just had to move on.
I'll dig through my old project this afternoon, and see if I can find it.
Thanks - really appreciate that. I'm having 2 difficult problems, and NormalizeCentralMeridian seems to be doing nothing.
1. I have a simple rectangular box spanning the antimeridian. Can't split it in two with NormalizeCentralMeridian.
2. And then I have the mother of all meridian problems. I have a polygon enclosing Antarctica. Need to split that in two as well.
This problem is REALLY bugging me. I can't see what I'm doing wrong. I have written a minimal code example. It creates a linestring (using a polylinebuilder) that crosses the Antimeridian (it's a box around Fiji). It is 1 part with 5 points. I then apply NormalizeCentralMeridian to it to produce "normal". normal is identical to linestring.
Dim plb As New PolylineBuilder(SpatialReferences.Wgs84) ' drawn bounding box
plb.AddPoint(New MapPoint(177.17, -19.25)) ' first point
plb.AddPoint(New MapPoint(-179.65, -19.25))
plb.AddPoint(New MapPoint(-179.65, -15.67))
plb.AddPoint(New MapPoint(177.17, -15.67))
plb.AddPoint(New MapPoint(177.17, -19.25)) ' last point
Dim linestring = plb.ToGeometry
AppendText(TextBox1, $"Before {linestring.ToString}{vbCrLf}")
Dim normal = linestring.NormalizeCentralMeridian
AppendText(TextBox1, $"After {normal.ToString}{vbCrLf}")
Output of test program shows NormalizeCentralMeridian is having no effect
Before Polyline[Parts=1, Points=5, Wkid=4326]
After Polyline[Parts=1, Points=5, Wkid=4326]
I have a fix, but I'm not why it's valid. If I have a polygon that spans the antimeridian, I simply add 360 to any -ve X value. NormalizeCentralMeridian then does what you'd expect. I'm not sure I fully understand why, but at least I have a solution.
Do you have a snippet of code that you could post? That sounds like what I was trying, but I'm still getting an additional line along the antimeridian.
Below is the code I currently use. It works in almost all cases.
1. If you have a polygon spanning the antimeridian, it produces the desired result - the polygon is split into pieces. I have a box around Fiji, and I can render it no problem.
2. I also have a polygon that encircles the South Pole. This code is splitting the polygon into 3 pieces, but it is not rendering properly. All the signs on the X's in the 3 pieces are the same, so they look sensible.
The code works by testing for antimeridian crossing (CrossesAntiMeridian) and if it does then
1. deconstruct the polygon into a polygonbuilder so we can modify it
2. Add 360 to every X that is less than 0 in every part
3. Rebuild the polygon from the polygonbuilder
4. Use NormalizeCentralMeridian
5. Use Simplify as results of NormalizeCentralMeridian seem to leave polygons that are not Simple
As I said, it seems to be working for 'standard' cases where a pole is not involved, but it seems to breakdown at the poles.
Function CrossesAntiMeridian(g As Geometry) As Boolean
' returns true if geometry crosses anti-meridian
Return Math.Abs(g.Extent.XMax - g.Extent.XMin) > 300
End Function
Function NormalizeCentralMeridian(PolyBox As Polygon) As Polygon
' Normalize a polygon if it crosses the anti-meridian
If CrossesAntiMeridian(PolyBox) Then ' crosses anti-meridian
With PolyBox.Extent
Dim plb As New PolygonBuilder(PolyBox) ' deconstruct polygon to polygon builder
' Add 360 to any negative X value in any part
For prt = 0 To plb.Parts.Count - 1
For pnt = 0 To plb.Parts(prt).Points.Count - 1
If plb.Parts(prt).Points(pnt).X < 0 Then
plb.Parts(prt).SetPoint(pnt, New MapPoint(plb.Parts(prt).Points(pnt).X + 360, plb.Parts(prt).Points(pnt).Y, plb.SpatialReference)) ' add 360 to X
End If
Next
Next
Dim poly = plb.ToGeometry ' reconstruct geometry
Dim Normalized As Polygon = poly.NormalizeCentralMeridian ' split geometry into parts that don't cross the antimeridian
Normalized = Normalized.Simplify ' Normalizing seems to produce a non simple result
Return Normalized
End With
Else
Return PolyBox ' doesn't cross anti-meridian
End If
End Function
Below