Table of Contents

Source Code WpfDesktopEdition WrapDatelineModeWithProjection CS 110510.zip

App.xaml.cs

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
namespace WrapDatelineMode
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
    }
}

TestWindow.xaml.cs

using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using ThinkGeo.MapSuite.Core;
using ThinkGeo.MapSuite.WpfDesktopEdition;
namespace WrapDatelineMode
{
    /// <summary>
    /// Interaction logic for TestWindow.xaml
    /// </summary>
    public partial class TestWindow : Window
    {
        public TestWindow()
        {
            InitializeComponent();
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            wpfMap1.Background = new SolidColorBrush(Color.FromRgb(148, 196, 243));
            //Sets the correct map unit
            wpfMap1.MapUnit = GeographyUnit.DecimalDegree;
            //Sets the map extent in real coordinates.
            wpfMap1.CurrentExtent = new RectangleShape(-240.52, 59.04, -104.81, -39.22);
            WorldMapKitWmsWpfOverlay worldMapKitWmsWpfOverlay = new WorldMapKitWmsWpfOverlay();
            worldMapKitWmsWpfOverlay.Projection = WorldMapKitProjection.DecimalDegrees;
            //Sets the WrapDatelineMode to WrapDateline for the overlay.
            worldMapKitWmsWpfOverlay.WrappingMode = WrappingMode.WrapDateline;
            wpfMap1.Overlays.Add("WMK", worldMapKitWmsWpfOverlay);
            InMemoryFeatureLayer inMemoryFeatureLayer = new InMemoryFeatureLayer();
            inMemoryFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.CreateSimpleCircleStyle
                                                         (GeoColor.FromArgb(120, GeoColor.StandardColors.Red), 12);
            inMemoryFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.CreateSimpleAreaStyle(GeoColor.StandardColors.Transparent, GeoColor.StandardColors.Green, 2);
            inMemoryFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
            inMemoryFeatureLayer.Open();
            inMemoryFeatureLayer.InternalFeatures.Add(new Feature(new PointShape(-118.37,33.70))); //Los Angeles
            inMemoryFeatureLayer.InternalFeatures.Add(new Feature(new PointShape(139.98,35.61))); //Tokio
            inMemoryFeatureLayer.Close();
            LayerOverlay dynamicOverlay = new LayerOverlay();
            //Sets the WrapDatelineMode to WrapDateline for the overlay.
            dynamicOverlay.WrappingMode = WrappingMode.WrapDateline;
            dynamicOverlay.Layers.Add(inMemoryFeatureLayer);
            wpfMap1.Overlays.Add("DynamicOverlay", dynamicOverlay);
            wpfMap1.Refresh();
        }
        //Switches the map to Decimal Degrees
        private void ToDecimalDegrees(RectangleShape currentExtent)
        {
            if (wpfMap1.Overlays.Count > 0)
            {
                wpfMap1.MapUnit = GeographyUnit.DecimalDegree;
                wpfMap1.CurrentExtent = currentExtent;
                WorldMapKitWmsWpfOverlay worldMapKitWmsWpfOverlay = (WorldMapKitWmsWpfOverlay)wpfMap1.Overlays["WMK"];
                worldMapKitWmsWpfOverlay.Projection = WorldMapKitProjection.DecimalDegrees;
                LayerOverlay dynamicOverlay = (LayerOverlay)wpfMap1.Overlays["DynamicOverlay"];
                foreach (FeatureLayer featureLayer in dynamicOverlay.Layers)
                {
                    featureLayer.FeatureSource.Projection = null;
                }
                wpfMap1.Refresh();
            }
        }
        //Switches the map to Spherical Mercator
        private void ToSphericalMercator(RectangleShape currentExtent)
        {
            if (wpfMap1.Overlays.Count > 0)
            {
                wpfMap1.MapUnit = GeographyUnit.Meter;
                wpfMap1.CurrentExtent = currentExtent;
                WorldMapKitWmsWpfOverlay worldMapKitWmsWpfOverlay = (WorldMapKitWmsWpfOverlay)wpfMap1.Overlays["WMK"];
                worldMapKitWmsWpfOverlay.Projection = WorldMapKitProjection.SphericalMercator;
                LayerOverlay dynamicOverlay = (LayerOverlay)wpfMap1.Overlays["DynamicOverlay"];
                //We have to set the projection to Spherical Mercator for the InMemoryFeatureLayers because they are
                //originatly in Decimal Degrees.
                Proj4Projection proj4 = new Proj4Projection();
                proj4.InternalProjectionParametersString = Proj4Projection.GetWgs84ParametersString(); //Decimal Degrees or Geodetic.
                proj4.ExternalProjectionParametersString = Proj4Projection.GetGoogleMapParametersString(); //Spherical Mercator.
                foreach (FeatureLayer featureLayer in dynamicOverlay.Layers)
                {
                    featureLayer.FeatureSource.Projection = proj4;
                }
                wpfMap1.Refresh();
            }
        }
        private void radioBtnDecimalDegrees_Checked(object sender, RoutedEventArgs e)
        {
            ToDecimalDegrees(new RectangleShape(-240.52, 59.04, -104.81, -39.22));
        }
        private void radioBtnSphericalMercator_Checked(object sender, RoutedEventArgs e)
        {
            ToSphericalMercator(new RectangleShape(-26945197,8311113, -11963706, -2158350));
        }
        private void wpfMap1_MouseMove(object sender, MouseEventArgs e)
        {
            if (radioBtnDecimalDegrees.IsChecked == true)
            {
                MouseMoveDecimalDegrees(e);
            }
            else
            {
                MouseMoveSphericalMercator(e);
            }
        }
        private void MouseMoveDecimalDegrees(MouseEventArgs e)
        {
            //Gets the PointShape in world coordinates from screen coordinates.
            Point point = e.MouseDevice.GetPosition(null);
            ScreenPointF screenPointF = new ScreenPointF((float)point.X, (float)point.Y);
            PointShape pointShape = ExtentHelper.ToWorldCoordinate(wpfMap1.CurrentExtent, screenPointF, (float)wpfMap1.Width, (float)wpfMap1.Height);
            //Uses the WrapDatelineProjection to get the proper decimal degree value on the virtual maps to the right and left of the central map.
            WrapDatelineProjection wrapDatelineProjection = new WrapDatelineProjection();
            //Sets the HalfExtentWidth of the wrapdateline overlay we want to apply the projection on.
            //Here it is 180 because, the full extent width is 360.
            wrapDatelineProjection.HalfExtentWidth = wpfMap1.Overlays["WMK"].GetBoundingBox().Width / 2;//180;
            wrapDatelineProjection.Open();
            Vertex projVertex = wrapDatelineProjection.ConvertToExternalProjection(pointShape.X, pointShape.Y);
            wrapDatelineProjection.Close();
            //Shows the real coordinates.
            textBox1.Text = "real X: " + string.Format("{0:0.00}", System.Math.Round(pointShape.X, 2)) +
                         "  real Y: " + string.Format("{0:0.00}", System.Math.Round(pointShape.Y, 2));
            //Shows the decimal degrees after the WrapDatelineProjection
            textBox2.Text = "Decimal Degree X: " + string.Format("{0:0.00}", System.Math.Round(projVertex.X, 2)) +
                         " Decimal Degree Y: " + string.Format("{0:0.00}", System.Math.Round(projVertex.Y, 2));
            //Shows the Decimal Minutes Seconds format after the WrapDatelineProjection
            textBox3.Text = "Long.: " + DecimalDegreesHelper.GetDegreesMinutesSecondsStringFromDecimalDegree(projVertex.X) +
                          "  Lat.: " + DecimalDegreesHelper.GetDegreesMinutesSecondsStringFromDecimalDegree(projVertex.Y);
        }
        private void MouseMoveSphericalMercator(MouseEventArgs e)
        {
            //Gets the PointShape in world coordinates from screen coordinates.
            Point point = e.MouseDevice.GetPosition(null);
            ScreenPointF screenPointF = new ScreenPointF((float)point.X, (float)point.Y);
            PointShape pointShape = ExtentHelper.ToWorldCoordinate(wpfMap1.CurrentExtent, screenPointF, (float)wpfMap1.Width, (float)wpfMap1.Height);
            //Uses the WrapDatelineProjection to get the proper meter value on the virtual maps to the right and left of the central map.
            WrapDatelineProjection wrapDatelineProjection = new WrapDatelineProjection();
            //Sets the HalfExtentWidth of the wrapdateline overlay we want to apply the projection on. (40002730 / 2)
            wrapDatelineProjection.HalfExtentWidth = 40002730.0 / 2;
            wrapDatelineProjection.Open();
            Vertex projVertex = wrapDatelineProjection.ConvertToExternalProjection(pointShape.X, pointShape.Y);
            wrapDatelineProjection.Close();
            //Shows the real meter coordinates.
            textBox1.Text = "real X: " + string.Format("{0:0,0}", System.Math.Round(pointShape.X, 2)) +
                         "  real Y: " + string.Format("{0:0,0}", System.Math.Round(pointShape.Y, 2));
            //Shows the meter after the WrapDatelineProjection
            textBox2.Text = " X: " + string.Format("{0:0,0}", System.Math.Round(projVertex.X, 2)) +
                         " Y: " + string.Format("{0:0,0}", System.Math.Round(projVertex.Y, 2));
            //Shows the Decimal Minutes Seconds format after the WrapDatelineProjection
            Proj4Projection proj4 = new Proj4Projection();
            proj4.InternalProjectionParametersString = Proj4Projection.GetGoogleMapParametersString(); //Spherical Mercator.
            proj4.ExternalProjectionParametersString = Proj4Projection.GetWgs84ParametersString(); //Decimal Degrees or Geodetic.
            proj4.Open();
            Vertex decimalDegreeVertex = proj4.ConvertToExternalProjection(projVertex.X,projVertex.Y);
            proj4.Close();
            textBox3.Text = "Long.: " + DecimalDegreesHelper.GetDegreesMinutesSecondsStringFromDecimalDegree(decimalDegreeVertex.X) +
                          "  Lat.: " + DecimalDegreesHelper.GetDegreesMinutesSecondsStringFromDecimalDegree(decimalDegreeVertex.Y);
        }
    }
}

