diff --git a/Testing/WPF-GMapControlNew/GMapControlNew.xaml.cs b/Testing/WPF-GMapControlNew/GMapControlNew.xaml.cs
new file mode 100644
--- /dev/null
+++ b/Testing/WPF-GMapControlNew/GMapControlNew.xaml.cs
@@ -0,0 +1,1323 @@
+
+namespace GMap.NET.WindowsPresentation
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.ComponentModel;
+ using System.Diagnostics;
+ using System.Globalization;
+ using System.Linq;
+ using System.Windows;
+ using System.Windows.Controls;
+ using System.Windows.Input;
+ using System.Windows.Media;
+ using System.Windows.Media.Animation;
+ using System.Windows.Media.Effects;
+ using System.Windows.Media.Imaging;
+ using System.Windows.Shapes;
+ using System.Windows.Threading;
+ using GMap.NET;
+ using GMap.NET.Internals;
+
+ ///
+ /// GMap.NET control for Windows Presentation
+ /// >> for testing purpose only >>
+ ///
+ [ToolboxItem(false)]
+ public partial class GMapControlNew : UserControl, Interface
+ {
+ readonly Core Core = new Core();
+ GRect region = new GRect();
+ bool RaiseEmptyTileError = false;
+ delegate void MethodInvoker();
+ PointLatLng selectionStart;
+ PointLatLng selectionEnd;
+ Typeface tileTypeface = new Typeface("Arial");
+ double zoomReal;
+ bool showTileGridLines = false;
+
+ FormattedText googleCopyright;
+ FormattedText yahooMapCopyright;
+ FormattedText virtualEarthCopyright;
+ FormattedText openStreetMapCopyright;
+ FormattedText arcGisMapCopyright;
+
+ ///
+ /// pen for empty tile borders
+ ///
+ public Pen EmptyTileBorders = new Pen(Brushes.White, 1.0);
+
+ ///
+ /// pen for Selection
+ ///
+ public Pen SelectionPen = new Pen(Brushes.Blue, 3.0);
+
+ ///
+ /// ///
+ /// pen for empty tile background
+ ///
+ public Brush EmptytileBrush = Brushes.Navy;
+
+ ///
+ /// occurs on empty tile displayed
+ ///
+ public event EmptyTileError OnEmptyTileError;
+
+ ///
+ /// text on empty tiles
+ ///
+ public FormattedText EmptyTileText = new FormattedText("We are sorry, but we don't\nhave imagery at this zoom\n level for this region.", System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface("Arial"), 16, Brushes.White);
+
+ ///
+ /// max zoom
+ ///
+ public int MaxZoom = 2;
+
+ ///
+ /// min zoom
+ ///
+ public int MinZoom = 2;
+
+ ///
+ /// map zooming type for mouse wheel
+ ///
+ public MouseWheelZoomType MouseWheelZoomType = MouseWheelZoomType.MousePositionAndCenter;
+
+ ///
+ /// center mouse OnMouseWheel
+ ///
+ public bool CenterPositionOnMouseWheel = true;
+
+ ///
+ /// map dragg button
+ ///
+ public MouseButton DragButton = MouseButton.Right;
+
+ ///
+ /// zoom increment on mouse wheel
+ ///
+ public double ZoomIncrement = 1.0;
+
+ ///
+ /// shows tile gridlines
+ ///
+ [Category("GMap.NET")]
+ public bool ShowTileGridLines
+ {
+ get
+ {
+ return showTileGridLines;
+ }
+ set
+ {
+ showTileGridLines = value;
+ InvalidateVisual();
+ }
+ }
+
+ ///
+ /// current selected area in map
+ ///
+ private RectLatLng selectedArea;
+
+ [Browsable(false)]
+ public RectLatLng SelectedArea
+ {
+ get
+ {
+ return selectedArea;
+ }
+ set
+ {
+ selectedArea = value;
+ InvalidateVisual();
+ }
+ }
+
+ ///
+ /// map boundaries
+ ///
+ public RectLatLng? BoundsOfMap = null;
+
+ ///
+ /// list of markers
+ ///
+ public readonly ObservableCollection Markers = new ObservableCollection();
+
+ ///
+ /// current map transformation
+ ///
+ internal Transform MapRenderTransform;
+
+ ///
+ /// current markers overlay offset
+ ///
+ internal TranslateTransform MapTranslateTransform = new TranslateTransform();
+
+ ///
+ /// map zoom
+ ///
+ [Category("GMap.NET")]
+ public double Zoom
+ {
+ get
+ {
+ return zoomReal;
+ }
+ set
+ {
+ if(zoomReal != value)
+ {
+ if(value > MaxZoom)
+ {
+ zoomReal = MaxZoom;
+ }
+ else
+ if(value < MinZoom)
+ {
+ zoomReal = MinZoom;
+ }
+ else
+ {
+ zoomReal = value;
+ }
+
+ double remainder = (double) System.Decimal.Remainder((Decimal) value, (Decimal) 1);
+ if(remainder != 0)
+ {
+ double scaleValue = remainder + 1;
+ {
+ MapRenderTransform = new ScaleTransform(scaleValue, scaleValue, ActualWidth / 2, ActualHeight / 2);
+ }
+
+ if(IsLoaded)
+ {
+ //DisplayZoomInFadeImage();
+ }
+
+ ZoomStep = Convert.ToInt32(value - remainder);
+
+ Core_OnMapZoomChanged();
+
+ InvalidateVisual();
+ }
+ else
+ {
+ MapRenderTransform = null;
+ ZoomStep = Convert.ToInt32(value);
+ InvalidateVisual();
+ }
+ }
+ }
+ }
+
+ protected bool DesignModeInConstruct
+ {
+ get
+ {
+ //Are we in Visual Studio Designer?
+ return System.ComponentModel.DesignerProperties.GetIsInDesignMode(this);
+ }
+ }
+
+ Canvas mapCanvas = null;
+
+ ///
+ /// markers overlay
+ ///
+ internal Canvas MapCanvas
+ {
+ get
+ {
+ if(mapCanvas == null)
+ {
+ // if(ObjectsLayer.VisualChildrenCount > 0)
+ {
+ Border border = VisualTreeHelper.GetChild(ObjectsLayer, 0) as Border;
+ ItemsPresenter items = border.Child as ItemsPresenter;
+ DependencyObject target = VisualTreeHelper.GetChild(items, 0);
+ mapCanvas = target as Canvas;
+ }
+ }
+
+ return mapCanvas;
+ }
+ }
+
+ public GMaps Manager
+ {
+ get
+ {
+ return GMaps.Instance;
+ }
+ }
+
+ public GMapControlNew()
+ {
+ InitializeComponent();
+
+ if(!DesignModeInConstruct)
+ {
+ ObjectsLayer.ItemsSource = Markers;
+
+ // removes white lines between tiles!
+ SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Unspecified);
+
+ // set image proxy
+ Manager.ImageProxy = new WindowsPresentationImageProxy();
+
+ //Core.RenderMode = GMap.NET.RenderMode.WPF;
+ //Core.OnNeedInvalidation += new NeedInvalidation(Core_OnNeedInvalidation);
+ //Core.OnMapZoomChanged += new MapZoomChanged(Core_OnMapZoomChanged);
+
+ Loaded += new RoutedEventHandler(GMapControl_Loaded);
+ Unloaded += new RoutedEventHandler(GMapControl_Unloaded);
+
+ googleCopyright = new FormattedText(Core.googleCopyright, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface("GenericSansSerif"), 9, Brushes.Navy);
+ yahooMapCopyright = new FormattedText(Core.yahooMapCopyright, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface("GenericSansSerif"), 9, Brushes.Navy);
+ virtualEarthCopyright = new FormattedText(Core.virtualEarthCopyright, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface("GenericSansSerif"), 9, Brushes.Navy);
+ openStreetMapCopyright = new FormattedText(Core.openStreetMapCopyright, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface("GenericSansSerif"), 9, Brushes.Navy);
+ arcGisMapCopyright = new FormattedText(Core.arcGisCopyright, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface("GenericSansSerif"), 9, Brushes.Navy);
+
+ MapType = MapType.GoogleMap;
+
+ OpacityAnimation = CreateOpacityAnimation(1);
+ ZoomAnimation = CreateZoomAnimation(2);
+ MoveAnimation = CreateMoveAnimation(2);
+ }
+ }
+
+ DoubleAnimation CreateZoomAnimation(double toValue)
+ {
+ var da = new DoubleAnimation(toValue, new Duration(TimeSpan.FromMilliseconds(555)));
+ da.AccelerationRatio = 0.1;
+ da.DecelerationRatio = 0.9;
+ da.FillBehavior = FillBehavior.HoldEnd;
+ da.Freeze();
+ return da;
+ }
+
+ DoubleAnimation CreateMoveAnimation(double toValue)
+ {
+ var da = new DoubleAnimation(toValue, new Duration(TimeSpan.FromMilliseconds(555)));
+ da.AccelerationRatio = 0.1;
+ da.DecelerationRatio = 0.9;
+ da.FillBehavior = FillBehavior.HoldEnd;
+ da.Freeze();
+ return da;
+ }
+
+ DoubleAnimation CreateOpacityAnimation(double toValue)
+ {
+ var da = new DoubleAnimation(toValue, new Duration(TimeSpan.FromMilliseconds(555)));
+ da.AccelerationRatio = 0.5;
+ da.DecelerationRatio = 0.5;
+ da.FillBehavior = FillBehavior.HoldEnd;
+ da.Freeze();
+ return da;
+ }
+
+ void BeginAnimateOpacity(TileVisual target)
+ {
+ target.Opacity = 0.4;
+ target.BeginAnimation(TileVisual.OpacityProperty, OpacityAnimation, HandoffBehavior.Compose);
+ }
+
+ void BeginAnimateZoom(TileVisual target)
+ {
+ //target.TranslateTransform.BeginAnimation(TranslateTransform.XProperty, MoveAnimation, HandoffBehavior.Compose);
+ //target.TranslateTransform.BeginAnimation(TranslateTransform.YProperty, MoveAnimation, HandoffBehavior.Compose);
+ //target.ScaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, ZoomAnimation, HandoffBehavior.Compose);
+ //target.ScaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, ZoomAnimation, HandoffBehavior.Compose);
+ }
+
+ DoubleAnimation OpacityAnimation;
+ DoubleAnimation ZoomAnimation;
+ DoubleAnimation MoveAnimation;
+
+ QuadTree QuadTree = new QuadTree();
+
+ bool update = true;
+ Dictionary images = new Dictionary();
+ System.Windows.Size TilesSize = new System.Windows.Size();
+
+ Stopwatch _stopwatch = new Stopwatch();
+ ushort _frameCounter;
+ ushort _frameCounterUpdate;
+ int count = 0;
+
+ protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
+ {
+ base.OnRenderSizeChanged(sizeInfo);
+
+ {
+ System.Windows.Size constraint = sizeInfo.NewSize;
+ region = new GRect(-50, -50, (int) constraint.Width + 100, (int) constraint.Height + 100);
+
+ TilesLayer.Width = sizeInfo.NewSize.Width;
+ TilesLayer.Height = sizeInfo.NewSize.Height;
+
+ QuadTree.Bounds = new Rect(sizeInfo.NewSize);
+ }
+
+ //var sizeInPx = Projection.GetTileMatrixSizePixel(ZoomStep);
+ //TilesLayer.Width = sizeInPx.Width;
+ //TilesLayer.Height = sizeInPx.Height;
+
+ if(IsLoaded)
+ {
+ Refresh();
+ }
+ }
+
+ void CompositionTargetEx_FrameUpdating(object sender, RenderingEventArgs e)
+ {
+ if(update)
+ {
+ _frameCounterUpdate++;
+ update = false;
+
+ #region -- add image --
+ for(int x = 0; x < TilesSize.Width; x++)
+ {
+ for(int y = 0; y < TilesSize.Height; y++)
+ {
+ var rawTile = new RawTile(MapType.GoogleHybrid, new GPoint(x, y), ZoomStep);
+ var rectTilePx = new Rect(x*Projection.TileSize.Width, y*Projection.TileSize.Height, Projection.TileSize.Width, Projection.TileSize.Height);
+
+ TileVisual image = null;
+ if(!images.TryGetValue(rawTile, out image))
+ {
+ var layers = GMaps.Instance.GetAllLayersOfType(rawTile.Type);
+
+ ImageSource[] imgs = new ImageSource[layers.Length];
+
+ // get tiles
+ for(int i = 0; i < layers.Length; i++)
+ {
+ Exception ex;
+ var res = GMaps.Instance.GetImageFrom(layers[i], rawTile.Pos, rawTile.Zoom, out ex) as WindowsPresentationImage;
+ if(res != null)
+ {
+ imgs[i] = res.Img;
+ }
+ }
+
+ // combine visual
+ image = new TileVisual(imgs, rawTile);
+ images.Add(rawTile, image);
+
+ Canvas.SetZIndex(image, -1);
+ }
+
+ bool ri = (region.IntersectsWith(new GRect((int) (rectTilePx.X + renderOffset.X), (int) (rectTilePx.Y + renderOffset.Y), (int) rectTilePx.Width, (int) rectTilePx.Height)));
+ if(TilesLayer.Children.Contains(image))
+ {
+ if(ri)
+ {
+ image.MoveTo(Math.Round(rectTilePx.X) + 0.6 + renderOffset.X, Math.Round(rectTilePx.Y) + 0.6 + renderOffset.Y);
+ }
+ else
+ {
+ TilesLayer.Children.Remove(image);
+ }
+ }
+ else
+ {
+ if(ri)
+ {
+ image.MoveTo(Math.Round(rectTilePx.X) + 0.6 + renderOffset.X, Math.Round(rectTilePx.Y) + 0.6 + renderOffset.Y);
+ BeginAnimateOpacity(image);
+ {
+ TilesLayer.Children.Add(image);
+ }
+ }
+ }
+ //break;
+ }
+ //break;
+ }
+
+ count = TilesLayer.Children.Count;
+
+ #endregion
+ }
+
+ if(_stopwatch.ElapsedMilliseconds >= 1000)
+ {
+ _stopwatch.Stop();
+
+ perfInfo.Text = "FPS: " + (ushort) (_frameCounter/_stopwatch.Elapsed.TotalSeconds) + " | " + (ushort) (_frameCounterUpdate/_stopwatch.Elapsed.TotalSeconds) + " | " + count + " tiles";
+
+ _frameCounter = 0;
+ _frameCounterUpdate = 0;
+ _stopwatch.Reset();
+ _stopwatch.Start();
+ }
+ else
+ {
+ _frameCounter++;
+ }
+ }
+
+ void GMapControl_Loaded(object sender, RoutedEventArgs e)
+ {
+ CompositionTargetEx.FrameUpdating += new EventHandler(CompositionTargetEx_FrameUpdating);
+ _stopwatch.Start();
+
+ Refresh();
+
+ //Core.StartSystem();
+ //Core_OnMapZoomChanged();
+ }
+
+ void GMapControl_Unloaded(object sender, RoutedEventArgs e)
+ {
+ CompositionTargetEx.FrameUpdating -= new EventHandler(CompositionTargetEx_FrameUpdating);
+ _stopwatch.Stop();
+
+ //Core.OnMapClose();
+ }
+
+ private void Refresh()
+ {
+ update = true;
+ InvalidateVisual();
+ }
+
+ //rotected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize)
+ ///
+ //MapBase parentMap = this.ParentMap;
+ //foreach(UIElement element in base.Children)
+ //{
+ // Rect finalRect = new Rect(0.0, 0.0, parentMap.ViewportSize.Width, parentMap.ViewportSize.Height);
+ // LocationRect positionRectangle = GetPositionRectangle(element);
+ // if(positionRectangle != null)
+ // {
+ // finalRect = parentMap.Mode.LocationToViewportPoint(positionRectangle);
+ // }
+ // else
+ // {
+ // Point point;
+ // Location position = GetPosition(element);
+ // if((position != null) && parentMap.TryLocationToViewportPoint(position, out point))
+ // {
+ // PositionOrigin positionOrigin = GetPositionOrigin(element);
+ // point.X -= positionOrigin.X * element.DesiredSize.Width;
+ // point.Y -= positionOrigin.Y * element.DesiredSize.Height;
+ // finalRect = new Rect(point.X, point.Y, element.DesiredSize.Width, element.DesiredSize.Height);
+ // }
+ // }
+ // Point positionOffset = GetPositionOffset(element);
+ // finalRect.X += positionOffset.X;
+ // finalRect.Y += positionOffset.Y;
+ // element.Arrange(finalRect);
+ //}
+ //return parentMap.ViewportSize;
+ //
+
+ //protected override Size MeasureOverride(Size availableSize)
+ //{
+ // MapBase parentMap = this.ParentMap;
+ // Guid lastProjectPassTag = this.lastProjectPassTag;
+ // this.lastProjectPassTag = Guid.NewGuid();
+ // foreach(UIElement element in base.Children)
+ // {
+ // IProjectable projectable = element as IProjectable;
+ // if(projectable != null)
+ // {
+ // ProjectionUpdateLevel pendingUpdate = this.pendingUpdate;
+ // if(((Guid) element.GetValue(ProjectionUpdatedTag)) != lastProjectPassTag)
+ // {
+ // pendingUpdate = ProjectionUpdateLevel.Full;
+ // }
+ // if(pendingUpdate != ProjectionUpdateLevel.None)
+ // {
+ // projectable.ProjectionUpdated(pendingUpdate);
+ // }
+ // element.SetValue(ProjectionUpdatedTag, this.lastProjectPassTag);
+ // }
+ // }
+ // this.pendingUpdate = ProjectionUpdateLevel.None;
+ // foreach(UIElement element2 in base.Children)
+ // {
+ // LocationRect positionRectangle = GetPositionRectangle(element2);
+ // if(positionRectangle != null)
+ // {
+ // Rect rect2 = parentMap.Mode.LocationToViewportPoint(positionRectangle);
+ // element2.Measure(new Size(rect2.Width, rect2.Height));
+ // }
+ // else
+ // {
+ // if((element2 is ContentPresenter) && (VisualTreeHelper.GetChildrenCount(element2) > 0))
+ // {
+ // IProjectable child = VisualTreeHelper.GetChild(element2, 0) as IProjectable;
+ // if(child != null)
+ // {
+ // child.ProjectionUpdated(ProjectionUpdateLevel.Full);
+ // UIElement element3 = child as UIElement;
+ // if(element3 != null)
+ // {
+ // element3.InvalidateMeasure();
+ // }
+ // }
+ // }
+ // element2.Measure(parentMap.ViewportSize);
+ // }
+ // }
+ // return parentMap.ViewportSize;
+ //}
+
+ #region -- etc --
+ void Core_OnMapZoomChanged()
+ {
+ //UpdateMarkersOffset();
+
+ foreach(var i in Markers)
+ {
+ //i.ForceUpdateLocalPosition(this);
+ }
+
+ var routes = Markers.Where(p => p != null && p.Route.Count > 1);
+ if(routes != null)
+ {
+ foreach(var i in routes)
+ {
+ //i.RegenerateRouteShape(this);
+ }
+ }
+ }
+
+ ///
+ /// on core needs invalidation
+ ///
+ void Core_OnNeedInvalidation()
+ {
+ try
+ {
+ this.Dispatcher.BeginInvoke(DispatcherPriority.Render, new MethodInvoker(Refresh));
+ }
+ catch
+ {
+ }
+ }
+
+ ///
+ /// updates markers overlay offset
+ ///
+ void UpdateMarkersOffset()
+ {
+ if(MapCanvas != null)
+ {
+ if(MapRenderTransform != null)
+ {
+ var tp = MapRenderTransform.Transform(new System.Windows.Point(Core.renderOffset.X, Core.renderOffset.Y));
+ MapTranslateTransform.X = tp.X;
+ MapTranslateTransform.Y = tp.Y;
+ }
+ else
+ {
+ MapTranslateTransform.X = Core.renderOffset.X;
+ MapTranslateTransform.Y = Core.renderOffset.Y;
+ }
+
+ MapCanvas.RenderTransform = MapTranslateTransform;
+ }
+ }
+
+ ///
+ /// gets image of the current view
+ ///
+ ///
+ public ImageSource ToImageSource()
+ {
+ FrameworkElement obj = this;
+
+ // Save current canvas transform
+ Transform transform = obj.LayoutTransform;
+ obj.LayoutTransform = null;
+
+ // fix margin offset as well
+ Thickness margin = obj.Margin;
+ obj.Margin = new Thickness(0, 0,
+ margin.Right - margin.Left, margin.Bottom - margin.Top);
+
+ // Get the size of canvas
+ System.Windows.Size size = new System.Windows.Size(obj.ActualWidth, obj.ActualHeight);
+
+ // force control to Update
+ obj.Measure(size);
+ obj.Arrange(new Rect(size));
+
+ RenderTargetBitmap bmp = new RenderTargetBitmap(
+ (int) size.Width, (int) size.Height, 96, 96, PixelFormats.Pbgra32);
+
+ bmp.Render(obj);
+
+ if(bmp.CanFreeze)
+ {
+ bmp.Freeze();
+ }
+
+ // return values as they were before
+ obj.LayoutTransform = transform;
+ obj.Margin = margin;
+
+ return bmp;
+ }
+
+ ///
+ /// creates path from list of points
+ ///
+ ///
+ ///
+ public Path CreateRoutePath(List localPath)
+ {
+ // Create a StreamGeometry to use to specify myPath.
+ StreamGeometry geometry = new StreamGeometry();
+
+ using(StreamGeometryContext ctx = geometry.Open())
+ {
+ ctx.BeginFigure(localPath[0], false, false);
+
+ // Draw a line to the next specified point.
+ ctx.PolyLineTo(localPath, true, true);
+ }
+
+ // Freeze the geometry (make it unmodifiable)
+ // for additional performance benefits.
+ geometry.Freeze();
+
+ // Create a path to draw a geometry with.
+ Path myPath = new Path();
+ {
+ // Specify the shape of the Path using the StreamGeometry.
+ myPath.Data = geometry;
+
+ BlurEffect ef = new BlurEffect();
+ {
+ ef.KernelType = KernelType.Gaussian;
+ ef.Radius = 3.0;
+ ef.RenderingBias = RenderingBias.Quality;
+ }
+
+ myPath.Effect = ef;
+
+ myPath.Stroke = Brushes.Navy;
+ myPath.StrokeThickness = 5;
+ myPath.StrokeLineJoin = PenLineJoin.Round;
+ myPath.StrokeStartLineCap = PenLineCap.Triangle;
+ myPath.StrokeEndLineCap = PenLineCap.Square;
+ myPath.Opacity = 0.6;
+ }
+ return myPath;
+ }
+
+ ///
+ /// sets zoom to max to fit rect
+ ///
+ /// area
+ ///
+ public bool SetZoomToFitRect(RectLatLng rect)
+ {
+ int maxZoom = Core.GetMaxZoomToFitRect(rect);
+ if(maxZoom > 0)
+ {
+ PointLatLng center = new PointLatLng(rect.Lat - (rect.HeightLat / 2), rect.Lng + (rect.WidthLng / 2));
+ Position = center;
+
+ if(maxZoom > MaxZoom)
+ {
+ maxZoom = MaxZoom;
+ }
+
+ if(ZoomStep != maxZoom)
+ {
+ Zoom = maxZoom;
+ }
+
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// sets to max zoom to fit all markers and centers them in map
+ ///
+ /// z index or null to check all
+ ///
+ public bool ZoomAndCenterMarkers(int? ZIndex)
+ {
+ RectLatLng? rect = GetRectOfAllMarkers(ZIndex);
+ if(rect.HasValue)
+ {
+ return SetZoomToFitRect(rect.Value);
+ }
+
+ return false;
+ }
+
+ ///
+ /// gets rectangle with all objects inside
+ ///
+ /// z index or null to check all
+ ///
+ public RectLatLng? GetRectOfAllMarkers(int? ZIndex)
+ {
+ RectLatLng? ret = null;
+
+ double left = double.MaxValue;
+ double top = double.MinValue;
+ double right = double.MinValue;
+ double bottom = double.MaxValue;
+ IEnumerable Overlays;
+
+ if(ZIndex.HasValue)
+ {
+ Overlays = Markers.Where(p => p != null && p.ZIndex == ZIndex);
+ }
+ else
+ {
+ Overlays = Markers;
+ }
+
+ if(Overlays != null)
+ {
+ foreach(var m in Overlays)
+ {
+ if(m.Shape != null && m.Shape.IsVisible)
+ {
+ // left
+ if(m.Position.Lng < left)
+ {
+ left = m.Position.Lng;
+ }
+
+ // top
+ if(m.Position.Lat > top)
+ {
+ top = m.Position.Lat;
+ }
+
+ // right
+ if(m.Position.Lng > right)
+ {
+ right = m.Position.Lng;
+ }
+
+ // bottom
+ if(m.Position.Lat < bottom)
+ {
+ bottom = m.Position.Lat;
+ }
+ }
+ }
+ }
+
+ if(left != double.MaxValue && right != double.MinValue && top != double.MinValue && bottom != double.MaxValue)
+ {
+ ret = RectLatLng.FromLTRB(left, top, right, bottom);
+ }
+
+ return ret;
+ }
+ #endregion
+
+ #region UserControl Events
+
+ //double move;
+ protected override void OnMouseWheel(MouseWheelEventArgs e)
+ {
+ base.OnMouseWheel(e);
+
+ if(e.Delta > 0)
+ {
+ ZoomStep++;
+
+ //ZoomAnimation = CreateZoomAnimation(ZoomStep);
+
+ // move -= Projection.TileSize.Width;
+ //MoveAnimation = CreateMoveAnimation(move);
+ }
+ else
+ {
+ ZoomStep--;
+
+ //ZoomAnimation = CreateZoomAnimation(ZoomStep);
+
+ //move += Projection.TileSize.Width;
+ //MoveAnimation = CreateMoveAnimation(move);
+ }
+ //Refresh();
+ }
+
+ bool isSelected = false;
+
+ System.Windows.Point? mouseDown = null;
+ static readonly System.Windows.Point Empty = new System.Windows.Point();
+
+ protected override void OnMouseDown(MouseButtonEventArgs e)
+ {
+ if(CanDragMap && e.ChangedButton == DragButton && e.ButtonState == MouseButtonState.Pressed)
+ {
+ mouseDown = e.GetPosition(TilesLayer);
+
+ dragPoint.X = mouseDown.Value.X - renderOffset.X;
+ dragPoint.Y = mouseDown.Value.Y - renderOffset.Y;
+
+ Mouse.Capture(TilesLayer);
+ }
+
+ base.OnMouseDown(e);
+ }
+
+ protected override void OnMouseUp(MouseButtonEventArgs e)
+ {
+ base.OnMouseUp(e);
+
+ mouseDown = null;
+ Mouse.Capture(null);
+ }
+
+ System.Windows.Point renderOffset = new System.Windows.Point();
+ System.Windows.Point dragPoint = new System.Windows.Point();
+
+ protected override void OnMouseMove(MouseEventArgs e)
+ {
+ base.OnMouseMove(e);
+
+ if(mouseDown.HasValue)
+ {
+ System.Windows.Point p = e.GetPosition(TilesLayer);
+
+ //TileOffset.Y += p.Y - mouseDown.Value.Y;
+ //TileOffset.X += p.X - mouseDown.Value.X;
+
+ renderOffset.X = p.X - dragPoint.X;
+ renderOffset.Y = p.Y - dragPoint.Y;
+
+ Refresh();
+ }
+ }
+
+ #endregion
+
+ #region IGControl Members
+
+ public void ReloadMap()
+ {
+ Core.ReloadMap();
+ }
+
+ public GeoCoderStatusCode SetCurrentPositionByKeywords(string keys)
+ {
+ GeoCoderStatusCode status = GeoCoderStatusCode.Unknow;
+ PointLatLng? pos = Manager.GetLatLngFromGeocoder(keys, out status);
+ if(pos.HasValue && status == GeoCoderStatusCode.G_GEO_SUCCESS)
+ {
+ Position = pos.Value;
+ }
+
+ return status;
+ }
+
+ public PointLatLng FromLocalToLatLng(int x, int y)
+ {
+ if(MapRenderTransform != null)
+ {
+ var tp = MapRenderTransform.Inverse.Transform(new System.Windows.Point(x, y));
+ x = (int) tp.X;
+ y = (int) tp.Y;
+ }
+
+ return Core.FromLocalToLatLng(x, y);
+ }
+
+ public GPoint FromLatLngToLocal(PointLatLng point)
+ {
+ GPoint ret = Core.FromLatLngToLocal(point);
+
+ if(MapRenderTransform != null)
+ {
+ var tp = MapRenderTransform.Transform(new System.Windows.Point(ret.X, ret.Y));
+ ret.X = (int) tp.X;
+ ret.Y = (int) tp.Y;
+ }
+
+ if(MapTranslateTransform != null)
+ {
+ ret.Offset(-(int) MapTranslateTransform.X, -(int) MapTranslateTransform.Y);
+ }
+
+ return ret;
+ }
+
+ public bool ShowExportDialog()
+ {
+#if SQLite
+ if(Cache.Instance.ImageCache is GMap.NET.CacheProviders.SQLitePureImageCache)
+ {
+ Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
+ {
+ dlg.CheckPathExists = true;
+ dlg.CheckFileExists = false;
+ dlg.AddExtension = true;
+ dlg.DefaultExt = "gmdb";
+ dlg.ValidateNames = true;
+ dlg.Title = "GMap.NET: Export map to db, if file exsist only new data will be added";
+ dlg.FileName = "DataExp";
+ dlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
+ dlg.Filter = "GMap.NET DB files (*.gmdb)|*.gmdb";
+ dlg.FilterIndex = 1;
+ dlg.RestoreDirectory = true;
+
+ if(dlg.ShowDialog() == true)
+ {
+ bool ok = GMaps.Instance.ExportToGMDB(dlg.FileName);
+ if(ok)
+ {
+ MessageBox.Show("Complete!", "GMap.NET", MessageBoxButton.OK, MessageBoxImage.Information);
+ }
+ else
+ {
+ MessageBox.Show(" Failed!", "GMap.NET", MessageBoxButton.OK, MessageBoxImage.Warning);
+ }
+
+ return ok;
+ }
+ }
+ }
+ else
+ {
+ MessageBox.Show("Failed! Only SQLite support ;/", "GMap.NET", MessageBoxButton.OK, MessageBoxImage.Warning);
+ }
+#endif
+ return false;
+ }
+
+ public bool ShowImportDialog()
+ {
+#if SQLite
+ if(Cache.Instance.ImageCache is GMap.NET.CacheProviders.SQLitePureImageCache)
+ {
+ Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
+ {
+ dlg.CheckPathExists = true;
+ dlg.CheckFileExists = false;
+ dlg.AddExtension = true;
+ dlg.DefaultExt = "gmdb";
+ dlg.ValidateNames = true;
+ dlg.Title = "GMap.NET: Import to db, only new data will be added";
+ dlg.FileName = "DataImport";
+ dlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
+ dlg.Filter = "GMap.NET DB files (*.gmdb)|*.gmdb";
+ dlg.FilterIndex = 1;
+ dlg.RestoreDirectory = true;
+
+ if(dlg.ShowDialog() == true)
+ {
+ Cursor = Cursors.Wait;
+
+ bool ok = GMaps.Instance.ImportFromGMDB(dlg.FileName);
+ if(ok)
+ {
+ MessageBox.Show("Complete!", "GMap.NET", MessageBoxButton.OK, MessageBoxImage.Information);
+ ReloadMap();
+ }
+ else
+ {
+ MessageBox.Show(" Failed!", "GMap.NET", MessageBoxButton.OK, MessageBoxImage.Warning);
+ }
+
+ Cursor = Cursors.Arrow;
+
+ return ok;
+ }
+ }
+ }
+ else
+ {
+ MessageBox.Show("Failed! Only SQLite support ;/", "GMap.NET", MessageBoxButton.OK, MessageBoxImage.Warning);
+ }
+#endif
+ return false;
+ }
+
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ [Browsable(false)]
+ internal int ZoomStep
+ {
+ get
+ {
+ return Core.Zoom;
+ }
+ set
+ {
+ if(value > MaxZoom)
+ {
+ Core.Zoom = MaxZoom;
+ }
+ else if(value < MinZoom)
+ {
+ Core.Zoom = MinZoom;
+ }
+ else
+ {
+ bool changed = (Core.Zoom != value);
+ Core.Zoom = value;
+ if(changed)
+ {
+ foreach(UIElement u in TilesLayer.Children)
+ {
+ var m = u as TileVisual;
+ if(m != null)
+ {
+ if(images.ContainsKey(m.Tile))
+ {
+ images.Remove(m.Tile);
+ m.Source.Clear();
+ }
+ }
+ }
+
+ TilesLayer.Children.Clear();
+
+ var sizeinTiles = Projection.GetTileMatrixSizeXY(ZoomStep);
+ TilesSize.Width = sizeinTiles.Width;
+ TilesSize.Height = sizeinTiles.Height;
+
+ if(IsLoaded)
+ {
+ Refresh();
+ }
+ }
+ }
+ }
+ }
+
+ [Browsable(false)]
+ public PointLatLng Position
+ {
+ get
+ {
+ return Core.CurrentPosition;
+ }
+ set
+ {
+ Core.CurrentPosition = value;
+ UpdateMarkersOffset();
+ }
+ }
+
+ [Browsable(false)]
+ public GPoint CurrentPositionGPixel
+ {
+ get
+ {
+ return Core.CurrentPositionGPixel;
+ }
+ }
+
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ [Browsable(false)]
+ public string CacheLocation
+ {
+ get
+ {
+ return Cache.Instance.CacheLocation;
+ }
+ set
+ {
+ Cache.Instance.CacheLocation = value;
+ }
+ }
+
+ [Browsable(false)]
+ public bool IsDragging
+ {
+ get
+ {
+ return Core.IsDragging;
+ }
+ }
+
+ [Browsable(false)]
+ public RectLatLng CurrentViewArea
+ {
+ get
+ {
+ return Core.CurrentViewArea;
+ }
+ }
+
+ [Category("GMap.NET")]
+ public MapType MapType
+ {
+ get
+ {
+ return Core.MapType;
+ }
+ set
+ {
+ Core.MapType = value;
+ }
+ }
+
+ [Browsable(false)]
+ public PureProjection Projection
+ {
+ get
+ {
+ return Core.Projection;
+ }
+ }
+
+ [Category("GMap.NET")]
+ public bool CanDragMap
+ {
+ get
+ {
+ return Core.CanDragMap;
+ }
+ set
+ {
+ Core.CanDragMap = value;
+ }
+ }
+
+ public GMap.NET.RenderMode RenderMode
+ {
+ get
+ {
+ return GMap.NET.RenderMode.WPF;
+ }
+ }
+
+ #endregion
+
+ #region IGControl event Members
+
+ public event PositionChanged OnPositionChanged
+ {
+ add
+ {
+ Core.OnCurrentPositionChanged += value;
+ }
+ remove
+ {
+ Core.OnCurrentPositionChanged -= value;
+ }
+ }
+
+ public event TileLoadComplete OnTileLoadComplete
+ {
+ add
+ {
+ Core.OnTileLoadComplete += value;
+ }
+ remove
+ {
+ Core.OnTileLoadComplete -= value;
+ }
+ }
+
+ public event TileLoadStart OnTileLoadStart
+ {
+ add
+ {
+ Core.OnTileLoadStart += value;
+ }
+ remove
+ {
+ Core.OnTileLoadStart -= value;
+ }
+ }
+
+ public event MapDrag OnMapDrag
+ {
+ add
+ {
+ Core.OnMapDrag += value;
+ }
+ remove
+ {
+ Core.OnMapDrag -= value;
+ }
+ }
+
+ public event MapZoomChanged OnMapZoomChanged
+ {
+ add
+ {
+ Core.OnMapZoomChanged += value;
+ }
+ remove
+ {
+ Core.OnMapZoomChanged -= value;
+ }
+ }
+
+ ///
+ /// occures on map type changed
+ ///
+ public event MapTypeChanged OnMapTypeChanged
+ {
+ add
+ {
+ Core.OnMapTypeChanged += value;
+ }
+ remove
+ {
+ Core.OnMapTypeChanged -= value;
+ }
+ }
+
+ #endregion
+ }
+
+ static class Extensions
+ {
+ public static void CenterAt(this FrameworkElement element, System.Windows.Point center)
+ {
+ CenterAt(element, center.X, center.Y);
+ }
+
+ public static void CenterAt(this FrameworkElement element, double x, double y)
+ {
+ MoveTo(element, x - element.Width / 2, y - element.Height / 2);
+ }
+
+ public static void MoveTo(this UIElement element, double x, double y)
+ {
+ Canvas.SetLeft(element, x);
+ Canvas.SetTop(element, y);
+ }
+
+ public static void MoveTo(this UIElement element, System.Windows.Point position)
+ {
+ MoveTo(element, position.X, position.Y);
+ }
+
+ public static void MoveOffset(this UIElement element, double xOffset, double yOffset)
+ {
+ if(element == null || double.IsNaN(xOffset) || double.IsNaN(yOffset))
+ {
+ return;
+ }
+ var coordinates = element.GetCoordinates();
+ Canvas.SetLeft(element, coordinates.X + xOffset);
+ Canvas.SetTop(element, coordinates.Y + yOffset);
+ }
+
+ public static System.Windows.Point GetCoordinates(this UIElement element)
+ {
+ return new System.Windows.Point(Canvas.GetLeft(element), Canvas.GetTop(element));
+ }
+
+ public static System.Windows.Rect GetRect(this UIElement element)
+ {
+ return new System.Windows.Rect(element.GetCoordinates(), element.RenderSize);
+ }
+ }
+}
\ No newline at end of file