====== 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();
}
}
}