WrapDatelineProjection.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ThinkGeo.MapSuite.Core;
namespace WrapDatelineMode
{
    class WrapDatelineProjection : Projection, IDisposable
    {
        private double nHalfExtentWidth;
        private double [] an = new double[100];
        private double[] an_minus = new double[100];
        //Property for half the extent of the central map.
        //For example:
        //If the map is in decimal degree, the value will be 180 (worldMapKitWmsWpfOverlay.GetBoundingBox().Width / 2).
        //If the map is using Google map, the value will be 14000955.5 (googleMapsOverlay.GetBoundingBox().Width / 2)
        public double HalfExtentWidth
        {
            get { return nHalfExtentWidth; }
            set
            {
                nHalfExtentWidth = value;
                double sum = 0;
                for (int i = 0; i <= an.Length - 1; i += 1)
                {
                    an[i] = nHalfExtentWidth + sum;
                    sum = sum + (nHalfExtentWidth * 2);
                }
                sum = 0;
                for (int i = 0; i <= an_minus.Length - 1; i += 1)
                {
                    an_minus[i] = -nHalfExtentWidth - sum;
                    sum = sum + (nHalfExtentWidth * 2);
                }
            }
        }
        protected override Vertex[] ConvertToExternalProjectionCore(double[] x, double[] y)
        {
            Vertex[] vertices = new Vertex[x.Length];
            for (int i = 0; i < vertices.Length; i++)
            {
                if ((x[i] > HalfExtentWidth)|| (x[i] < (-HalfExtentWidth)))
                {
                double realx = GetAp(x[i]);
                vertices[i] = new Vertex(realx, y[i]);
                }
                else
                {
                    vertices[i] = new Vertex(x[i], y[i]);
                }
            }
            return vertices;
        }
        private double GetAp(double Xp)
        {
            double result = 0;
            if (Xp > 0)
            {
                for (int i = 0; i < an.Length - 2; i++)
                {
                    if ((Xp >= an[i]) && (Xp < an[i|+ 1]))
                    {
                        result = Xp - (an[i] + HalfExtentWidth);
                        break;
                    }
                }
            }
            else
            {
                for (int i = 0; i < an_minus.Length - 2; i++)
                {
                    if ((Xp <= an_minus[i]) && (Xp > an_minus[i|+ 1]))
                    {
                        result = Xp + (an[i] + HalfExtentWidth);
                        break;
                    }
                }
            }
            return result;
        }
        protected override Vertex[] ConvertToInternalProjectionCore(double[] x, double[] y)
        {
            throw new NotImplementedException();
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        private void Dispose(bool disposing)
        {
            Close();
        }
    }
}