Some cleanup.

This commit is contained in:
ClemensF 2012-08-08 20:42:06 +02:00
parent 65a0d8d51a
commit be3144af07
8 changed files with 217 additions and 236 deletions

View file

@ -3,6 +3,8 @@
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Collections.Specialized;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
@ -41,7 +43,7 @@ namespace MapControl
public static readonly DependencyProperty TileLayersProperty = DependencyProperty.Register(
"TileLayers", typeof(TileLayerCollection), typeof(Map), new FrameworkPropertyMetadata(
(o, e) => ((Map)o).TileLayersPropertyChanged((TileLayerCollection)e.NewValue),
(o, e) => ((Map)o).TileLayersPropertyChanged((TileLayerCollection)e.OldValue, (TileLayerCollection)e.NewValue),
(o, v) => ((Map)o).CoerceTileLayersProperty((TileLayerCollection)v)));
public static readonly DependencyProperty MainTileLayerProperty = DependencyProperty.Register(
@ -122,14 +124,9 @@ namespace MapControl
}
/// <summary>
/// Raised when the ViewTransform property has changed.
/// Raised when the current viewport has changed.
/// </summary>
public event EventHandler ViewTransformChanged;
/// <summary>
/// Raised when the TileLayers property has changed.
/// </summary>
public event EventHandler TileLayersChanged;
public event Action ViewportChanged;
public double MinZoomLevel { get; set; }
public double MaxZoomLevel { get; set; }
@ -258,7 +255,7 @@ namespace MapControl
}
/// <summary>
/// Gets or sets the map rotation angle in degrees.
/// Gets or sets the map heading, or clockwise rotation angle in degrees.
/// </summary>
public double Heading
{
@ -381,7 +378,7 @@ namespace MapControl
if (transformOrigin != null)
{
viewportOrigin += translation;
UpdateViewTransform();
UpdateTransform();
}
else
{
@ -404,7 +401,7 @@ namespace MapControl
Heading = (((Heading + rotation) % 360d) + 360d) % 360d;
ZoomLevel += Math.Log(scale, 2d);
updateTransform = true;
UpdateViewTransform();
UpdateTransform();
}
TranslateMap(translation);
@ -448,7 +445,7 @@ namespace MapControl
base.OnRenderSizeChanged(sizeInfo);
ResetTransformOrigin();
UpdateViewTransform();
UpdateTransform();
}
protected override void OnRender(DrawingContext drawingContext)
@ -456,21 +453,89 @@ namespace MapControl
drawingContext.DrawRectangle(Background, null, new Rect(RenderSize));
}
protected override void OnViewTransformChanged(Map map)
protected override void OnViewportChanged()
{
base.OnViewTransformChanged(map);
base.OnViewportChanged();
if (ViewTransformChanged != null)
if (ViewportChanged != null)
{
ViewTransformChanged(this, EventArgs.Empty);
ViewportChanged();
}
}
protected internal virtual void OnTileLayersChanged()
private void TileLayerCollectionChanged(object sender, NotifyCollectionChangedEventArgs eventArgs)
{
if (tileContainer.TileLayers != null &&
tileContainer.TileLayers.Count > 0 &&
tileContainer.TileLayers[0].HasDarkBackground)
switch (eventArgs.Action)
{
case NotifyCollectionChangedAction.Add:
tileContainer.AddTileLayers(eventArgs.NewStartingIndex, eventArgs.NewItems.Cast<TileLayer>());
break;
case NotifyCollectionChangedAction.Remove:
tileContainer.RemoveTileLayers(eventArgs.OldStartingIndex, eventArgs.OldItems.Cast<TileLayer>());
break;
case NotifyCollectionChangedAction.Move:
case NotifyCollectionChangedAction.Replace:
tileContainer.RemoveTileLayers(eventArgs.OldStartingIndex, eventArgs.OldItems.Cast<TileLayer>());
tileContainer.AddTileLayers(eventArgs.NewStartingIndex, eventArgs.NewItems.Cast<TileLayer>());
break;
case NotifyCollectionChangedAction.Reset:
tileContainer.ClearTileLayers();
if (eventArgs.NewItems != null)
{
tileContainer.AddTileLayers(0, eventArgs.NewItems.Cast<TileLayer>());
}
break;
}
UpdateMainTileLayer();
}
private void TileLayersPropertyChanged(TileLayerCollection oldTileLayers, TileLayerCollection newTileLayers)
{
tileContainer.ClearTileLayers();
if (oldTileLayers != null)
{
oldTileLayers.CollectionChanged -= TileLayerCollectionChanged;
}
if (newTileLayers != null)
{
newTileLayers.CollectionChanged += TileLayerCollectionChanged;
tileContainer.AddTileLayers(0, newTileLayers);
}
UpdateMainTileLayer();
}
private TileLayerCollection CoerceTileLayersProperty(TileLayerCollection tileLayers)
{
if (tileLayers == null)
{
tileLayers = new TileLayerCollection();
}
return tileLayers;
}
private void MainTileLayerPropertyChanged(TileLayer mainTileLayer)
{
if (mainTileLayer != null)
{
if (TileLayers.Count == 0)
{
TileLayers.Add(mainTileLayer);
}
else if (TileLayers[0] != mainTileLayer)
{
TileLayers[0] = mainTileLayer;
}
}
if (mainTileLayer != null && mainTileLayer.HasDarkBackground)
{
if (DarkForeground != null)
{
@ -494,63 +559,34 @@ namespace MapControl
Background = LightBackground;
}
}
if (TileLayersChanged != null)
{
TileLayersChanged(this, EventArgs.Empty);
}
}
private void TileLayersPropertyChanged(TileLayerCollection tileLayers)
{
if (tileLayers != null)
{
tileContainer.TileLayers = tileLayers;
MainTileLayer = tileLayers.Count > 0 ? tileLayers[0] : null;
}
}
private TileLayerCollection CoerceTileLayersProperty(TileLayerCollection tileLayers)
{
if (tileLayers == null)
{
tileLayers = new TileLayerCollection();
}
return tileLayers;
}
private void MainTileLayerPropertyChanged(TileLayer mainTileLayer)
{
if (mainTileLayer != null)
{
if (tileContainer.TileLayers.Count == 0)
{
tileContainer.TileLayers.Add(mainTileLayer);
}
else if (tileContainer.TileLayers[0] != mainTileLayer)
{
tileContainer.TileLayers[0] = mainTileLayer;
}
}
}
private TileLayer CoerceMainTileLayerProperty(TileLayer mainTileLayer)
{
if (mainTileLayer == null && tileContainer.TileLayers.Count > 0)
if (mainTileLayer == null && TileLayers.Count > 0)
{
mainTileLayer = tileContainer.TileLayers[0];
mainTileLayer = TileLayers[0];
}
return mainTileLayer;
}
private void UpdateMainTileLayer()
{
TileLayer mainTileLayer = TileLayers.FirstOrDefault();
if (MainTileLayer != mainTileLayer)
{
MainTileLayer = mainTileLayer;
}
}
private void CenterPropertyChanged(Location center)
{
if (updateTransform)
{
ResetTransformOrigin();
UpdateViewTransform();
UpdateTransform();
}
if (centerAnimation == null)
@ -600,7 +636,7 @@ namespace MapControl
{
if (updateTransform)
{
UpdateViewTransform();
UpdateTransform();
}
if (zoomLevelAnimation == null)
@ -649,7 +685,7 @@ namespace MapControl
{
if (updateTransform)
{
UpdateViewTransform();
UpdateTransform();
}
if (headingAnimation == null)
@ -704,20 +740,20 @@ namespace MapControl
return ((heading % 360d) + 360d) % 360d;
}
private void UpdateViewTransform()
private void UpdateTransform()
{
double scale;
if (transformOrigin != null)
{
scale = tileContainer.SetTransform(ZoomLevel, Heading, MapTransform.Transform(transformOrigin), viewportOrigin, RenderSize);
scale = tileContainer.SetViewportTransform(ZoomLevel, Heading, MapTransform.Transform(transformOrigin), viewportOrigin, RenderSize);
updateTransform = false;
Center = ViewportPointToLocation(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d));
updateTransform = true;
}
else
{
scale = tileContainer.SetTransform(ZoomLevel, Heading, MapTransform.Transform(Center), viewportOrigin, RenderSize);
scale = tileContainer.SetViewportTransform(ZoomLevel, Heading, MapTransform.Transform(Center), viewportOrigin, RenderSize);
}
scale *= MapTransform.RelativeScale(Center) / MeterPerDegree; // Pixels per meter at center latitude
@ -728,7 +764,7 @@ namespace MapControl
rotateTransform.Angle = Heading;
scaleRotateTransform.Matrix = scaleTransform.Value * rotateTransform.Value;
OnViewTransformChanged(this);
OnViewportChanged();
}
}
}

