Version 2.1.0:

- TileImageLoader with local file caching in WinRT
- Location implements IEquatable
- Removed Surface sample application
This commit is contained in:
ClemensF 2014-07-09 21:27:28 +02:00
parent 10527c3f0d
commit 4e0253aa70
38 changed files with 493 additions and 393 deletions

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.0.0")]
[assembly: AssemblyFileVersion("2.0.0")]
[assembly: AssemblyVersion("2.1.0")]
[assembly: AssemblyFileVersion("2.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.0.0")]
[assembly: AssemblyFileVersion("2.0.0")]
[assembly: AssemblyVersion("2.1.0")]
[assembly: AssemblyFileVersion("2.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -38,16 +38,15 @@ namespace MapControl
public static void DrawGlyphRun(this DrawingContext drawingContext, Brush foreground, GlyphRun glyphRun,
Point position, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment)
{
var bbox = glyphRun.ComputeInkBoundingBox();
var transform = new TranslateTransform(position.X - bbox.X, position.Y - bbox.Y);
var boundingBox = glyphRun.ComputeInkBoundingBox();
switch (horizontalAlignment)
{
case HorizontalAlignment.Center:
transform.X -= bbox.Width / 2d;
position.X -= boundingBox.Width / 2d;
break;
case HorizontalAlignment.Right:
transform.X -= bbox.Width;
position.X -= boundingBox.Width;
break;
default:
break;
@ -56,16 +55,16 @@ namespace MapControl
switch (verticalAlignment)
{
case VerticalAlignment.Center:
transform.Y -= bbox.Height / 2d;
position.Y -= boundingBox.Height / 2d;
break;
case VerticalAlignment.Bottom:
transform.Y -= bbox.Height;
position.Y -= boundingBox.Height;
break;
default:
break;
}
drawingContext.PushTransform(transform);
drawingContext.PushTransform(new TranslateTransform(position.X - boundingBox.X, position.Y - boundingBox.Y));
drawingContext.DrawGlyphRun(foreground, glyphRun);
drawingContext.Pop();
}

View file

@ -0,0 +1,14 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2014 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System.Threading.Tasks;
namespace MapControl
{
public interface IObjectCache
{
Task<object> GetAsync(string key);
Task SetAsync(string key, object value);
}
}

View file

@ -0,0 +1,62 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2014 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
namespace MapControl
{
public class ImageFileCache : IObjectCache
{
private readonly IStorageFolder rootFolder;
public ImageFileCache()
{
rootFolder = ApplicationData.Current.TemporaryFolder;
}
public ImageFileCache(IStorageFolder folder)
{
rootFolder = folder;
}
public async Task<object> GetAsync(string key)
{
try
{
return await PathIO.ReadBufferAsync(Path.Combine(rootFolder.Path, key));
}
catch
{
return null;
}
}
public async Task SetAsync(string key, object value)
{
try
{
var buffer = (IBuffer)value;
var names = key.Split('\\');
var folder = rootFolder;
for (int i = 0; i < names.Length - 1; i++)
{
folder = await folder.CreateFolderAsync(names[i], CreationCollisionOption.OpenIfExists);
}
var file = await folder.CreateFileAsync(names[names.Length - 1], CreationCollisionOption.ReplaceExisting);
await FileIO.WriteBufferAsync(file, buffer);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
}
}

View file

@ -10,7 +10,7 @@ namespace MapControl
/// <summary>
/// A geographic location with latitude and longitude values in degrees.
/// </summary>
public partial class Location
public partial class Location : IEquatable<Location>
{
private double latitude;
private double longitude;
@ -37,6 +37,23 @@ namespace MapControl
set { longitude = value; }
}
public bool Equals(Location location)
{
return location != null
&& location.latitude == latitude
&& location.longitude == longitude;
}
public override bool Equals(object obj)
{
return Equals(obj as Location);
}
public override int GetHashCode()
{
return latitude.GetHashCode() ^ longitude.GetHashCode();
}
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "{0:F5},{1:F5}", latitude, longitude);

View file

@ -579,7 +579,7 @@ namespace MapControl
{
AdjustCenterProperty(TargetCenterProperty, ref targetCenter);
if (targetCenter.Latitude != Center.Latitude || targetCenter.Longitude != Center.Longitude)
if (!targetCenter.Equals(Center))
{
if (centerAnimation != null)
{

View file

@ -106,7 +106,7 @@
<Compile Include="Tile.Silverlight.WinRT.cs" />
<Compile Include="TileContainer.cs" />
<Compile Include="TileContainer.Silverlight.WinRT.cs" />
<Compile Include="TileImageLoader.Silverlight.WinRT.cs" />
<Compile Include="TileImageLoader.Silverlight.cs" />
<Compile Include="TileLayer.cs" />
<Compile Include="TileLayerCollection.cs" />
<Compile Include="TileSource.cs" />

View file

@ -3,10 +3,10 @@
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Collections.Generic;
using System.Linq;
#if WINDOWS_RUNTIME
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
@ -31,7 +31,7 @@ namespace MapControl
public MapGraticule()
{
IsHitTestVisible = false;
StrokeThickness = 0.5;
Stroke = new SolidColorBrush(Color.FromArgb(127, 0, 0, 0));
path = new Path
{
@ -55,7 +55,6 @@ namespace MapControl
protected override void OnViewportChanged()
{
var geometry = (PathGeometry)path.Data;
var bounds = ParentMap.ViewportTransform.Inverse.TransformBounds(new Rect(new Point(), ParentMap.RenderSize));
var start = ParentMap.MapTransform.Transform(new Point(bounds.X, bounds.Y));
var end = ParentMap.MapTransform.Transform(new Point(bounds.X + bounds.Width, bounds.Y + bounds.Height));
@ -88,28 +87,22 @@ namespace MapControl
graticuleStart = lineStart;
graticuleEnd = lineEnd;
var geometry = (PathGeometry)path.Data;
geometry.Figures.Clear();
geometry.Transform = ParentMap.ViewportTransform;
var latLocations = new List<Location>((int)((end.Latitude - labelStart.Latitude) / spacing) + 1);
for (var lat = labelStart.Latitude; lat <= end.Latitude; lat += spacing)
{
var location = new Location(lat, lineStart.Longitude);
latLocations.Add(location);
var figure = new PathFigure
{
StartPoint = ParentMap.MapTransform.Transform(location),
StartPoint = ParentMap.MapTransform.Transform(new Location(lat, lineStart.Longitude)),
IsClosed = false,
IsFilled = false
};
location.Longitude = lineEnd.Longitude;
figure.Segments.Add(new LineSegment
{
Point = ParentMap.MapTransform.Transform(location),
Point = ParentMap.MapTransform.Transform(new Location(lat, lineEnd.Longitude)),
});
geometry.Figures.Add(figure);
@ -134,14 +127,11 @@ namespace MapControl
var childIndex = 1; // 0 for Path
var format = spacing < 1d ? "{0} {1}°{2:00}'" : "{0} {1}°";
var measureSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
foreach (var location in latLocations)
for (var lat = labelStart.Latitude; lat <= end.Latitude; lat += spacing)
{
for (var lon = labelStart.Longitude; lon <= end.Longitude; lon += spacing)
{
location.Longitude = lon;
TextBlock label;
if (childIndex < Children.Count)
@ -150,9 +140,14 @@ namespace MapControl
}
else
{
var renderTransform = new TransformGroup();
renderTransform.Children.Add(new TranslateTransform());
renderTransform.Children.Add(ParentMap.RotateTransform);
renderTransform.Children.Add(new TranslateTransform());
label = new TextBlock
{
RenderTransform = new TransformGroup()
RenderTransform = renderTransform
};
label.SetBinding(TextBlock.ForegroundProperty, new Binding
@ -175,30 +170,13 @@ namespace MapControl
label.FontStyle = FontStyle;
label.FontStretch = FontStretch;
label.FontWeight = FontWeight;
label.Text = string.Format("{0}\n{1}", CoordinateString(lat, format, "NS"), CoordinateString(Location.NormalizeLongitude(lon), format, "EW"));
label.Tag = new Location(lat, lon);
label.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
label.Text = string.Format("{0}\n{1}",
CoordinateString(location.Latitude, format, "NS"),
CoordinateString(Location.NormalizeLongitude(location.Longitude), format, "EW"));
label.Measure(measureSize);
var transformGroup = (TransformGroup)label.RenderTransform;
if (transformGroup.Children.Count == 0)
{
transformGroup.Children.Add(new TranslateTransform());
transformGroup.Children.Add(ParentMap.RotateTransform);
transformGroup.Children.Add(new TranslateTransform());
}
var translateTransform = (TranslateTransform)transformGroup.Children[0];
var translateTransform = (TranslateTransform)((TransformGroup)label.RenderTransform).Children[0];
translateTransform.X = StrokeThickness / 2d + 2d;
translateTransform.Y = -label.DesiredSize.Height / 2d;
var viewportPosition = ParentMap.LocationToViewportPoint(location);
translateTransform = (TranslateTransform)transformGroup.Children[2];
translateTransform.X = viewportPosition.X;
translateTransform.Y = viewportPosition.Y;
}
}
@ -208,6 +186,18 @@ namespace MapControl
}
}
// don't use MapPanel.Location because labels may be at more than 180° distance from map center
for (int i = 1; i < Children.Count; i++)
{
var label = (TextBlock)Children[i];
var location = (Location)label.Tag;
var viewportTransform = (TranslateTransform)((TransformGroup)label.RenderTransform).Children[2];
var viewportPosition = ParentMap.LocationToViewportPoint(location);
viewportTransform.X = viewportPosition.X;
viewportTransform.Y = viewportPosition.Y;
}
base.OnViewportChanged();
}
}

View file

@ -2,6 +2,7 @@
// Copyright © 2014 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
#if WINDOWS_RUNTIME
using Windows.UI.Xaml;
#else
@ -43,7 +44,7 @@ namespace MapControl
hemisphere = hemispheres[1];
}
var minutes = (int)(value * 60d + 0.5);
var minutes = (int)Math.Round(value * 60d);
return string.Format(format, hemisphere, minutes / 60, (double)(minutes % 60));
}

View file

@ -14,8 +14,8 @@ using System.Windows;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.0.0")]
[assembly: AssemblyFileVersion("2.0.0")]
[assembly: AssemblyVersion("2.1.0")]
[assembly: AssemblyFileVersion("2.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -13,12 +13,6 @@ namespace MapControl
{
internal partial class TileContainer
{
private Matrix GetViewportTransformMatrix(double scale, double offsetX, double offsetY)
{
return new Matrix(scale, 0d, 0d, -scale, offsetX, offsetY)
.RotateAt(rotation, viewportOrigin.X, viewportOrigin.Y);
}
private Matrix GetTileIndexMatrix(int numTiles)
{
var scale = (double)numTiles / 360d;
@ -29,6 +23,13 @@ namespace MapControl
.Scale(scale, -scale); // map coordinates to tile indices
}
private void UpdateViewportTransform(double scale, double offsetX, double offsetY)
{
ViewportTransform.Matrix =
new Matrix(scale, 0d, 0d, -scale, offsetX, offsetY)
.RotateAt(rotation, viewportOrigin.X, viewportOrigin.Y);
}
/// <summary>
/// Sets a RenderTransform with origin at tileGrid.X and tileGrid.Y to minimize rounding errors.
/// </summary>

View file

@ -9,14 +9,6 @@ namespace MapControl
{
internal partial class TileContainer
{
private Matrix GetViewportTransformMatrix(double scale, double offsetX, double offsetY)
{
var transform = new Matrix(scale, 0d, 0d, -scale, offsetX, offsetY);
transform.RotateAt(rotation, viewportOrigin.X, viewportOrigin.Y);
return transform;
}
private Matrix GetTileIndexMatrix(int numTiles)
{
var scale = (double)numTiles / 360d;
@ -28,6 +20,14 @@ namespace MapControl
return transform;
}
private void UpdateViewportTransform(double scale, double offsetX, double offsetY)
{
var transform = new Matrix(scale, 0d, 0d, -scale, offsetX, offsetY);
transform.RotateAt(rotation, viewportOrigin.X, viewportOrigin.Y);
ViewportTransform.Matrix = transform;
}
/// <summary>
/// Sets a RenderTransform with origin at tileGrid.X and tileGrid.Y to minimize rounding errors.
/// </summary>

View file

@ -22,7 +22,7 @@ namespace MapControl
// relative scaled tile size ranges from 0.75 to 1.5 (192 to 384 pixels)
private static double zoomLevelSwitchDelta = -Math.Log(0.75, 2d);
internal static TimeSpan UpdateInterval = TimeSpan.FromSeconds(0.5);
public static TimeSpan UpdateInterval = TimeSpan.FromSeconds(0.5);
private readonly DispatcherTimer updateTimer;
private Size viewportSize;
@ -102,7 +102,7 @@ namespace MapControl
var transformOffsetX = viewportOrigin.X - mapOrigin.X * scale;
var transformOffsetY = viewportOrigin.Y + mapOrigin.Y * scale;
ViewportTransform.Matrix = GetViewportTransformMatrix(scale, transformOffsetX, transformOffsetY);
UpdateViewportTransform(scale, transformOffsetX, transformOffsetY);
tileLayerOffset.X = transformOffsetX - 180d * scale;
tileLayerOffset.Y = transformOffsetY - 180d * scale;

View file

@ -1,64 +0,0 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2014 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Collections.Generic;
using System.Diagnostics;
#if WINDOWS_RUNTIME
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
#else
using System.Windows.Media;
using System.Windows.Media.Imaging;
#endif
namespace MapControl
{
/// <summary>
/// Loads map tile images.
/// </summary>
internal class TileImageLoader
{
internal void BeginGetTiles(TileLayer tileLayer, IEnumerable<Tile> tiles)
{
var imageTileSource = tileLayer.TileSource as ImageTileSource;
if (imageTileSource != null)
{
foreach (var tile in tiles)
{
try
{
var image = imageTileSource.LoadImage(tile.XIndex, tile.Y, tile.ZoomLevel);
tile.SetImageSource(image, tileLayer.AnimateTileOpacity);
}
catch (Exception ex)
{
Debug.WriteLine("Loading tile image failed: {0}", ex.Message);
}
}
}
else
{
foreach (var tile in tiles)
{
try
{
var uri = tileLayer.TileSource.GetUri(tile.XIndex, tile.Y, tile.ZoomLevel);
var image = uri != null ? new BitmapImage(uri) : null;
tile.SetImageSource(image, tileLayer.AnimateTileOpacity);
}
catch (Exception ex)
{
Debug.WriteLine("Creating tile image failed: {0}", ex.Message);
}
}
}
}
public void CancelGetTiles()
{
}
}
}

View file

@ -0,0 +1,55 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2014 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace MapControl
{
/// <summary>
/// Loads map tile images.
/// </summary>
internal class TileImageLoader
{
internal void BeginGetTiles(TileLayer tileLayer, IEnumerable<Tile> tiles)
{
var imageTileSource = tileLayer.TileSource as ImageTileSource;
foreach (var tile in tiles)
{
try
{
ImageSource image = null;
if (imageTileSource != null)
{
image = imageTileSource.LoadImage(tile.XIndex, tile.Y, tile.ZoomLevel);
}
else
{
var uri = tileLayer.TileSource.GetUri(tile.XIndex, tile.Y, tile.ZoomLevel);
if (uri != null)
{
image = new BitmapImage(uri);
}
}
tile.SetImageSource(image, tileLayer.AnimateTileOpacity);
}
catch (Exception ex)
{
Debug.WriteLine("Loading tile image failed: {0}", ex.Message);
}
}
}
internal void CancelGetTiles()
{
}
}
}

View file

@ -0,0 +1,196 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2014 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Storage.Streams;
using Windows.UI.Core;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.Web.Http;
using Windows.Web.Http.Filters;
namespace MapControl
{
/// <summary>
/// Loads map tile images.
/// </summary>
public class TileImageLoader
{
public static IObjectCache Cache { get; set; }
private HttpClient httpClient;
internal void BeginGetTiles(TileLayer tileLayer, IEnumerable<Tile> tiles)
{
var imageTileSource = tileLayer.TileSource as ImageTileSource;
foreach (var tile in tiles)
{
try
{
ImageSource image = null;
if (imageTileSource != null)
{
image = imageTileSource.LoadImage(tile.XIndex, tile.Y, tile.ZoomLevel);
}
else
{
var uri = tileLayer.TileSource.GetUri(tile.XIndex, tile.Y, tile.ZoomLevel);
if (uri != null)
{
if (Cache == null || string.IsNullOrEmpty(tileLayer.SourceName))
{
image = new BitmapImage(uri);
}
else
{
var bitmap = new BitmapImage();
image = bitmap;
Task.Run(async () => await LoadCachedImage(tileLayer, tile, uri, bitmap));
}
}
}
tile.SetImageSource(image, tileLayer.AnimateTileOpacity);
}
catch (Exception ex)
{
Debug.WriteLine("Loading tile image failed: {0}", ex.Message);
}
}
}
internal void CancelGetTiles()
{
}
private async Task LoadCachedImage(TileLayer tileLayer, Tile tile, Uri uri, BitmapImage bitmap)
{
var cacheKey = string.Format(@"{0}\{1}\{2}\{3}{4}",
tileLayer.SourceName, tile.ZoomLevel, tile.XIndex, tile.Y, Path.GetExtension(uri.LocalPath));
var buffer = await Cache.GetAsync(cacheKey) as IBuffer;
if (buffer != null)
{
await LoadImageFromBuffer(buffer, bitmap);
//Debug.WriteLine("Loaded cached image {0}", cacheKey);
}
else
{
DownloadAndCacheImage(uri, bitmap, cacheKey);
}
}
private async Task LoadImageFromBuffer(IBuffer buffer, BitmapImage bitmap)
{
using (var stream = new InMemoryRandomAccessStream())
{
await stream.WriteAsync(buffer);
await stream.FlushAsync();
stream.Seek(0);
await bitmap.Dispatcher.RunAsync(CoreDispatcherPriority.Low, async () =>
{
try
{
await bitmap.SetSourceAsync(stream);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
});
}
}
private void DownloadAndCacheImage(Uri uri, BitmapImage bitmap, string cacheKey)
{
try
{
if (httpClient == null)
{
var filter = new HttpBaseProtocolFilter();
filter.AllowAutoRedirect = false;
filter.CacheControl.ReadBehavior = HttpCacheReadBehavior.Default;
filter.CacheControl.WriteBehavior = HttpCacheWriteBehavior.NoCache;
httpClient = new HttpClient(filter);
}
httpClient.GetAsync(uri).Completed = async (request, status) =>
{
if (status == AsyncStatus.Completed)
{
using (var response = request.GetResults())
{
await LoadImageFromHttpResponse(response, bitmap, cacheKey);
}
}
else
{
Debug.WriteLine("{0}: {1}", uri, request.ErrorCode != null ? request.ErrorCode.Message : status.ToString());
}
};
}
catch (Exception ex)
{
Debug.WriteLine("{0}: {1}", uri, ex.Message);
}
}
private async Task LoadImageFromHttpResponse(HttpResponseMessage response, BitmapImage bitmap, string cacheKey)
{
if (response.IsSuccessStatusCode)
{
var stream = new InMemoryRandomAccessStream();
using (var content = response.Content)
{
await content.WriteToStreamAsync(stream);
}
await stream.FlushAsync();
stream.Seek(0);
await bitmap.Dispatcher.RunAsync(CoreDispatcherPriority.Low, async () =>
{
try
{
await bitmap.SetSourceAsync(stream);
// cache image asynchronously, after successful decoding
var task = Task.Run(async () =>
{
var buffer = new Windows.Storage.Streams.Buffer((uint)stream.Size);
stream.Seek(0);
await stream.ReadAsync(buffer, buffer.Capacity, InputStreamOptions.None);
stream.Dispose();
await Cache.SetAsync(cacheKey, buffer);
});
}
catch (Exception ex)
{
Debug.WriteLine("{0}: {1}", response.RequestMessage.RequestUri, ex.Message);
stream.Dispose();
}
});
}
else
{
Debug.WriteLine("{0}: {1}", response.RequestMessage.RequestUri, response.StatusCode);
}
}
}
}

View file

@ -42,6 +42,9 @@
<Compile Include="..\Extensions.WinRT.cs">
<Link>Extensions.WinRT.cs</Link>
</Compile>
<Compile Include="..\ImageFileCache.WinRT.cs">
<Link>ImageFileCache.WinRT.cs</Link>
</Compile>
<Compile Include="..\ImageTileSource.Silverlight.WinRT.cs">
<Link>ImageTileSource.Silverlight.WinRT.cs</Link>
</Compile>
@ -51,6 +54,9 @@
<Compile Include="..\Int32Rect.cs">
<Link>Int32Rect.cs</Link>
</Compile>
<Compile Include="..\IObjectCache.WinRT.cs">
<Link>IObjectCache.WinRT.cs</Link>
</Compile>
<Compile Include="..\Location.cs">
<Link>Location.cs</Link>
</Compile>
@ -138,8 +144,8 @@
<Compile Include="..\TileContainer.Silverlight.WinRT.cs">
<Link>TileContainer.Silverlight.WinRT.cs</Link>
</Compile>
<Compile Include="..\TileImageLoader.Silverlight.WinRT.cs">
<Link>TileImageLoader.Silverlight.WinRT.cs</Link>
<Compile Include="..\TileImageLoader.WinRT.cs">
<Link>TileImageLoader.WinRT.cs</Link>
</Compile>
<Compile Include="..\TileLayer.cs">
<Link>TileLayer.cs</Link>

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.0.0")]
[assembly: AssemblyFileVersion("2.0.0")]
[assembly: AssemblyVersion("2.1.0")]
[assembly: AssemblyFileVersion("2.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -35,7 +35,7 @@
<local:ObjectReferenceConverter x:Key="ObjectReferenceConverter"/>
</Page.Resources>
<Grid>
<map:MapBase x:Name="map" ZoomLevel="11"
<map:MapBase x:Name="map" ZoomLevel="11" MinZoomLevel="2"
ManipulationMode="Scale,TranslateX,TranslateY,TranslateInertia"
ManipulationStarted="MapManipulationStarted"
ManipulationCompleted="MapManipulationCompleted"

View file

@ -14,7 +14,13 @@ namespace PhoneApplication
public MainPage()
{
TileImageLoader.Cache = new ImageFileCache();
InitializeComponent();
var tileLayers = (TileLayerCollection)Resources["TileLayers"];
map.TileLayer = tileLayers[0];
DataContext = new ViewModel(Dispatcher);
NavigationCacheMode = NavigationCacheMode.Required;
}

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.0.0")]
[assembly: AssemblyFileVersion("2.0.0")]
[assembly: AssemblyVersion("2.1.0")]
[assembly: AssemblyFileVersion("2.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: ComVisible(false)]

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.0.0")]
[assembly: AssemblyFileVersion("2.0.0")]
[assembly: AssemblyVersion("2.1.0")]
[assembly: AssemblyFileVersion("2.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -1,4 +1,5 @@
using System.Globalization;
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
@ -22,14 +23,27 @@ namespace SilverlightApplication
private void MapMouseMove(object sender, MouseEventArgs e)
{
var location = map.ViewportPointToLocation(e.GetPosition(map));
var longitude = Location.NormalizeLongitude(location.Longitude);
var latString = location.Latitude < 0 ?
string.Format(CultureInfo.InvariantCulture, "S {0:00.00000}", -location.Latitude) :
string.Format(CultureInfo.InvariantCulture, "N {0:00.00000}", location.Latitude);
var lonString = longitude < 0 ?
string.Format(CultureInfo.InvariantCulture, "W {0:000.00000}", -longitude) :
string.Format(CultureInfo.InvariantCulture, "E {0:000.00000}", longitude);
mouseLocation.Text = latString + "\n" + lonString;
var latitude = (int)Math.Round(location.Latitude * 60000d);
var longitude = (int)Math.Round(Location.NormalizeLongitude(location.Longitude) * 60000d);
var latHemisphere = 'N';
var lonHemisphere = 'E';
if (latitude < 0)
{
latitude = -latitude;
latHemisphere = 'S';
}
if (longitude < 0)
{
longitude = -longitude;
lonHemisphere = 'W';
}
mouseLocation.Text = string.Format(CultureInfo.InvariantCulture,
"{0} {1:00} {2:00.000}\n{3} {4:000} {5:00.000}",
latHemisphere, latitude / 60000, (double)(latitude % 60000) / 1000d,
lonHemisphere, longitude / 60000, (double)(longitude % 60000) / 1000d);
}
private void TileLayerSelectionChanged(object sender, SelectionChangedEventArgs e)

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.0.0")]
[assembly: AssemblyFileVersion("2.0.0")]
[assembly: AssemblyVersion("2.1.0")]
[assembly: AssemblyFileVersion("2.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -22,6 +22,12 @@
<map:TileLayer SourceName="MapQuest OSM" Description="MapQuest OSM - © {y} MapQuest &amp; OpenStreetMap Contributors">
<map:TileSource UriFormat="http://otile{n}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png"/>
</map:TileLayer>
<map:TileLayer SourceName="Bing Maps" Description="Bing Maps - © {y} Microsoft Corporation" MinZoomLevel="1" MaxZoomLevel="19">
<map:TileSource UriFormat="http://ecn.t{i}.tiles.virtualearth.net/tiles/r{q}.png?g=0&amp;stl=h"/>
</map:TileLayer>
<map:TileLayer SourceName="Bing Images" Description="Bing Maps - © {y} Microsoft Corporation" MinZoomLevel="1" MaxZoomLevel="19" Background="#FF3F3F3F" Foreground="White">
<map:TileSource UriFormat="http://ecn.t{i}.tiles.virtualearth.net/tiles/a{q}.jpeg?g=0"/>
</map:TileLayer>
<map:TileLayer SourceName="Seamarks" Description="© {y} OpenSeaMap Contributors, CC-BY-SA" MinZoomLevel="10" MaxZoomLevel="18">
<map:TileSource UriFormat="http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png"/>
</map:TileLayer>
@ -124,7 +130,7 @@
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<map:Map x:Name="map" MinZoomLevel="2" Center="{Binding MapCenter}" MaxZoomLevel="18" ZoomLevel="11" Foreground="Black">
<map:Map x:Name="map" Center="{Binding MapCenter}" MinZoomLevel="2" MaxZoomLevel="18" ZoomLevel="11" Foreground="Black">
<map:MapImage x:Name="mapImage" South="53.54031" North="53.74871" West="8.08594" East="8.43750"
Source="10_535_330.jpg" Opacity="0.5"/>
<map:MapGraticule Opacity="0.6"/>
@ -190,6 +196,8 @@
<ComboBoxItem>OCM Transport</ComboBoxItem>
<ComboBoxItem>OCM Landscape</ComboBoxItem>
<ComboBoxItem>MapQuest OSM</ComboBoxItem>
<ComboBoxItem>Bing Maps</ComboBoxItem>
<ComboBoxItem>Bing Images</ComboBoxItem>
</ComboBox>
</StackPanel>
</Grid>

View file

@ -1,4 +1,5 @@
using MapControl;
using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
@ -9,7 +10,12 @@ namespace StoreApplication
{
public MainPage()
{
TileImageLoader.Cache = new ImageFileCache();
this.InitializeComponent();
var tileLayers = (TileLayerCollection)Resources["TileLayers"];
map.TileLayer = tileLayers[0];
}
private void ImageOpacitySliderValueChanged(object sender, RangeBaseValueChangedEventArgs e)

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.0.0")]
[assembly: AssemblyFileVersion("2.0.0")]
[assembly: AssemblyVersion("2.1.0")]
[assembly: AssemblyFileVersion("2.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -1,3 +0,0 @@
<?xml version="1.0"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>

View file

@ -1,12 +0,0 @@
<Application x:Class="SurfaceApplication.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Microsoft.Surface.Presentation.Generic;v2.0.0.0;31bf3856ad364e35;component/themes\styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

View file

@ -1,8 +0,0 @@
using System.Windows;
namespace SurfaceApplication
{
public partial class App : Application
{
}
}

View file

@ -1,12 +0,0 @@
<s:SurfaceWindow x:Class="SurfaceApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://schemas.microsoft.com/surface/2008"
xmlns:m="clr-namespace:MapControl;assembly=MapControl.WPF"
Title="SurfaceApplication" WindowStyle="None" WindowState="Maximized">
<Grid>
<m:Map Center="53.5,8.2" ZoomLevel="11" TouchDown="MapTouchDown">
<m:MapGraticule Opacity="0.5" MinLineSpacing="200"/>
</m:Map>
</Grid>
</s:SurfaceWindow>

View file

@ -1,28 +0,0 @@
using System.Windows.Input;
using Microsoft.Surface;
using Microsoft.Surface.Presentation.Controls;
using Microsoft.Surface.Presentation.Input;
namespace SurfaceApplication
{
public partial class MainWindow : SurfaceWindow
{
public MainWindow()
{
InitializeComponent();
}
private void MapTouchDown(object sender, TouchEventArgs e)
{
if (SurfaceEnvironment.IsSurfaceEnvironmentAvailable &&
!e.Device.GetIsFingerRecognized())
{
// If touch event is from a blob or tag, prevent touch capture by setting
// TouchEventArgs.Handled = true. Hence no manipulation will be started.
// See http://msdn.microsoft.com/en-us/library/ms754010#touch_and_manipulation
e.Handled = true;
}
}
}
}

View file

@ -1,15 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("Surface Sample Application")]
[assembly: AssemblyDescription("XAML Map Control Sample Application for PixelSense (Surface 2)")]
[assembly: AssemblyProduct("XAML Map Control")]
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.0.0")]
[assembly: AssemblyFileVersion("2.0.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -1,97 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{6285FB9D-B7EA-469A-B464-224077967167}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SurfaceApplication</RootNamespace>
<AssemblyName>SurfaceApplication</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="Microsoft.Surface" />
<Reference Include="Microsoft.Surface.Presentation" />
<Reference Include="Microsoft.Surface.Presentation.Generic" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<None Include="App.config" />
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<Content Include="SurfaceApplication.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<ProjectReference Include="..\..\MapControl\MapControl.WPF.csproj">
<Project>{226f3575-b683-446d-a2f0-181291dc8787}</Project>
<Name>MapControl.WPF</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains the information needed to install your application
with the Surface Shell. Please refer to the documentation for deployment
instructions.
-->
<ss:ApplicationInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ss="http://schemas.microsoft.com/Surface/2007/ApplicationMetadata">
<Application>
<Title>SurfaceApplication</Title>
<Description>SurfaceApplication</Description>
<ExecutableFile>SurfaceApplication.exe</ExecutableFile>
<Arguments>
</Arguments>
<IconImageFile>Resources\icon.png</IconImageFile>
<Tags>
<!--
If your application uses tagged objects, please uncomment this section to register the tags with the Shell.
You can register Tags by using the appropriate instructions below.
-->
<!--
To register a specific value Tag:
1. Please uncomment the Tag Element below.
2. Replace "C0" below with the value of your Tag (in hexadecimal format). Repeat this section (this element and its children) for other Tags
3. Please remove the Launch element if you do not want to register the tag with Object Routing.
-->
<!--
<Tag Value="0xC0">
<Actions>
<Launch />
</Actions>
</Tag>
-->
<!--
To register all Tags in a series:
1. Please uncomment the Tag Element below.
2. Replace "0000000000000000" below with the series of your Tag (in hexadecimal format). Repeat this section (this element and its children) for other Tags
3. Please remove the Launch element if you do not want to register the tag with Object Routing.
-->
<!--
<Tag Series="0x0000000000000000">
<Actions>
<Launch />
</Actions>
</Tag>
-->
</Tags>
</Application>
</ss:ApplicationInfo>

View file

@ -2,7 +2,6 @@
using System.Globalization;
using System.Runtime.Caching;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Caching;
using MapControl;
@ -56,14 +55,27 @@ namespace WpfApplication
private void MapMouseMove(object sender, MouseEventArgs e)
{
var location = map.ViewportPointToLocation(e.GetPosition(map));
var longitude = Location.NormalizeLongitude(location.Longitude);
var latString = location.Latitude < 0 ?
string.Format(CultureInfo.InvariantCulture, "S {0:00.00000}", -location.Latitude) :
string.Format(CultureInfo.InvariantCulture, "N {0:00.00000}", location.Latitude);
var lonString = longitude < 0 ?
string.Format(CultureInfo.InvariantCulture, "W {0:000.00000}", -longitude) :
string.Format(CultureInfo.InvariantCulture, "E {0:000.00000}", longitude);
mouseLocation.Text = latString + "\n" + lonString;
var latitude = (int)Math.Round(location.Latitude * 60000d);
var longitude = (int)Math.Round(Location.NormalizeLongitude(location.Longitude) * 60000d);
var latHemisphere = 'N';
var lonHemisphere = 'E';
if (latitude < 0)
{
latitude = -latitude;
latHemisphere = 'S';
}
if (longitude < 0)
{
longitude = -longitude;
lonHemisphere = 'W';
}
mouseLocation.Text = string.Format(CultureInfo.InvariantCulture,
"{0} {1:00} {2:00.000}\n{3} {4:000} {5:00.000}",
latHemisphere, latitude / 60000, (double)(latitude % 60000) / 1000d,
lonHemisphere, longitude / 60000, (double)(longitude % 60000) / 1000d);
}
private void MapManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.0.0")]
[assembly: AssemblyFileVersion("2.0.0")]
[assembly: AssemblyVersion("2.1.0")]
[assembly: AssemblyFileVersion("2.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]