====== 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 { /// /// Interaction logic for App.xaml /// 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 { /// /// Interaction logic for TestWindow.xaml /// 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(); } } }