View file

@ -7,16 +7,17 @@ using System.Windows;
namespace MapControl
{
internal interface INotifyParentMapChanged
{
void ParentMapChanged(Map oldParentMap, Map newParentMap);
}
/// <summary>
/// Base class for child elements of a MapPanel.
/// </summary>
public abstract class MapElement : FrameworkElement, INotifyParentMapChanged
public abstract class MapElement : FrameworkElement
{
static MapElement()
{
MapPanel.ParentMapProperty.OverrideMetadata(typeof(MapElement),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, ParentMapPropertyChanged));
}
protected MapElement()
{
HorizontalAlignment = HorizontalAlignment.Stretch;
@ -28,23 +29,26 @@ namespace MapControl
get { return MapPanel.GetParentMap(this); }
}
protected abstract void OnViewTransformChanged(Map parentMap);
protected abstract void OnViewportChanged();
private void OnViewTransformChanged(object sender, EventArgs eventArgs)
private static void ParentMapPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs eventArgs)
{
OnViewTransformChanged((Map)sender);
}
MapElement mapElement = obj as MapElement;
void INotifyParentMapChanged.ParentMapChanged(Map oldParentMap, Map newParentMap)
{
if (oldParentMap != null)
if (mapElement != null)
{
oldParentMap.ViewTransformChanged -= OnViewTransformChanged;
}
Map oldParentMap = eventArgs.OldValue as Map;
Map newParentMap = eventArgs.NewValue as Map;
if (newParentMap != null)
{
newParentMap.ViewTransformChanged += OnViewTransformChanged;
if (oldParentMap != null)
{
oldParentMap.ViewportChanged -= mapElement.OnViewportChanged;
}
if (newParentMap != null)
{
newParentMap.ViewportChanged += mapElement.OnViewportChanged;
}
}
}
}

