This project has moved. For the latest updates, please go here.

MapRectangle crossing 180 degrees longitude

Nov 15, 2013 at 9:23 PM
Edited Nov 15, 2013 at 9:27 PM
I'm trying to place a MapRectangle that crosses 180 degrees, but the MapRectangle does not allow this. For example this MapRectangle will not show up:
<map:MapRectangle Fill="Black" North="61.58900" South="44.71300" East="-174.72400" West="156.72400" />
But this one works:
<map:MapRectangle Fill="Black" North="61.58900" South="44.71300" East="-154.72400" West="-174.72400" />
I did a bit of experimentation with MapRectangle.UpdateData and came up with this:
        protected override void UpdateData()
        {
            var geometry = (RectangleGeometry)Data;

            if (ParentMap != null &&
                !double.IsNaN(South) && !double.IsNaN(North) &&
                !double.IsNaN(West) && !double.IsNaN(East) &&
                //South < North && West < East)
                South < North)
            {
                var p1 = ParentMap.MapTransform.Transform(new Location(South, West));
                var p2 = ParentMap.MapTransform.Transform(new Location(North, East));

                // Handle the case of crossing over 180 degrees
                if (p2.X < p1.X)
                {
                    p2.X += 360;
                }

                // Create a scaled RectangleGeometry due to inaccurate hit testing in WPF.
                // See http://stackoverflow.com/a/19335624/1136211
                geometry.Rect = new Rect(p1.X * geometryScale, p1.Y * geometryScale,
                    (p2.X - p1.X) * geometryScale, (p2.Y - p1.Y) * geometryScale);

                var transform = new TransformGroup();
                transform.Children.Add(geometryScaleTransform); // revert scaling
                transform.Children.Add(ParentMap.ViewportTransform);
                RenderTransform = transform;
            }
            else
            {
                geometry.ClearValue(RectangleGeometry.RectProperty);
                ClearValue(RenderTransformProperty);
            }
        }
This works, but I think this is only a partial solution. If the viewport has 180 degree longitude to the right of center, then the rectangle is visible. As the user drags 180 degree longitude left across the center of the viewport, the rectangle jumps out of view. At ZoomLevel 0 with the screen maximized you can see it jump along with the Points and PushPins.

Any ideas on making the rectangles (and other items) stay visible for someone working along 180 degrees longitude?
Coordinator
Nov 17, 2013 at 7:09 PM
Edited Nov 17, 2013 at 7:15 PM
As of version 1.9.0 the map control has a modified calculation of viewport positions from MapPanel.Location property values. Viewport positions are now kept near the map center, and remain visible when the map center crosses 180° latitude (i.e jumps from E180 to W180 and vice versa).

This change does however not apply to MapRectangle, since here viewport positions are not continuously recalculated during map viewport changes. Instead the "logical" (Mercator-transformed) coordinates are calculated once (in UpdateData) and subsequently transformed by the ViewportTransform in MapBase. This is done for performance reasons.

You may however use the following workaround until I finally come up with a solution. First, take care that the value of the East property is always greater than the West value in your application. It doesn't matter if West is less then -180 or East is greater than 180.

Then add a handler for the MapBase.ViewportChanged event and check if the MapRectangle and the Center Location of the map lie on different sides of 180° longitude. If that is the case, adjust the West and East values.
private void MapViewportChanged(object sender, EventArgs e)
{
    var map = sender as Map;

    if (Math.Abs(map.Center.Longitude - mapRectangle.West) > 180d)
    {
        if (mapImage1.West < 0d)
        {
            mapRectangle.West += 360d;
            mapRectangle.East += 360d;
        }
        else
        {
            mapRectangle.East -= 360d;
            mapRectangle.West -= 360d;
        }
    }
}
Nov 18, 2013 at 6:54 PM
Thanks for the workaround. This is working nicely in my project.

Rob