View file

@ -125,8 +125,9 @@ namespace MapControl
return visual;
}
protected override void OnViewTransformChanged(Map parentMap)
protected override void OnViewportChanged()
{
Map parentMap = ParentMap;
Rect bounds = parentMap.ViewportTransform.Inverse.TransformBounds(new Rect(parentMap.RenderSize));
Location loc1 = parentMap.MapTransform.TransformBack(bounds.TopLeft);
Location loc2 = parentMap.MapTransform.TransformBack(bounds.BottomRight);
@ -195,7 +196,7 @@ namespace MapControl
private void UpdateBrush()
{
pen.Brush = null;
OnViewTransformChanged(ParentMap);
OnViewportChanged();
}
private static string CoordinateString(double value, string format, string hemispheres)

View file

@ -15,7 +15,7 @@ namespace MapControl
/// coordinates. IsInsideMapBounds indicates if the viewport coordinates are located
/// inside the visible part of the map.
/// </summary>
public class MapPanel : Panel, INotifyParentMapChanged
public class MapPanel : Panel
{
public static readonly DependencyProperty ParentMapProperty = DependencyProperty.RegisterAttached(
"ParentMap", typeof(Map), typeof(MapPanel),
@ -102,8 +102,10 @@ namespace MapControl
return finalSize;
}
protected virtual void OnViewTransformChanged(Map parentMap)
protected virtual void OnViewportChanged()
{
Map parentMap = ParentMap;
foreach (UIElement element in InternalChildren)
{
Location location = GetLocation(element);
@ -115,31 +117,24 @@ namespace MapControl
}
}
private void OnViewTransformChanged(object sender, EventArgs eventArgs)
{
OnViewTransformChanged((Map)sender);
}
void INotifyParentMapChanged.ParentMapChanged(Map oldParentMap, Map newParentMap)
{
if (oldParentMap != null && oldParentMap != this)
{
oldParentMap.ViewTransformChanged -= OnViewTransformChanged;
}
if (newParentMap != null && newParentMap != this)
{
newParentMap.ViewTransformChanged += OnViewTransformChanged;
}
}
private static void ParentMapPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs eventArgs)
{
INotifyParentMapChanged notifyChanged = obj as INotifyParentMapChanged;
MapPanel mapPanel = obj as MapPanel;
if (notifyChanged != null)
if (mapPanel != null)
{
notifyChanged.ParentMapChanged(eventArgs.OldValue as Map, eventArgs.NewValue as Map);
Map oldParentMap = eventArgs.OldValue as Map;
Map newParentMap = eventArgs.NewValue as Map;
if (oldParentMap != null && oldParentMap != mapPanel)
{
oldParentMap.ViewportChanged -= mapPanel.OnViewportChanged;
}
if (newParentMap != null && newParentMap != mapPanel)
{
newParentMap.ViewportChanged += mapPanel.OnViewportChanged;
}
}
}

View file

@ -156,13 +156,13 @@ namespace MapControl
AddVisualChild(visual);
}
protected override void OnViewTransformChanged(Map parentMap)
protected override void OnViewportChanged()
{
double scale = 1d;
if (TransformStroke)
{
scale = parentMap.CenterScale * Map.MeterPerDegree;
scale = ParentMap.CenterScale * Map.MeterPerDegree;
}
drawing.Pen.Thickness = scale * StrokeThickness;
@ -175,12 +175,10 @@ namespace MapControl
protected void UpdateGeometry(bool closed)
{
Map parentMap = MapPanel.GetParentMap(this);
if (parentMap != null && Locations != null && Locations.Count > 0)
if (ParentMap != null && Locations != null && Locations.Count > 0)
{
drawing.Geometry = CreateGeometry(parentMap, Locations, closed);
OnViewTransformChanged(parentMap);
drawing.Geometry = CreateGeometry(Locations, closed);
OnViewportChanged();
}
else
{
@ -190,28 +188,26 @@ namespace MapControl
private void UpdatePenThickness()
{
Map parentMap = MapPanel.GetParentMap(this);
if (parentMap != null)
if (ParentMap != null)
{
OnViewTransformChanged(parentMap);
OnViewportChanged();
}
}
private Geometry CreateGeometry(Map parentMap, LocationCollection locations, bool closed)
private Geometry CreateGeometry(LocationCollection locations, bool closed)
{
StreamGeometry geometry = new StreamGeometry
{
Transform = parentMap.ViewportTransform
Transform = ParentMap.ViewportTransform
};
using (StreamGeometryContext sgc = geometry.Open())
{
sgc.BeginFigure(parentMap.MapTransform.Transform(locations.First()), closed, closed);
sgc.BeginFigure(ParentMap.MapTransform.Transform(locations.First()), closed, closed);
if (Locations.Count > 1)
{
sgc.PolyLineTo(parentMap.MapTransform.Transform(locations.Skip(1)), true, true);
sgc.PolyLineTo(ParentMap.MapTransform.Transform(locations.Skip(1)), true, true);
}
}

View file

@ -3,8 +3,7 @@
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
@ -23,44 +22,56 @@ namespace MapControl
private double zoomLevel;
private int tileZoomLevel;
private Int32Rect tileGrid;
private TileLayerCollection tileLayers;
private readonly DispatcherTimer updateTimer;
private readonly MatrixTransform viewportTransform = new MatrixTransform();
public readonly MatrixTransform ViewportTransform = new MatrixTransform();
public TileContainer()
{
updateTimer = new DispatcherTimer(TimeSpan.FromSeconds(0.5), DispatcherPriority.Background, UpdateTiles, Dispatcher);
}
public TileLayerCollection TileLayers
public void AddTileLayers(int index, IEnumerable<TileLayer> tileLayers)
{
get { return tileLayers; }
set
Matrix transform = GetVisualTransform();
foreach (TileLayer tileLayer in tileLayers)
{
if (tileLayers != null)
if (string.IsNullOrEmpty(tileLayer.Name))
{
tileLayers.CollectionChanged -= TileLayersChanged;
throw new ArgumentException("TileLayer.Name property must not be null or empty.");
}
tileLayers = value;
ClearChildren();
if (tileLayers != null)
{
tileLayers.CollectionChanged += TileLayersChanged;
AddChildren(0, tileLayers);
}
((Map)VisualParent).OnTileLayersChanged();
Children.Insert(index++, tileLayer);
tileLayer.TransformMatrix = transform;
tileLayer.UpdateTiles(tileZoomLevel, tileGrid);
}
}
public Transform ViewportTransform
public void RemoveTileLayers(int index, IEnumerable<TileLayer> tileLayers)
{
get { return viewportTransform; }
int count = 0;
foreach (TileLayer tileLayer in tileLayers)
{
tileLayer.ClearTiles();
count++;
}
Children.RemoveRange(index, count);
}
public double SetTransform(double mapZoomLevel, double mapRotation, Point mapOrigin, Point viewportOrigin, Size viewportSize)
public void ClearTileLayers()
{
foreach (TileLayer tileLayer in Children)
{
tileLayer.ClearTiles();
}
Children.Clear();
}
public double SetViewportTransform(double mapZoomLevel, double mapRotation, Point mapOrigin, Point viewportOrigin, Size viewportSize)
{
zoomLevel = mapZoomLevel;
rotation = mapRotation;
@ -75,16 +86,13 @@ namespace MapControl
transform.Scale(scale, scale);
transform.Translate(offset.X, offset.Y);
transform.RotateAt(rotation, origin.X, origin.Y);
viewportTransform.Matrix = transform;
ViewportTransform.Matrix = transform;
transform = GetVisualTransform();
if (tileLayers != null)
foreach (TileLayer tileLayer in Children)
{
foreach (TileLayer tileLayer in tileLayers)
{
tileLayer.TransformMatrix = transform;
}
tileLayer.TransformMatrix = transform;
}
updateTimer.IsEnabled = true;
@ -113,7 +121,7 @@ namespace MapControl
int zoom = (int)Math.Floor(zoomLevel + 1d - zoomLevelSwitchOffset);
int numTiles = 1 << zoom;
double mapToTileScale = (double)numTiles / 360d;
Matrix transform = viewportTransform.Matrix;
Matrix transform = ViewportTransform.Matrix;
transform.Invert(); // view to map coordinates
transform.Translate(180d, -180d);
transform.Scale(mapToTileScale, -mapToTileScale); // map coordinates to tile indices
@ -142,77 +150,12 @@ namespace MapControl
tileGrid = grid;
transform = GetVisualTransform();
if (tileLayers != null)
foreach (TileLayer tileLayer in Children)
{
foreach (TileLayer tileLayer in tileLayers)
{
tileLayer.TransformMatrix = transform;
tileLayer.UpdateTiles(tileZoomLevel, tileGrid);
}
tileLayer.TransformMatrix = transform;
tileLayer.UpdateTiles(tileZoomLevel, tileGrid);
}
}
}
private void TileLayersChanged(object sender, NotifyCollectionChangedEventArgs eventArgs)
{
switch (eventArgs.Action)
{
case NotifyCollectionChangedAction.Add:
AddChildren(eventArgs.NewStartingIndex, eventArgs.NewItems);
break;
case NotifyCollectionChangedAction.Remove:
RemoveChildren(eventArgs.OldStartingIndex, eventArgs.OldItems);
break;
case NotifyCollectionChangedAction.Move:
case NotifyCollectionChangedAction.Replace:
RemoveChildren(eventArgs.OldStartingIndex, eventArgs.OldItems);
AddChildren(eventArgs.NewStartingIndex, eventArgs.NewItems);
break;
case NotifyCollectionChangedAction.Reset:
ClearChildren();
if (eventArgs.NewItems != null)
{
AddChildren(0, eventArgs.NewItems);
}
break;
}
((Map)VisualParent).OnTileLayersChanged();
}
private void AddChildren(int index, IList layers)
{
Matrix transform = GetVisualTransform();
foreach (TileLayer tileLayer in layers)
{
Children.Insert(index++, tileLayer);
tileLayer.TransformMatrix = transform;
tileLayer.UpdateTiles(tileZoomLevel, tileGrid);
}
}
private void RemoveChildren(int index, IList layers)
{
foreach (TileLayer tileLayer in layers)
{
tileLayer.ClearTiles();
}
Children.RemoveRange(index, layers.Count);
}
private void ClearChildren()
{
foreach (TileLayer tileLayer in Children)
{
tileLayer.ClearTiles();
}
Children.Clear();
}
}
}

View file

@ -27,7 +27,6 @@ namespace MapControl
tileImageLoader = new TileImageLoader(this);
VisualEdgeMode = EdgeMode.Aliased;
VisualTransform = new MatrixTransform();
Name = string.Empty;
MinZoomLevel = 1;
MaxZoomLevel = 18;
MaxParallelDownloads = 8;
@ -59,7 +58,7 @@ namespace MapControl
tileImageLoader.CancelGetTiles();
if (VisualParent != null && TileSource != null)
if (TileSource != null)
{
SelectTiles();
RenderTiles();
@ -76,11 +75,11 @@ namespace MapControl
private void SelectTiles()
{
TileContainer tileContainer = VisualParent as TileContainer;
int maxZoomLevel = Math.Min(zoomLevel, MaxZoomLevel);
int minZoomLevel = maxZoomLevel;
ContainerVisual parent = Parent as ContainerVisual;
if (tileContainer != null && tileContainer.TileLayers.IndexOf(this) == 0)
if (parent != null && parent.Children.IndexOf(this) == 0)
{
minZoomLevel = MinZoomLevel;
}