Subversion Repositories Projects

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2287 - 1

2
namespace GMap.NET.WindowsPresentation
3
{
4
   using System;
5
   using System.Collections.Generic;
6
   using System.Collections.ObjectModel;
7
   using System.ComponentModel;
8
   using System.Globalization;
9
   using System.Linq;
10
   using System.Windows;
11
   using System.Windows.Controls;
12
   using System.Windows.Data;
13
   using System.Windows.Input;
14
   using System.Windows.Media;
15
   using System.Windows.Media.Effects;
16
   using System.Windows.Media.Imaging;
17
   using System.Windows.Shapes;
18
   using System.Windows.Threading;
19
   using GMap.NET;
20
   using GMap.NET.Internals;
21
   using System.Diagnostics;
22
   using GMap.NET.MapProviders;
23
   using System.Windows.Media.Animation;
24
   using GMap.NET.Projections;
25
 
26
   /// <summary>
27
   /// GMap.NET control for Windows Presentation
28
   /// </summary>
29
   public partial class GMapControl : ItemsControl, Interface, IDisposable
30
   {
31
      #region DependencyProperties and related stuff
32
 
33
      public System.Windows.Point MapPoint
34
      {
35
         get
36
         {
37
            return (System.Windows.Point)GetValue(MapPointProperty);
38
         }
39
         set
40
         {
41
            SetValue(MapPointProperty, value);
42
         }
43
      }
44
 
45
 
46
      // Using a DependencyProperty as the backing store for point.  This enables animation, styling, binding, etc...
47
      public static readonly DependencyProperty MapPointProperty =
48
             DependencyProperty.Register("MapPoint", typeof(System.Windows.Point), typeof(GMapControl), new PropertyMetadata(new Point(), OnMapPointPropertyChanged));
49
 
50
 
51
      private static void OnMapPointPropertyChanged(DependencyObject source,
52
      DependencyPropertyChangedEventArgs e)
53
      {
54
         Point temp = (Point)e.NewValue;
55
         (source as GMapControl).Position = new PointLatLng(temp.X, temp.Y);
56
      }
57
 
58
      public static readonly DependencyProperty MapProviderProperty = DependencyProperty.Register("MapProvider", typeof(GMapProvider), typeof(GMapControl), new UIPropertyMetadata(EmptyProvider.Instance, new PropertyChangedCallback(MapProviderPropertyChanged)));
59
 
60
      /// <summary>
61
      /// type of map
62
      /// </summary>
63
      [Browsable(false)]
64
      public GMapProvider MapProvider
65
      {
66
         get
67
         {
68
            return GetValue(MapProviderProperty) as GMapProvider;
69
         }
70
         set
71
         {
72
            SetValue(MapProviderProperty, value);
73
         }
74
      }
75
 
76
      private static void MapProviderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
77
      {
78
         GMapControl map = (GMapControl)d;
79
         if(map != null && e.NewValue != null)
80
         {
81
            Debug.WriteLine("MapType: " + e.OldValue + " -> " + e.NewValue);
82
 
83
            RectLatLng viewarea = map.SelectedArea;
84
            if(viewarea != RectLatLng.Empty)
85
            {
86
               map.Position = new PointLatLng(viewarea.Lat - viewarea.HeightLat / 2, viewarea.Lng + viewarea.WidthLng / 2);
87
            }
88
            else
89
            {
90
               viewarea = map.ViewArea;
91
            }
92
 
93
            map.Core.Provider = e.NewValue as GMapProvider;
94
 
95
            map.Copyright = null;
96
            if(!string.IsNullOrEmpty(map.Core.Provider.Copyright))
97
            {
98
               map.Copyright = new FormattedText(map.Core.Provider.Copyright, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface("GenericSansSerif"), 9, Brushes.Navy);
99
            }
100
 
101
            if(map.Core.IsStarted && map.Core.zoomToArea)
102
            {
103
               // restore zoomrect as close as possible
104
               if(viewarea != RectLatLng.Empty && viewarea != map.ViewArea)
105
               {
106
                  int bestZoom = map.Core.GetMaxZoomToFitRect(viewarea);
107
                  if(bestZoom > 0 && map.Zoom != bestZoom)
108
                  {
109
                     map.Zoom = bestZoom;
110
                  }
111
               }
112
            }
113
         }
114
      }
115
 
116
      public static readonly DependencyProperty ZoomProperty = DependencyProperty.Register("Zoom", typeof(double), typeof(GMapControl), new UIPropertyMetadata(0.0, new PropertyChangedCallback(ZoomPropertyChanged), new CoerceValueCallback(OnCoerceZoom)));
117
 
118
      /// <summary>
119
      /// map zoom
120
      /// </summary>
121
      [Category("GMap.NET")]
122
      public double Zoom
123
      {
124
         get
125
         {
126
            return (double)(GetValue(ZoomProperty));
127
         }
128
         set
129
         {
130
            SetValue(ZoomProperty, value);
131
         }
132
      }
133
 
134
      private static object OnCoerceZoom(DependencyObject o, object value)
135
      {
136
         GMapControl map = o as GMapControl;
137
         if(map != null)
138
         {
139
            double result = (double)value;
140
            if(result > map.MaxZoom)
141
            {
142
               result = map.MaxZoom;
143
            }
144
            if(result < map.MinZoom)
145
            {
146
               result = map.MinZoom;
147
            }
148
 
149
            return result;
150
         }
151
         else
152
         {
153
            return value;
154
         }
155
      }
156
 
157
      private ScaleModes scaleMode = ScaleModes.Integer;
158
 
159
      /// <summary>
160
      /// Specifies, if a floating map scale is displayed using a 
161
      /// stretched, or a narrowed map.
162
      /// If <code>ScaleMode</code> is <code>ScaleDown</code>,
163
      /// then a scale of 12.3 is displayed using a map zoom level of 13
164
      /// resized to the lower level. If the parameter is <code>ScaleUp</code> ,
165
      /// then the same scale is displayed using a zoom level of 12 with an
166
      /// enlarged scale. If the value is <code>Dynamic</code>, then until a
167
      /// remainder of 0.25 <code>ScaleUp</code> is applied, for bigger
168
      /// remainders <code>ScaleDown</code>.
169
      /// </summary>
170
      [Category("GMap.NET")]
171
      [Description("map scale type")]
172
      public ScaleModes ScaleMode
173
      {
174
         get
175
         {
176
            return scaleMode;
177
         }
178
         set
179
         {
180
            scaleMode = value;
181
            InvalidateVisual();
182
         }
183
      }
184
 
185
      private static void ZoomPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
186
      {
187
         GMapControl map = (GMapControl)d;
188
         if(map != null && map.MapProvider.Projection != null)
189
         {
190
            double value = (double)e.NewValue;
191
 
192
            Debug.WriteLine("Zoom: " + e.OldValue + " -> " + value);
193
 
194
            double remainder = value % 1;
195
            if(map.ScaleMode != ScaleModes.Integer && remainder != 0 && map.ActualWidth > 0)
196
            {
197
               bool scaleDown;
198
 
199
               switch(map.ScaleMode)
200
               {
201
                  case ScaleModes.ScaleDown:
202
                  scaleDown = true;
203
                  break;
204
 
205
                  case ScaleModes.Dynamic:
206
                  scaleDown = remainder > 0.25;
207
                  break;
208
 
209
                  default:
210
                  scaleDown = false;
211
                  break;
212
               }
213
 
214
               if(scaleDown)
215
                  remainder--;
216
 
217
               double scaleValue = Math.Pow(2d, remainder);
218
               {
219
                  if(map.MapScaleTransform == null)
220
                  {
221
                     map.MapScaleTransform = map.lastScaleTransform;
222
                  }
223
                  map.MapScaleTransform.ScaleX = scaleValue;
224
                  map.MapScaleTransform.ScaleY = scaleValue;
225
 
226
                  map.Core.scaleX = 1 / scaleValue;
227
                  map.Core.scaleY = 1 / scaleValue;
228
 
229
                  map.MapScaleTransform.CenterX = map.ActualWidth / 2;
230
                  map.MapScaleTransform.CenterY = map.ActualHeight / 2;
231
               }
232
 
233
               map.Core.Zoom = Convert.ToInt32(scaleDown ? Math.Ceiling(value) : value - remainder);
234
            }
235
            else
236
            {
237
               map.MapScaleTransform = null;
238
               map.Core.scaleX = 1;
239
               map.Core.scaleY = 1;
240
               map.Core.Zoom = (int)Math.Floor(value);
241
            }
242
 
243
            if(map.IsLoaded)
244
            {
245
               map.ForceUpdateOverlays();
246
               map.InvalidateVisual(true);
247
            }
248
         }
249
      }
250
 
251
      readonly ScaleTransform lastScaleTransform = new ScaleTransform();
252
 
253
      #endregion
254
 
255
      readonly Core Core = new Core();
256
      //GRect region;
257
      delegate void MethodInvoker();
258
      PointLatLng selectionStart;
259
      PointLatLng selectionEnd;
260
      Typeface tileTypeface = new Typeface("Arial");
261
      bool showTileGridLines = false;
262
 
263
      FormattedText Copyright;
264
 
265
      /// <summary>
266
      /// enables filling empty tiles using lower level images
267
      /// </summary>
268
      [Browsable(false)]
269
      public bool FillEmptyTiles
270
      {
271
         get
272
         {
273
            return Core.fillEmptyTiles;
274
         }
275
         set
276
         {
277
            Core.fillEmptyTiles = value;
278
         }
279
      }
280
 
281
      /// <summary>
282
      /// max zoom
283
      /// </summary>         
284
      [Category("GMap.NET")]
285
      [Description("maximum zoom level of map")]
286
      public int MaxZoom
287
      {
288
         get
289
         {
290
            return Core.maxZoom;
291
         }
292
         set
293
         {
294
            Core.maxZoom = value;
295
         }
296
      }
297
 
298
      /// <summary>
299
      /// min zoom
300
      /// </summary>      
301
      [Category("GMap.NET")]
302
      [Description("minimum zoom level of map")]
303
      public int MinZoom
304
      {
305
         get
306
         {
307
            return Core.minZoom;
308
         }
309
         set
310
         {
311
            Core.minZoom = value;
312
         }
313
      }
314
 
315
      /// <summary>
316
      /// pen for empty tile borders
317
      /// </summary>
318
      public Pen EmptyTileBorders = new Pen(Brushes.White, 1.0);
319
 
320
      /// <summary>
321
      /// pen for Selection
322
      /// </summary>
323
      public Pen SelectionPen = new Pen(Brushes.Blue, 2.0);
324
 
325
      /// <summary>
326
      /// background of selected area
327
      /// </summary>
328
      public Brush SelectedAreaFill = new SolidColorBrush(Color.FromArgb(33, Colors.RoyalBlue.R, Colors.RoyalBlue.G, Colors.RoyalBlue.B));
329
 
330
      /// <summary>
331
      /// /// <summary>
332
      /// pen for empty tile background
333
      /// </summary>
334
      public Brush EmptytileBrush = Brushes.Navy;
335
 
336
      /// <summary>
337
      /// text on empty tiles
338
      /// </summary>
339
      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.Blue);
340
 
341
      /// <summary>
342
      /// map zooming type for mouse wheel
343
      /// </summary>
344
      [Category("GMap.NET")]
345
      [Description("map zooming type for mouse wheel")]
346
      public MouseWheelZoomType MouseWheelZoomType
347
      {
348
         get
349
         {
350
            return Core.MouseWheelZoomType;
351
         }
352
         set
353
         {
354
            Core.MouseWheelZoomType = value;
355
         }
356
      }
357
 
358
              /// <summary>
359
        /// enable map zoom on mouse wheel
360
        /// </summary>
361
        [Category("GMap.NET")]
362
        [Description("enable map zoom on mouse wheel")]
363
        public bool MouseWheelZoomEnabled
364
        {
365
            get
366
            {
367
                return Core.MouseWheelZoomEnabled;
368
            }
369
            set
370
            {
371
                Core.MouseWheelZoomEnabled = value;
372
            }
373
        }
374
 
375
      /// <summary>
376
      /// map dragg button
377
      /// </summary>
378
      [Category("GMap.NET")]
379
      public MouseButton DragButton = MouseButton.Right;
380
 
381
      /// <summary>
382
      /// use circle for selection
383
      /// </summary>
384
      public bool SelectionUseCircle = false;
385
 
386
      /// <summary>
387
      /// shows tile gridlines
388
      /// </summary>
389
      [Category("GMap.NET")]
390
      public bool ShowTileGridLines
391
      {
392
         get
393
         {
394
            return showTileGridLines;
395
         }
396
         set
397
         {
398
            showTileGridLines = value;
399
            InvalidateVisual();
400
         }
401
      }
402
 
403
      /// <summary>
404
      /// retry count to get tile 
405
      /// </summary>
406
      [Browsable(false)]
407
      public int RetryLoadTile
408
      {
409
         get
410
         {
411
            return Core.RetryLoadTile;
412
         }
413
         set
414
         {
415
            Core.RetryLoadTile = value;
416
         }
417
      }
418
 
419
      /// <summary>
420
      /// how many levels of tiles are staying decompresed in memory
421
      /// </summary>
422
      [Browsable(false)]
423
      public int LevelsKeepInMemmory
424
      {
425
         get
426
         {
427
            return Core.LevelsKeepInMemmory;
428
         }
429
 
430
         set
431
         {
432
            Core.LevelsKeepInMemmory = value;
433
         }
434
      }
435
 
436
      /// <summary>
437
      /// current selected area in map
438
      /// </summary>
439
      private RectLatLng selectedArea;
440
 
441
      [Browsable(false)]
442
      public RectLatLng SelectedArea
443
      {
444
         get
445
         {
446
            return selectedArea;
447
         }
448
         set
449
         {
450
            selectedArea = value;
451
            InvalidateVisual();
452
         }
453
      }
454
 
455
      /// <summary>
456
      /// is touch control enabled
457
      /// </summary>
458
      public bool TouchEnabled = true;
459
 
460
      /// <summary>
461
      /// map boundaries
462
      /// </summary>
463
      public RectLatLng? BoundsOfMap = null;
464
 
465
      /// <summary>
466
      /// occurs when mouse selection is changed
467
      /// </summary>        
468
      public event SelectionChange OnSelectionChange;
469
 
470
      /// <summary>
471
      /// list of markers
472
      /// </summary>
473
      public readonly ObservableCollection<GMapMarker> Markers = new ObservableCollection<GMapMarker>();
474
 
475
      /// <summary>
476
      /// current markers overlay offset
477
      /// </summary>
478
      internal readonly TranslateTransform MapTranslateTransform = new TranslateTransform();
479
      internal readonly TranslateTransform MapOverlayTranslateTransform = new TranslateTransform();
480
 
481
      internal ScaleTransform MapScaleTransform = new ScaleTransform();
482
      internal RotateTransform MapRotateTransform = new RotateTransform();
483
 
484
      protected bool DesignModeInConstruct
485
      {
486
         get
487
         {
488
            return System.ComponentModel.DesignerProperties.GetIsInDesignMode(this);
489
         }
490
      }
491
 
492
      Canvas mapCanvas = null;
493
 
494
      /// <summary>
495
      /// markers overlay
496
      /// </summary>
497
      internal Canvas MapCanvas
498
      {
499
         get
500
         {
501
            if(mapCanvas == null)
502
            {
503
               if(this.VisualChildrenCount > 0)
504
               {
505
                  Border border = VisualTreeHelper.GetChild(this, 0) as Border;
506
                  ItemsPresenter items = border.Child as ItemsPresenter;
507
                  DependencyObject target = VisualTreeHelper.GetChild(items, 0);
508
                  mapCanvas = target as Canvas;
509
 
510
                  mapCanvas.RenderTransform = MapTranslateTransform;
511
               }
512
            }
513
 
514
            return mapCanvas;
515
         }
516
      }
517
 
518
      public GMaps Manager
519
      {
520
         get
521
         {
522
            return GMaps.Instance;
523
         }
524
      }
525
 
526
      static DataTemplate DataTemplateInstance;
527
      static ItemsPanelTemplate ItemsPanelTemplateInstance;
528
      static Style StyleInstance;
529
 
530
      public GMapControl()
531
      {
532
         if(!DesignModeInConstruct)
533
         {
534
            #region -- templates --
535
 
536
            #region -- xaml --
537
            //  <ItemsControl Name="figures">
538
            //    <ItemsControl.ItemTemplate>
539
            //        <DataTemplate>
540
            //            <ContentPresenter Content="{Binding Path=Shape}" />
541
            //        </DataTemplate>
542
            //    </ItemsControl.ItemTemplate>
543
            //    <ItemsControl.ItemsPanel>
544
            //        <ItemsPanelTemplate>
545
            //            <Canvas />
546
            //        </ItemsPanelTemplate>
547
            //    </ItemsControl.ItemsPanel>
548
            //    <ItemsControl.ItemContainerStyle>
549
            //        <Style>
550
            //            <Setter Property="Canvas.Left" Value="{Binding Path=LocalPositionX}"/>
551
            //            <Setter Property="Canvas.Top" Value="{Binding Path=LocalPositionY}"/>
552
            //        </Style>
553
            //    </ItemsControl.ItemContainerStyle>
554
            //</ItemsControl> 
555
            #endregion
556
 
557
            if(DataTemplateInstance == null)
558
            {
559
               DataTemplateInstance = new DataTemplate(typeof(GMapMarker));
560
               {
561
                  FrameworkElementFactory fef = new FrameworkElementFactory(typeof(ContentPresenter));
562
                  fef.SetBinding(ContentPresenter.ContentProperty, new Binding("Shape"));
563
                  DataTemplateInstance.VisualTree = fef;
564
               }
565
            }
566
            ItemTemplate = DataTemplateInstance;
567
 
568
            if(ItemsPanelTemplateInstance == null)
569
            {
570
               var factoryPanel = new FrameworkElementFactory(typeof(Canvas));
571
               {
572
                  factoryPanel.SetValue(Canvas.IsItemsHostProperty, true);
573
 
574
                  ItemsPanelTemplateInstance = new ItemsPanelTemplate();
575
                  {
576
                     ItemsPanelTemplateInstance.VisualTree = factoryPanel;
577
                  }
578
               }
579
            }
580
            ItemsPanel = ItemsPanelTemplateInstance;
581
 
582
            if(StyleInstance == null)
583
            {
584
               StyleInstance = new Style();
585
               {
586
                  StyleInstance.Setters.Add(new Setter(Canvas.LeftProperty, new Binding("LocalPositionX")));
587
                  StyleInstance.Setters.Add(new Setter(Canvas.TopProperty, new Binding("LocalPositionY")));
588
                  StyleInstance.Setters.Add(new Setter(Canvas.ZIndexProperty, new Binding("ZIndex")));
589
               }
590
            }
591
            ItemContainerStyle = StyleInstance;
592
            #endregion
593
 
594
            ClipToBounds = true;
595
            SnapsToDevicePixels = true;
596
 
597
            Core.SystemType = "WindowsPresentation";
598
 
599
            Core.RenderMode = GMap.NET.RenderMode.WPF;
600
 
601
            Core.OnMapZoomChanged += new MapZoomChanged(ForceUpdateOverlays);
602
            Loaded += new RoutedEventHandler(GMapControl_Loaded);
603
            Dispatcher.ShutdownStarted += new EventHandler(Dispatcher_ShutdownStarted);
604
            SizeChanged += new SizeChangedEventHandler(GMapControl_SizeChanged);
605
 
606
            // by default its internal property, feel free to use your own
607
            if(ItemsSource == null)
608
            {
609
               ItemsSource = Markers;
610
            }
611
 
612
            Core.Zoom = (int)((double)ZoomProperty.DefaultMetadata.DefaultValue);
613
         }
614
      }
615
 
616
      static GMapControl()
617
      {
618
         GMapImageProxy.Enable();
619
#if !PocketPC
620
         GMaps.Instance.SQLitePing();
621
#endif
622
      }
623
 
624
      void invalidatorEngage(object sender, ProgressChangedEventArgs e)
625
      {
626
         base.InvalidateVisual();
627
      }
628
 
629
      /// <summary>
630
      /// enque built-in thread safe invalidation
631
      /// </summary>
632
      public new void InvalidateVisual()
633
      {
634
         if(Core.Refresh != null)
635
         {
636
            Core.Refresh.Set();
637
         }
638
      }
639
 
640
      /// <summary>
641
      /// Invalidates the rendering of the element, and forces a complete new layout
642
      /// pass. System.Windows.UIElement.OnRender(System.Windows.Media.DrawingContext)
643
      /// is called after the layout cycle is completed. If not forced enques built-in thread safe invalidation
644
      /// </summary>
645
      /// <param name="forced"></param>
646
      public void InvalidateVisual(bool forced)
647
      {
648
         if(forced)
649
         {
650
            lock(Core.invalidationLock)
651
            {
652
               Core.lastInvalidation = DateTime.Now;
653
            }
654
            base.InvalidateVisual();
655
         }
656
         else
657
         {
658
            InvalidateVisual();
659
         }
660
      }
661
 
662
      protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
663
      {
664
         base.OnItemsChanged(e);
665
 
666
         if(e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
667
         {
668
             ForceUpdateOverlays(e.NewItems);
669
         }
670
         else
671
         {
672
             InvalidateVisual();
673
         }
674
      }
675
 
676
      /// <summary>
677
      /// inits core system
678
      /// </summary>
679
      /// <param name="sender"></param>
680
      /// <param name="e"></param>
681
      void GMapControl_Loaded(object sender, RoutedEventArgs e)
682
      {
683
         if(!Core.IsStarted)
684
         {
685
            if(lazyEvents)
686
            {
687
               lazyEvents = false;
688
 
689
               if(lazySetZoomToFitRect.HasValue)
690
               {
691
                  SetZoomToFitRect(lazySetZoomToFitRect.Value);
692
                  lazySetZoomToFitRect = null;
693
               }
694
            }
695
            Core.OnMapOpen().ProgressChanged += new ProgressChangedEventHandler(invalidatorEngage);
696
            ForceUpdateOverlays();
697
 
698
            if(Application.Current != null)
699
            {
700
               loadedApp = Application.Current;
701
 
702
               loadedApp.Dispatcher.Invoke(DispatcherPriority.ApplicationIdle,
703
                  new Action(delegate()
704
                  {
705
                     loadedApp.SessionEnding += new SessionEndingCancelEventHandler(Current_SessionEnding);
706
                  }
707
                  ));
708
            }
709
         }
710
      }
711
 
712
      Application loadedApp;
713
 
714
      void Current_SessionEnding(object sender, SessionEndingCancelEventArgs e)
715
      {
716
         GMaps.Instance.CancelTileCaching();
717
      }
718
 
719
      void Dispatcher_ShutdownStarted(object sender, EventArgs e)
720
      {
721
         Dispose();
722
      }
723
 
724
      /// <summary>
725
      /// recalculates size
726
      /// </summary>
727
      /// <param name="sender"></param>
728
      /// <param name="e"></param>
729
      void GMapControl_SizeChanged(object sender, SizeChangedEventArgs e)
730
      {
731
         System.Windows.Size constraint = e.NewSize;
732
 
733
         // 50px outside control
734
         //region = new GRect(-50, -50, (int)constraint.Width + 100, (int)constraint.Height + 100);
735
 
736
         Core.OnMapSizeChanged((int)constraint.Width, (int)constraint.Height);
737
 
738
         if(Core.IsStarted)
739
         {
740
            if(IsRotated)
741
            {
742
               UpdateRotationMatrix();
743
            }
744
 
745
            ForceUpdateOverlays();
746
         }
747
      }
748
 
749
      void ForceUpdateOverlays()
750
      {
751
          ForceUpdateOverlays(ItemsSource);          
752
      }
753
 
754
      void ForceUpdateOverlays(System.Collections.IEnumerable items)
755
      {
756
         using(Dispatcher.DisableProcessing())
757
         {
758
            UpdateMarkersOffset();
759
 
760
            foreach(GMapMarker i in items)
761
            {
762
               if(i != null)
763
               {
764
                  i.ForceUpdateLocalPosition(this);
765
 
766
                  if(i is IShapable)
767
                  {
768
                     (i as IShapable).RegenerateShape(this);
769
                  }
770
               }
771
            }
772
         }
773
         InvalidateVisual();
774
      }
775
 
776
      /// <summary>
777
      /// updates markers overlay offset
778
      /// </summary>
779
      void UpdateMarkersOffset()
780
      {
781
         if(MapCanvas != null)
782
         {
783
            if(MapScaleTransform != null)
784
            {
785
               var tp = MapScaleTransform.Transform(new System.Windows.Point(Core.renderOffset.X, Core.renderOffset.Y));
786
               MapOverlayTranslateTransform.X = tp.X;
787
               MapOverlayTranslateTransform.Y = tp.Y;
788
 
789
               // map is scaled already
790
               MapTranslateTransform.X = Core.renderOffset.X;
791
               MapTranslateTransform.Y = Core.renderOffset.Y;
792
            }
793
            else
794
            {
795
               MapTranslateTransform.X = Core.renderOffset.X;
796
               MapTranslateTransform.Y = Core.renderOffset.Y;
797
 
798
               MapOverlayTranslateTransform.X = MapTranslateTransform.X;
799
               MapOverlayTranslateTransform.Y = MapTranslateTransform.Y;
800
            }
801
         }
802
      }
803
 
804
      public Brush EmptyMapBackground = Brushes.WhiteSmoke;
805
 
806
      /// <summary>
807
      /// render map in WPF
808
      /// </summary>
809
      /// <param name="g"></param>
810
      void DrawMap(DrawingContext g)
811
      {
812
         if(MapProvider == EmptyProvider.Instance || MapProvider == null)
813
         {
814
            return;
815
         }
816
 
817
         Core.tileDrawingListLock.AcquireReaderLock();
818
         Core.Matrix.EnterReadLock();
819
         try
820
         {
821
            foreach(var tilePoint in Core.tileDrawingList)
822
            {
823
               Core.tileRect.Location = tilePoint.PosPixel;
824
               Core.tileRect.OffsetNegative(Core.compensationOffset);
825
 
826
               //if(region.IntersectsWith(Core.tileRect) || IsRotated)
827
               {
828
                  bool found = false;
829
 
830
                  Tile t = Core.Matrix.GetTileWithNoLock(Core.Zoom, tilePoint.PosXY);
831
                  if(t.NotEmpty)
832
                  {
833
                     foreach(GMapImage img in t.Overlays)
834
                     {
835
                        if(img != null && img.Img != null)
836
                        {
837
                           if(!found)
838
                              found = true;
839
 
840
                           var imgRect = new Rect(Core.tileRect.X + 0.6, Core.tileRect.Y + 0.6, Core.tileRect.Width + 0.6, Core.tileRect.Height + 0.6);
841
                           if(!img.IsParent)
842
                           {
843
                              g.DrawImage(img.Img, imgRect);
844
                           }
845
                           else
846
                           {
847
                              // TODO: move calculations to loader thread
848
                              var geometry = new RectangleGeometry(imgRect);
849
                              var parentImgRect = new Rect(Core.tileRect.X - Core.tileRect.Width * img.Xoff + 0.6, Core.tileRect.Y - Core.tileRect.Height * img.Yoff + 0.6, Core.tileRect.Width * img.Ix + 0.6, Core.tileRect.Height * img.Ix + 0.6);
850
 
851
                              g.PushClip(geometry);
852
                              g.DrawImage(img.Img, parentImgRect);
853
                              g.Pop();
854
                              geometry = null;
855
                           }
856
                        }
857
                     }
858
                  }
859
                  else if(FillEmptyTiles && MapProvider.Projection is MercatorProjection)
860
                  {
861
                     #region -- fill empty tiles --
862
                     int zoomOffset = 1;
863
                     Tile parentTile = Tile.Empty;
864
                     long Ix = 0;
865
 
866
                     while(!parentTile.NotEmpty && zoomOffset < Core.Zoom && zoomOffset <= LevelsKeepInMemmory)
867
                     {
868
                        Ix = (long)Math.Pow(2, zoomOffset);
869
                        parentTile = Core.Matrix.GetTileWithNoLock(Core.Zoom - zoomOffset++, new GMap.NET.GPoint((int)(tilePoint.PosXY.X / Ix), (int)(tilePoint.PosXY.Y / Ix)));
870
                     }
871
 
872
                     if(parentTile.NotEmpty)
873
                     {
874
                        long Xoff = Math.Abs(tilePoint.PosXY.X - (parentTile.Pos.X * Ix));
875
                        long Yoff = Math.Abs(tilePoint.PosXY.Y - (parentTile.Pos.Y * Ix));
876
 
877
                        var geometry = new RectangleGeometry(new Rect(Core.tileRect.X + 0.6, Core.tileRect.Y + 0.6, Core.tileRect.Width + 0.6, Core.tileRect.Height + 0.6));
878
                        var parentImgRect = new Rect(Core.tileRect.X - Core.tileRect.Width * Xoff + 0.6, Core.tileRect.Y - Core.tileRect.Height * Yoff + 0.6, Core.tileRect.Width * Ix + 0.6, Core.tileRect.Height * Ix + 0.6);
879
 
880
                        // render tile 
881
                        {
882
                           foreach(GMapImage img in parentTile.Overlays)
883
                           {
884
                              if(img != null && img.Img != null && !img.IsParent)
885
                              {
886
                                 if(!found)
887
                                    found = true;
888
 
889
                                 g.PushClip(geometry);
890
                                 g.DrawImage(img.Img, parentImgRect);
891
                                 g.DrawRectangle(SelectedAreaFill, null, geometry.Bounds);
892
                                 g.Pop();
893
                              }
894
                           }
895
                        }
896
 
897
                        geometry = null;
898
                     }
899
                     #endregion
900
                  }
901
 
902
                  // add text if tile is missing
903
                  if(!found)
904
                  {
905
                     lock(Core.FailedLoads)
906
                     {
907
                        var lt = new LoadTask(tilePoint.PosXY, Core.Zoom);
908
 
909
                        if(Core.FailedLoads.ContainsKey(lt))
910
                        {
911
                           g.DrawRectangle(EmptytileBrush, EmptyTileBorders, new Rect(Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height));
912
 
913
                           var ex = Core.FailedLoads[lt];
914
                           FormattedText TileText = new FormattedText("Exception: " + ex.Message, System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, tileTypeface, 14, Brushes.Red);
915
                           TileText.MaxTextWidth = Core.tileRect.Width - 11;
916
 
917
                           g.DrawText(TileText, new System.Windows.Point(Core.tileRect.X + 11, Core.tileRect.Y + 11));
918
 
919
                           g.DrawText(EmptyTileText, new System.Windows.Point(Core.tileRect.X + Core.tileRect.Width / 2 - EmptyTileText.Width / 2, Core.tileRect.Y + Core.tileRect.Height / 2 - EmptyTileText.Height / 2));
920
                        }
921
                     }
922
                  }
923
 
924
                  if(ShowTileGridLines)
925
                  {
926
                     g.DrawRectangle(null, EmptyTileBorders, new Rect(Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height));
927
 
928
                     if(tilePoint.PosXY == Core.centerTileXYLocation)
929
                     {
930
                        FormattedText TileText = new FormattedText("CENTER:" + tilePoint.ToString(), System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, tileTypeface, 16, Brushes.Red);
931
                        TileText.MaxTextWidth = Core.tileRect.Width;
932
                        g.DrawText(TileText, new System.Windows.Point(Core.tileRect.X + Core.tileRect.Width / 2 - EmptyTileText.Width / 2, Core.tileRect.Y + Core.tileRect.Height / 2 - TileText.Height / 2));
933
                     }
934
                     else
935
                     {
936
                        FormattedText TileText = new FormattedText("TILE: " + tilePoint.ToString(), System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, tileTypeface, 16, Brushes.Red);
937
                        TileText.MaxTextWidth = Core.tileRect.Width;
938
                        g.DrawText(TileText, new System.Windows.Point(Core.tileRect.X + Core.tileRect.Width / 2 - EmptyTileText.Width / 2, Core.tileRect.Y + Core.tileRect.Height / 2 - TileText.Height / 2));
939
                     }
940
                  }
941
               }
942
            }
943
         }
944
         finally
945
         {
946
            Core.Matrix.LeaveReadLock();
947
            Core.tileDrawingListLock.ReleaseReaderLock();
948
         }
949
      }
950
 
951
      /// <summary>
952
      /// gets image of the current view
953
      /// </summary>
954
      /// <returns></returns>
955
      public ImageSource ToImageSource()
956
      {
957
         FrameworkElement obj = this;
958
 
959
         // Save current canvas transform
960
         Transform transform = obj.LayoutTransform;
961
         obj.LayoutTransform = null;
962
 
963
         // fix margin offset as well
964
         Thickness margin = obj.Margin;
965
         obj.Margin = new Thickness(0, 0,
966
         margin.Right - margin.Left, margin.Bottom - margin.Top);
967
 
968
         // Get the size of canvas
969
         Size size = new Size(obj.ActualWidth, obj.ActualHeight);
970
 
971
         // force control to Update
972
         obj.Measure(size);
973
         obj.Arrange(new Rect(size));
974
 
975
         RenderTargetBitmap bmp = new RenderTargetBitmap(
976
         (int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32);
977
 
978
         bmp.Render(obj);
979
 
980
         if(bmp.CanFreeze)
981
         {
982
            bmp.Freeze();
983
         }
984
 
985
         // return values as they were before
986
         obj.LayoutTransform = transform;
987
         obj.Margin = margin;
988
 
989
         return bmp;
990
      }
991
 
992
      /// <summary>
993
      /// creates path from list of points, for performance set addBlurEffect to false
994
      /// </summary>
995
      /// <param name="pl"></param>
996
      /// <returns></returns>
997
      public virtual Path CreateRoutePath(List<Point> localPath)
998
      {
999
         return CreateRoutePath(localPath, true);
1000
      }
1001
 
1002
      /// <summary>
1003
      /// creates path from list of points, for performance set addBlurEffect to false
1004
      /// </summary>
1005
      /// <param name="pl"></param>
1006
      /// <returns></returns>
1007
      public virtual Path CreateRoutePath(List<Point> localPath, bool addBlurEffect)
1008
      {
1009
         // Create a StreamGeometry to use to specify myPath.
1010
         StreamGeometry geometry = new StreamGeometry();
1011
 
1012
         using(StreamGeometryContext ctx = geometry.Open())
1013
         {
1014
            ctx.BeginFigure(localPath[0], false, false);
1015
 
1016
            // Draw a line to the next specified point.
1017
            ctx.PolyLineTo(localPath, true, true);
1018
         }
1019
 
1020
         // Freeze the geometry (make it unmodifiable)
1021
         // for additional performance benefits.
1022
         geometry.Freeze();
1023
 
1024
         // Create a path to draw a geometry with.
1025
         Path myPath = new Path();
1026
         {
1027
            // Specify the shape of the Path using the StreamGeometry.
1028
            myPath.Data = geometry;
1029
 
1030
            if (addBlurEffect)
1031
            {
1032
                BlurEffect ef = new BlurEffect();
1033
                {
1034
                    ef.KernelType = KernelType.Gaussian;
1035
                    ef.Radius = 3.0;
1036
                    ef.RenderingBias = RenderingBias.Performance;
1037
                }
1038
 
1039
                myPath.Effect = ef;
1040
            }
1041
 
1042
            myPath.Stroke = Brushes.Navy;
1043
            myPath.StrokeThickness = 5;
1044
            myPath.StrokeLineJoin = PenLineJoin.Round;
1045
            myPath.StrokeStartLineCap = PenLineCap.Triangle;
1046
            myPath.StrokeEndLineCap = PenLineCap.Square;
1047
 
1048
            myPath.Opacity = 0.6;
1049
            myPath.IsHitTestVisible = false;
1050
         }
1051
         return myPath;
1052
      }
1053
 
1054
      /// <summary>
1055
      /// creates path from list of points, for performance set addBlurEffect to false
1056
      /// </summary>
1057
      /// <param name="pl"></param>
1058
      /// <returns></returns>
1059
      public virtual Path CreatePolygonPath(List<Point> localPath)
1060
      {
1061
         return CreatePolygonPath(localPath, false);
1062
      }
1063
 
1064
      /// <summary>
1065
      /// creates path from list of points, for performance set addBlurEffect to false
1066
      /// </summary>
1067
      /// <param name="pl"></param>
1068
      /// <returns></returns>
1069
      public virtual Path CreatePolygonPath(List<Point> localPath, bool addBlurEffect)
1070
      {
1071
         // Create a StreamGeometry to use to specify myPath.
1072
         StreamGeometry geometry = new StreamGeometry();
1073
 
1074
         using(StreamGeometryContext ctx = geometry.Open())
1075
         {
1076
            ctx.BeginFigure(localPath[0], true, true);
1077
 
1078
            // Draw a line to the next specified point.
1079
            ctx.PolyLineTo(localPath, true, true);
1080
         }
1081
 
1082
         // Freeze the geometry (make it unmodifiable)
1083
         // for additional performance benefits.
1084
         geometry.Freeze();
1085
 
1086
         // Create a path to draw a geometry with.
1087
         Path myPath = new Path();
1088
         {
1089
            // Specify the shape of the Path using the StreamGeometry.
1090
            myPath.Data = geometry;
1091
 
1092
            if (addBlurEffect)
1093
            {
1094
                BlurEffect ef = new BlurEffect();
1095
                {
1096
                    ef.KernelType = KernelType.Gaussian;
1097
                    ef.Radius = 3.0;
1098
                    ef.RenderingBias = RenderingBias.Performance;
1099
                }
1100
 
1101
                myPath.Effect = ef;
1102
            }
1103
 
1104
            myPath.Stroke = Brushes.MidnightBlue;
1105
            myPath.StrokeThickness = 5;
1106
            myPath.StrokeLineJoin = PenLineJoin.Round;
1107
            myPath.StrokeStartLineCap = PenLineCap.Triangle;
1108
            myPath.StrokeEndLineCap = PenLineCap.Square;
1109
 
1110
            myPath.Fill = Brushes.AliceBlue;
1111
 
1112
            myPath.Opacity = 0.6;
1113
            myPath.IsHitTestVisible = false;
1114
         }
1115
         return myPath;
1116
      }
1117
 
1118
      /// <summary>
1119
      /// sets zoom to max to fit rect
1120
      /// </summary>
1121
      /// <param name="rect">area</param>
1122
      /// <returns></returns>
1123
      public bool SetZoomToFitRect(RectLatLng rect)
1124
      {
1125
         if(lazyEvents)
1126
         {
1127
            lazySetZoomToFitRect = rect;
1128
         }
1129
         else
1130
         {
1131
            int maxZoom = Core.GetMaxZoomToFitRect(rect);
1132
            if(maxZoom > 0)
1133
            {
1134
               PointLatLng center = new PointLatLng(rect.Lat - (rect.HeightLat / 2), rect.Lng + (rect.WidthLng / 2));
1135
               Position = center;
1136
 
1137
               if(maxZoom > MaxZoom)
1138
               {
1139
                  maxZoom = MaxZoom;
1140
               }
1141
 
1142
               if(Core.Zoom != maxZoom)
1143
               {
1144
                  Zoom = maxZoom;
1145
               }
1146
 
1147
               return true;
1148
            }
1149
         }
1150
         return false;
1151
      }
1152
 
1153
      RectLatLng? lazySetZoomToFitRect = null;
1154
      bool lazyEvents = true;
1155
 
1156
      /// <summary>
1157
      /// sets to max zoom to fit all markers and centers them in map
1158
      /// </summary>
1159
      /// <param name="ZIndex">z index or null to check all</param>
1160
      /// <returns></returns>
1161
      public bool ZoomAndCenterMarkers(int? ZIndex)
1162
      {
1163
         RectLatLng? rect = GetRectOfAllMarkers(ZIndex);
1164
         if(rect.HasValue)
1165
         {
1166
            return SetZoomToFitRect(rect.Value);
1167
         }
1168
 
1169
         return false;
1170
      }
1171
 
1172
      /// <summary>
1173
      /// gets rectangle with all objects inside
1174
      /// </summary>
1175
      /// <param name="ZIndex">z index or null to check all</param>
1176
      /// <returns></returns>
1177
      public RectLatLng? GetRectOfAllMarkers(int? ZIndex)
1178
      {
1179
         RectLatLng? ret = null;
1180
 
1181
         double left = double.MaxValue;
1182
         double top = double.MinValue;
1183
         double right = double.MinValue;
1184
         double bottom = double.MaxValue;
1185
         IEnumerable<GMapMarker> Overlays;
1186
 
1187
         if(ZIndex.HasValue)
1188
         {
1189
            Overlays = ItemsSource.Cast<GMapMarker>().Where(p => p != null && p.ZIndex == ZIndex);
1190
         }
1191
         else
1192
         {
1193
            Overlays = ItemsSource.Cast<GMapMarker>();
1194
         }
1195
 
1196
         if(Overlays != null)
1197
         {
1198
            foreach(var m in Overlays)
1199
            {
1200
               if(m.Shape != null && m.Shape.Visibility == System.Windows.Visibility.Visible)
1201
               {
1202
                  // left
1203
                  if(m.Position.Lng < left)
1204
                  {
1205
                     left = m.Position.Lng;
1206
                  }
1207
 
1208
                  // top
1209
                  if(m.Position.Lat > top)
1210
                  {
1211
                     top = m.Position.Lat;
1212
                  }
1213
 
1214
                  // right
1215
                  if(m.Position.Lng > right)
1216
                  {
1217
                     right = m.Position.Lng;
1218
                  }
1219
 
1220
                  // bottom
1221
                  if(m.Position.Lat < bottom)
1222
                  {
1223
                     bottom = m.Position.Lat;
1224
                  }
1225
               }
1226
            }
1227
         }
1228
 
1229
         if(left != double.MaxValue && right != double.MinValue && top != double.MinValue && bottom != double.MaxValue)
1230
         {
1231
            ret = RectLatLng.FromLTRB(left, top, right, bottom);
1232
         }
1233
 
1234
         return ret;
1235
      }
1236
 
1237
      /// <summary>
1238
      /// offset position in pixels
1239
      /// </summary>
1240
      /// <param name="x"></param>
1241
      /// <param name="y"></param>
1242
      public void Offset(int x, int y)
1243
      {
1244
         if(IsLoaded)
1245
         {
1246
            if(IsRotated)
1247
            {
1248
               Point p = new Point(x, y);
1249
               p = rotationMatrixInvert.Transform(p);
1250
               x = (int)p.X;
1251
               y = (int)p.Y;
1252
 
1253
               Core.DragOffset(new GPoint(x, y));
1254
 
1255
               ForceUpdateOverlays();
1256
            }
1257
            else
1258
            {
1259
               Core.DragOffset(new GPoint(x, y));
1260
 
1261
               UpdateMarkersOffset();
1262
               InvalidateVisual(true);
1263
            }
1264
         }
1265
      }
1266
 
1267
      readonly RotateTransform rotationMatrix = new RotateTransform();
1268
      GeneralTransform rotationMatrixInvert = new RotateTransform();
1269
 
1270
      /// <summary>
1271
      /// updates rotation matrix
1272
      /// </summary>
1273
      void UpdateRotationMatrix()
1274
      {
1275
         System.Windows.Point center = new System.Windows.Point(ActualWidth / 2.0, ActualHeight / 2.0);
1276
 
1277
         rotationMatrix.Angle = -Bearing;
1278
         rotationMatrix.CenterY = center.Y;
1279
         rotationMatrix.CenterX = center.X;
1280
 
1281
         rotationMatrixInvert = rotationMatrix.Inverse;
1282
      }
1283
 
1284
      /// <summary>
1285
      /// returs true if map bearing is not zero
1286
      /// </summary>         
1287
      public bool IsRotated
1288
      {
1289
         get
1290
         {
1291
            return Core.IsRotated;
1292
         }
1293
      }
1294
 
1295
      /// <summary>
1296
      /// bearing for rotation of the map
1297
      /// </summary>
1298
      [Category("GMap.NET")]
1299
      public float Bearing
1300
      {
1301
         get
1302
         {
1303
            return Core.bearing;
1304
         }
1305
         set
1306
         {
1307
            if(Core.bearing != value)
1308
            {
1309
               bool resize = Core.bearing == 0;
1310
               Core.bearing = value;
1311
 
1312
               UpdateRotationMatrix();
1313
 
1314
               if(value != 0 && value % 360 != 0)
1315
               {
1316
                  Core.IsRotated = true;
1317
 
1318
                  if(Core.tileRectBearing.Size == Core.tileRect.Size)
1319
                  {
1320
                     Core.tileRectBearing = Core.tileRect;
1321
                     Core.tileRectBearing.Inflate(1, 1);
1322
                  }
1323
               }
1324
               else
1325
               {
1326
                  Core.IsRotated = false;
1327
                  Core.tileRectBearing = Core.tileRect;
1328
               }
1329
 
1330
               if(resize)
1331
               {
1332
                  Core.OnMapSizeChanged((int)ActualWidth, (int)ActualHeight);
1333
               }
1334
 
1335
               if(Core.IsStarted)
1336
               {
1337
                  ForceUpdateOverlays();
1338
               }
1339
            }
1340
         }
1341
      }
1342
 
1343
      /// <summary>
1344
      /// apply transformation if in rotation mode
1345
      /// </summary>
1346
      System.Windows.Point ApplyRotation(double x, double y)
1347
      {
1348
         System.Windows.Point ret = new System.Windows.Point(x, y);
1349
 
1350
         if(IsRotated)
1351
         {
1352
            ret = rotationMatrix.Transform(ret);
1353
         }
1354
 
1355
         return ret;
1356
      }
1357
 
1358
      /// <summary>
1359
      /// apply transformation if in rotation mode
1360
      /// </summary>
1361
      System.Windows.Point ApplyRotationInversion(double x, double y)
1362
      {
1363
         System.Windows.Point ret = new System.Windows.Point(x, y);
1364
 
1365
         if(IsRotated)
1366
         {
1367
            ret = rotationMatrixInvert.Transform(ret);
1368
         }
1369
 
1370
         return ret;
1371
      }
1372
 
1373
      #region UserControl Events
1374
      protected override void OnRender(DrawingContext drawingContext)
1375
      {
1376
         if(!Core.IsStarted)
1377
            return;
1378
 
1379
         drawingContext.DrawRectangle(EmptyMapBackground, null, new Rect(RenderSize));
1380
 
1381
         if(IsRotated)
1382
         {
1383
            drawingContext.PushTransform(rotationMatrix);
1384
 
1385
            if(MapScaleTransform != null)
1386
            {
1387
               drawingContext.PushTransform(MapScaleTransform);
1388
               drawingContext.PushTransform(MapTranslateTransform);
1389
               {
1390
                  DrawMap(drawingContext);
1391
               }
1392
               drawingContext.Pop();
1393
               drawingContext.Pop();
1394
            }
1395
            else
1396
            {
1397
               drawingContext.PushTransform(MapTranslateTransform);
1398
               {
1399
                  DrawMap(drawingContext);
1400
               }
1401
               drawingContext.Pop();
1402
            }
1403
 
1404
            drawingContext.Pop();
1405
         }
1406
         else
1407
         {
1408
            if(MapScaleTransform != null)
1409
            {
1410
               drawingContext.PushTransform(MapScaleTransform);
1411
               drawingContext.PushTransform(MapTranslateTransform);
1412
               {
1413
                  DrawMap(drawingContext);
1414
 
1415
#if DEBUG
1416
                  drawingContext.DrawLine(VirtualCenterCrossPen, new Point(-20, 0), new Point(20, 0));
1417
                  drawingContext.DrawLine(VirtualCenterCrossPen, new Point(0, -20), new Point(0, 20));
1418
#endif
1419
               }
1420
               drawingContext.Pop();
1421
               drawingContext.Pop();
1422
            }
1423
            else
1424
            {
1425
               drawingContext.PushTransform(MapTranslateTransform);
1426
               {
1427
                  DrawMap(drawingContext);
1428
#if DEBUG
1429
                  drawingContext.DrawLine(VirtualCenterCrossPen, new Point(-20, 0), new Point(20, 0));
1430
                  drawingContext.DrawLine(VirtualCenterCrossPen, new Point(0, -20), new Point(0, 20));
1431
#endif
1432
               }
1433
               drawingContext.Pop();
1434
            }
1435
         }
1436
 
1437
         // selection
1438
         if(!SelectedArea.IsEmpty)
1439
         {
1440
            GPoint p1 = FromLatLngToLocal(SelectedArea.LocationTopLeft);
1441
            GPoint p2 = FromLatLngToLocal(SelectedArea.LocationRightBottom);
1442
 
1443
            long x1 = p1.X;
1444
            long y1 = p1.Y;
1445
            long x2 = p2.X;
1446
            long y2 = p2.Y;
1447
 
1448
            if(SelectionUseCircle)
1449
            {
1450
               drawingContext.DrawEllipse(SelectedAreaFill, SelectionPen, new System.Windows.Point(x1 + (x2 - x1) / 2, y1 + (y2 - y1) / 2), (x2 - x1) / 2, (y2 - y1) / 2);
1451
            }
1452
            else
1453
            {
1454
               drawingContext.DrawRoundedRectangle(SelectedAreaFill, SelectionPen, new Rect(x1, y1, x2 - x1, y2 - y1), 5, 5);
1455
            }
1456
         }
1457
 
1458
         if(ShowCenter)
1459
         {
1460
            drawingContext.DrawLine(CenterCrossPen, new System.Windows.Point((ActualWidth / 2) - 5, ActualHeight / 2), new System.Windows.Point((ActualWidth / 2) + 5, ActualHeight / 2));
1461
            drawingContext.DrawLine(CenterCrossPen, new System.Windows.Point(ActualWidth / 2, (ActualHeight / 2) - 5), new System.Windows.Point(ActualWidth / 2, (ActualHeight / 2) + 5));
1462
         }
1463
 
1464
         if(renderHelperLine)
1465
         {
1466
            var p = Mouse.GetPosition(this);
1467
 
1468
            drawingContext.DrawLine(HelperLinePen, new Point(p.X, 0), new Point(p.X, ActualHeight));
1469
            drawingContext.DrawLine(HelperLinePen, new Point(0, p.Y), new Point(ActualWidth, p.Y));
1470
         }
1471
 
1472
         #region -- copyright --
1473
 
1474
         if(Copyright != null)
1475
         {
1476
            drawingContext.DrawText(Copyright, new System.Windows.Point(5, ActualHeight - Copyright.Height - 5));
1477
         }
1478
 
1479
         #endregion
1480
 
1481
         base.OnRender(drawingContext);
1482
      }
1483
 
1484
      public Pen CenterCrossPen = new Pen(Brushes.Red, 1);
1485
      public bool ShowCenter = true;
1486
 
1487
#if DEBUG
1488
      readonly Pen VirtualCenterCrossPen = new Pen(Brushes.Blue, 1);
1489
#endif
1490
 
1491
      HelperLineOptions helperLineOption = HelperLineOptions.DontShow;
1492
 
1493
      /// <summary>
1494
      /// draw lines at the mouse pointer position
1495
      /// </summary>
1496
      [Browsable(false)]
1497
      public HelperLineOptions HelperLineOption
1498
      {
1499
         get
1500
         {
1501
            return helperLineOption;
1502
         }
1503
         set
1504
         {
1505
            helperLineOption = value;
1506
            renderHelperLine = (helperLineOption == HelperLineOptions.ShowAlways);
1507
            if(Core.IsStarted)
1508
            {
1509
               InvalidateVisual();
1510
            }
1511
         }
1512
      }
1513
 
1514
      public Pen HelperLinePen = new Pen(Brushes.Blue, 1);
1515
      bool renderHelperLine = false;
1516
 
1517
      protected override void OnKeyUp(KeyEventArgs e)
1518
      {
1519
         base.OnKeyUp(e);
1520
 
1521
         if(HelperLineOption == HelperLineOptions.ShowOnModifierKey)
1522
         {
1523
            renderHelperLine = !(e.IsUp && (e.Key == Key.LeftShift || e.SystemKey == Key.LeftAlt));
1524
            if(!renderHelperLine)
1525
            {
1526
               InvalidateVisual();
1527
            }
1528
         }        
1529
      }
1530
 
1531
      protected override void OnKeyDown(KeyEventArgs e)
1532
      {
1533
         base.OnKeyDown(e);
1534
 
1535
         if(HelperLineOption == HelperLineOptions.ShowOnModifierKey)
1536
         {
1537
            renderHelperLine = e.IsDown && (e.Key == Key.LeftShift || e.SystemKey == Key.LeftAlt);
1538
            if(renderHelperLine)
1539
            {
1540
               InvalidateVisual();
1541
            }
1542
         }        
1543
      }
1544
 
1545
      /// <summary>
1546
      /// reverses MouseWheel zooming direction
1547
      /// </summary>
1548
      public bool InvertedMouseWheelZooming = false;
1549
 
1550
      /// <summary>
1551
      /// lets you zoom by MouseWheel even when pointer is in area of marker
1552
      /// </summary>
1553
      public bool IgnoreMarkerOnMouseWheel = false;
1554
 
1555
      protected override void OnMouseWheel(MouseWheelEventArgs e)
1556
      {
1557
         base.OnMouseWheel(e);
1558
 
1559
         if(MouseWheelZoomEnabled && (IsMouseDirectlyOver || IgnoreMarkerOnMouseWheel) && !Core.IsDragging)
1560
         {
1561
            System.Windows.Point p = e.GetPosition(this);
1562
 
1563
            if(MapScaleTransform != null)
1564
            {
1565
               p = MapScaleTransform.Inverse.Transform(p);
1566
            }
1567
 
1568
            p = ApplyRotationInversion(p.X, p.Y);
1569
 
1570
            if(Core.mouseLastZoom.X != (int)p.X && Core.mouseLastZoom.Y != (int)p.Y)
1571
            {
1572
               if(MouseWheelZoomType == MouseWheelZoomType.MousePositionAndCenter)
1573
               {
1574
                  Core.position = FromLocalToLatLng((int)p.X, (int)p.Y);
1575
               }
1576
               else if(MouseWheelZoomType == MouseWheelZoomType.ViewCenter)
1577
               {
1578
                  Core.position = FromLocalToLatLng((int)ActualWidth / 2, (int)ActualHeight / 2);
1579
               }
1580
               else if(MouseWheelZoomType == MouseWheelZoomType.MousePositionWithoutCenter)
1581
               {
1582
                  Core.position = FromLocalToLatLng((int)p.X, (int)p.Y);
1583
               }
1584
 
1585
               Core.mouseLastZoom.X = (int)p.X;
1586
               Core.mouseLastZoom.Y = (int)p.Y;
1587
            }
1588
 
1589
            // set mouse position to map center
1590
            if(MouseWheelZoomType != MouseWheelZoomType.MousePositionWithoutCenter)
1591
            {
1592
               System.Windows.Point ps = PointToScreen(new System.Windows.Point(ActualWidth / 2, ActualHeight / 2));
1593
               Stuff.SetCursorPos((int)ps.X, (int)ps.Y);
1594
            }
1595
 
1596
            Core.MouseWheelZooming = true;
1597
 
1598
            if(e.Delta > 0)
1599
            {
1600
               if(!InvertedMouseWheelZooming)
1601
               {
1602
                  Zoom = ((int)Zoom) + 1;
1603
               }
1604
               else
1605
               {
1606
                  Zoom = ((int)(Zoom + 0.99)) - 1;
1607
               }
1608
            }
1609
            else
1610
            {
1611
               if(InvertedMouseWheelZooming)
1612
               {
1613
                  Zoom = ((int)Zoom) + 1;
1614
               }
1615
               else
1616
               {
1617
                  Zoom = ((int)(Zoom + 0.99)) - 1;
1618
               }
1619
            }
1620
 
1621
            Core.MouseWheelZooming = false;
1622
         }
1623
      }
1624
 
1625
      bool isSelected = false;
1626
 
1627
      protected override void OnMouseDown(MouseButtonEventArgs e)
1628
      {
1629
         base.OnMouseDown(e);
1630
         if(CanDragMap && e.ChangedButton == DragButton)
1631
         {
1632
            Point p = e.GetPosition(this);
1633
 
1634
            if(MapScaleTransform != null)
1635
            {
1636
               p = MapScaleTransform.Inverse.Transform(p);
1637
            }
1638
 
1639
            p = ApplyRotationInversion(p.X, p.Y);
1640
 
1641
            Core.mouseDown.X = (int)p.X;
1642
            Core.mouseDown.Y = (int)p.Y;
1643
 
1644
            InvalidateVisual();
1645
         }
1646
         else
1647
         {
1648
            if(!isSelected)
1649
            {
1650
               Point p = e.GetPosition(this);
1651
               isSelected = true;
1652
               SelectedArea = RectLatLng.Empty;
1653
               selectionEnd = PointLatLng.Empty;
1654
               selectionStart = FromLocalToLatLng((int)p.X, (int)p.Y);
1655
            }
1656
         }        
1657
      }
1658
 
1659
      int onMouseUpTimestamp = 0;
1660
 
1661
      protected override void OnMouseUp(MouseButtonEventArgs e)
1662
      {
1663
         base.OnMouseUp(e);
1664
 
1665
         if(isSelected)
1666
         {
1667
            isSelected = false;
1668
         }
1669
 
1670
         if(Core.IsDragging)
1671
         {
1672
            if(isDragging)
1673
            {
1674
               onMouseUpTimestamp = e.Timestamp & Int32.MaxValue;
1675
               isDragging = false;
1676
               Debug.WriteLine("IsDragging = " + isDragging);
1677
               Cursor = cursorBefore;
1678
               Mouse.Capture(null);
1679
            }
1680
            Core.EndDrag();
1681
 
1682
            if(BoundsOfMap.HasValue && !BoundsOfMap.Value.Contains(Position))
1683
            {
1684
               if(Core.LastLocationInBounds.HasValue)
1685
               {
1686
                  Position = Core.LastLocationInBounds.Value;
1687
               }
1688
            }
1689
         }
1690
         else
1691
         {
1692
            if(e.ChangedButton == DragButton)
1693
            {
1694
               Core.mouseDown = GPoint.Empty;
1695
            }
1696
 
1697
            if(!selectionEnd.IsEmpty && !selectionStart.IsEmpty)
1698
            {
1699
               bool zoomtofit = false;
1700
 
1701
               if(!SelectedArea.IsEmpty && Keyboard.Modifiers == ModifierKeys.Shift)
1702
               {
1703
                  zoomtofit = SetZoomToFitRect(SelectedArea);
1704
               }
1705
 
1706
               if(OnSelectionChange != null)
1707
               {
1708
                  OnSelectionChange(SelectedArea, zoomtofit);
1709
               }
1710
            }
1711
            else
1712
            {
1713
               InvalidateVisual();
1714
            }
1715
         }
1716
      }
1717
 
1718
      Cursor cursorBefore = Cursors.Arrow;
1719
 
1720
      protected override void OnMouseMove(MouseEventArgs e)
1721
      {
1722
           if (CanDragMap)
1723
            {
1724
                 base.OnMouseMove(e);
1725
                // wpf generates to many events if mouse is over some visual
1726
                // and OnMouseUp is fired, wtf, anyway...
1727
                // http://greatmaps.codeplex.com/workitem/16013
1728
                if ((e.Timestamp & Int32.MaxValue) - onMouseUpTimestamp < 55)
1729
                {
1730
                    Debug.WriteLine("OnMouseMove skipped: " + ((e.Timestamp & Int32.MaxValue) - onMouseUpTimestamp) + "ms");
1731
                    return;
1732
                }
1733
 
1734
                if (!Core.IsDragging && !Core.mouseDown.IsEmpty)
1735
                {
1736
                    Point p = e.GetPosition(this);
1737
 
1738
                    if (MapScaleTransform != null)
1739
                    {
1740
                        p = MapScaleTransform.Inverse.Transform(p);
1741
                    }
1742
 
1743
                    p = ApplyRotationInversion(p.X, p.Y);
1744
 
1745
                    // cursor has moved beyond drag tolerance
1746
                    if (Math.Abs(p.X - Core.mouseDown.X) * 2 >= SystemParameters.MinimumHorizontalDragDistance || Math.Abs(p.Y - Core.mouseDown.Y) * 2 >= SystemParameters.MinimumVerticalDragDistance)
1747
                    {
1748
                        Core.BeginDrag(Core.mouseDown);
1749
                    }
1750
                }
1751
 
1752
                if (Core.IsDragging)
1753
                {
1754
                    if (!isDragging)
1755
                    {
1756
                        isDragging = true;
1757
                        Debug.WriteLine("IsDragging = " + isDragging);
1758
                        cursorBefore = Cursor;
1759
                        Cursor = Cursors.SizeAll;
1760
                        Mouse.Capture(this);
1761
                    }
1762
 
1763
                    if (BoundsOfMap.HasValue && !BoundsOfMap.Value.Contains(Position))
1764
                    {
1765
                        // ...
1766
                    }
1767
                    else
1768
                    {
1769
                        Point p = e.GetPosition(this);
1770
 
1771
                        if (MapScaleTransform != null)
1772
                        {
1773
                            p = MapScaleTransform.Inverse.Transform(p);
1774
                        }
1775
 
1776
                        p = ApplyRotationInversion(p.X, p.Y);
1777
 
1778
                        Core.mouseCurrent.X = (int)p.X;
1779
                        Core.mouseCurrent.Y = (int)p.Y;
1780
                        {
1781
                            Core.Drag(Core.mouseCurrent);
1782
                        }
1783
 
1784
                        if (IsRotated || scaleMode != ScaleModes.Integer)
1785
                        {
1786
                            ForceUpdateOverlays();
1787
                        }
1788
                        else
1789
                        {
1790
                            UpdateMarkersOffset();
1791
                        }
1792
                    }
1793
                    InvalidateVisual(true);
1794
                }
1795
                else
1796
                {
1797
                    if (isSelected && !selectionStart.IsEmpty && (Keyboard.Modifiers == ModifierKeys.Shift || Keyboard.Modifiers == ModifierKeys.Alt || DisableAltForSelection))
1798
                    {
1799
                        System.Windows.Point p = e.GetPosition(this);
1800
                        selectionEnd = FromLocalToLatLng((int)p.X, (int)p.Y);
1801
                        {
1802
                            GMap.NET.PointLatLng p1 = selectionStart;
1803
                            GMap.NET.PointLatLng p2 = selectionEnd;
1804
 
1805
                            double x1 = Math.Min(p1.Lng, p2.Lng);
1806
                            double y1 = Math.Max(p1.Lat, p2.Lat);
1807
                            double x2 = Math.Max(p1.Lng, p2.Lng);
1808
                            double y2 = Math.Min(p1.Lat, p2.Lat);
1809
 
1810
                            SelectedArea = new RectLatLng(y1, x1, x2 - x1, y1 - y2);
1811
                        }
1812
                    }
1813
 
1814
                    if (renderHelperLine)
1815
                    {
1816
                        InvalidateVisual(true);
1817
                    }
1818
                }
1819
            }    
1820
      }
1821
 
1822
      /// <summary>
1823
      /// if true, selects area just by holding mouse and moving
1824
      /// </summary>
1825
      public bool DisableAltForSelection = false;
1826
 
1827
      protected override void OnStylusDown(StylusDownEventArgs e)
1828
      {
1829
         base.OnStylusDown(e);
1830
 
1831
         if(TouchEnabled && CanDragMap && !e.InAir)
1832
         {
1833
            Point p = e.GetPosition(this);
1834
 
1835
            if(MapScaleTransform != null)
1836
            {
1837
               p = MapScaleTransform.Inverse.Transform(p);
1838
            }
1839
 
1840
            p = ApplyRotationInversion(p.X, p.Y);
1841
 
1842
            Core.mouseDown.X = (int)p.X;
1843
            Core.mouseDown.Y = (int)p.Y;
1844
 
1845
            InvalidateVisual();
1846
         }        
1847
      }
1848
 
1849
      protected override void OnStylusUp(StylusEventArgs e)
1850
      {
1851
         base.OnStylusUp(e);
1852
 
1853
         if(TouchEnabled)
1854
         {
1855
            if(isSelected)
1856
            {
1857
               isSelected = false;
1858
            }
1859
 
1860
            if(Core.IsDragging)
1861
            {
1862
               if(isDragging)
1863
               {
1864
                  onMouseUpTimestamp = e.Timestamp & Int32.MaxValue;
1865
                  isDragging = false;
1866
                  Debug.WriteLine("IsDragging = " + isDragging);
1867
                  Cursor = cursorBefore;
1868
                  Mouse.Capture(null);
1869
               }
1870
               Core.EndDrag();
1871
 
1872
               if(BoundsOfMap.HasValue && !BoundsOfMap.Value.Contains(Position))
1873
               {
1874
                  if(Core.LastLocationInBounds.HasValue)
1875
                  {
1876
                     Position = Core.LastLocationInBounds.Value;
1877
                  }
1878
               }
1879
            }
1880
            else
1881
            {
1882
               Core.mouseDown = GPoint.Empty;
1883
               InvalidateVisual();
1884
            }
1885
         }
1886
      }
1887
 
1888
      protected override void OnStylusMove(StylusEventArgs e)
1889
      {
1890
         base.OnStylusMove(e);
1891
 
1892
         if(TouchEnabled && CanDragMap)
1893
         {
1894
            // wpf generates to many events if mouse is over some visual
1895
            // and OnMouseUp is fired, wtf, anyway...
1896
            // http://greatmaps.codeplex.com/workitem/16013
1897
            if((e.Timestamp & Int32.MaxValue) - onMouseUpTimestamp < 55)
1898
            {
1899
               Debug.WriteLine("OnMouseMove skipped: " + ((e.Timestamp & Int32.MaxValue) - onMouseUpTimestamp) + "ms");
1900
               return;
1901
            }
1902
 
1903
            if(!Core.IsDragging && !Core.mouseDown.IsEmpty)
1904
            {
1905
               Point p = e.GetPosition(this);
1906
 
1907
               if(MapScaleTransform != null)
1908
               {
1909
                  p = MapScaleTransform.Inverse.Transform(p);
1910
               }
1911
 
1912
               p = ApplyRotationInversion(p.X, p.Y);
1913
 
1914
               // cursor has moved beyond drag tolerance
1915
               if(Math.Abs(p.X - Core.mouseDown.X) * 2 >= SystemParameters.MinimumHorizontalDragDistance || Math.Abs(p.Y - Core.mouseDown.Y) * 2 >= SystemParameters.MinimumVerticalDragDistance)
1916
               {
1917
                  Core.BeginDrag(Core.mouseDown);
1918
               }
1919
            }
1920
 
1921
            if(Core.IsDragging)
1922
            {
1923
               if(!isDragging)
1924
               {
1925
                  isDragging = true;
1926
                  Debug.WriteLine("IsDragging = " + isDragging);
1927
                  cursorBefore = Cursor;
1928
                  Cursor = Cursors.SizeAll;
1929
                  Mouse.Capture(this);
1930
               }
1931
 
1932
               if(BoundsOfMap.HasValue && !BoundsOfMap.Value.Contains(Position))
1933
               {
1934
                  // ...
1935
               }
1936
               else
1937
               {
1938
                  Point p = e.GetPosition(this);
1939
 
1940
                  if(MapScaleTransform != null)
1941
                  {
1942
                     p = MapScaleTransform.Inverse.Transform(p);
1943
                  }
1944
 
1945
                  p = ApplyRotationInversion(p.X, p.Y);
1946
 
1947
                  Core.mouseCurrent.X = (int)p.X;
1948
                  Core.mouseCurrent.Y = (int)p.Y;
1949
                  {
1950
                     Core.Drag(Core.mouseCurrent);
1951
                  }
1952
 
1953
                  if(IsRotated)
1954
                  {
1955
                     ForceUpdateOverlays();
1956
                  }
1957
                  else
1958
                  {
1959
                     UpdateMarkersOffset();
1960
                  }
1961
               }
1962
               InvalidateVisual();
1963
            }
1964
         }        
1965
      }
1966
 
1967
      #endregion
1968
 
1969
      #region IGControl Members
1970
 
1971
      /// <summary>
1972
      /// Call it to empty tile cache & reload tiles
1973
      /// </summary>
1974
      public void ReloadMap()
1975
      {
1976
         Core.ReloadMap();
1977
      }
1978
 
1979
      /// <summary>
1980
      /// sets position using geocoder
1981
      /// </summary>
1982
      /// <param name="keys"></param>
1983
      /// <returns></returns>
1984
      public GeoCoderStatusCode SetPositionByKeywords(string keys)
1985
      {
1986
         GeoCoderStatusCode status = GeoCoderStatusCode.Unknow;
1987
 
1988
         GeocodingProvider gp = MapProvider as GeocodingProvider;
1989
         if(gp == null)
1990
         {
1991
            gp = GMapProviders.OpenStreetMap as GeocodingProvider;
1992
         }
1993
 
1994
         if(gp != null)
1995
         {
1996
            var pt = gp.GetPoint(keys, out status);
1997
            if(status == GeoCoderStatusCode.G_GEO_SUCCESS && pt.HasValue)
1998
            {
1999
               Position = pt.Value;
2000
            }
2001
         }
2002
 
2003
         return status;
2004
      }
2005
 
2006
      public PointLatLng FromLocalToLatLng(int x, int y)
2007
      {
2008
         if(MapScaleTransform != null)
2009
         {
2010
            var tp = MapScaleTransform.Inverse.Transform(new System.Windows.Point(x, y));
2011
            x = (int)tp.X;
2012
            y = (int)tp.Y;
2013
         }
2014
 
2015
         if(IsRotated)
2016
         {
2017
            var f = rotationMatrixInvert.Transform(new System.Windows.Point(x, y));
2018
 
2019
            x = (int)f.X;
2020
            y = (int)f.Y;
2021
         }
2022
 
2023
         return Core.FromLocalToLatLng(x, y);
2024
      }
2025
 
2026
      public GPoint FromLatLngToLocal(PointLatLng point)
2027
      {
2028
         GPoint ret = Core.FromLatLngToLocal(point);
2029
 
2030
         if(MapScaleTransform != null)
2031
         {
2032
            var tp = MapScaleTransform.Transform(new System.Windows.Point(ret.X, ret.Y));
2033
            ret.X = (int)tp.X;
2034
            ret.Y = (int)tp.Y;
2035
         }
2036
 
2037
         if(IsRotated)
2038
         {
2039
            var f = rotationMatrix.Transform(new System.Windows.Point(ret.X, ret.Y));
2040
 
2041
            ret.X = (int)f.X;
2042
            ret.Y = (int)f.Y;
2043
         }
2044
 
2045
         return ret;
2046
      }
2047
 
2048
      public bool ShowExportDialog()
2049
      {
2050
         var dlg = new Microsoft.Win32.SaveFileDialog();
2051
         {
2052
            dlg.CheckPathExists = true;
2053
            dlg.CheckFileExists = false;
2054
            dlg.AddExtension = true;
2055
            dlg.DefaultExt = "gmdb";
2056
            dlg.ValidateNames = true;
2057
            dlg.Title = "GMap.NET: Export map to db, if file exsist only new data will be added";
2058
            dlg.FileName = "DataExp";
2059
            dlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
2060
            dlg.Filter = "GMap.NET DB files (*.gmdb)|*.gmdb";
2061
            dlg.FilterIndex = 1;
2062
            dlg.RestoreDirectory = true;
2063
 
2064
            if(dlg.ShowDialog() == true)
2065
            {
2066
               bool ok = GMaps.Instance.ExportToGMDB(dlg.FileName);
2067
               if(ok)
2068
               {
2069
                  MessageBox.Show("Complete!", "GMap.NET", MessageBoxButton.OK, MessageBoxImage.Information);
2070
               }
2071
               else
2072
               {
2073
                  MessageBox.Show("  Failed!", "GMap.NET", MessageBoxButton.OK, MessageBoxImage.Warning);
2074
               }
2075
 
2076
               return ok;
2077
            }
2078
         }
2079
 
2080
         return false;
2081
      }
2082
 
2083
      public bool ShowImportDialog()
2084
      {
2085
         var dlg = new Microsoft.Win32.OpenFileDialog();
2086
         {
2087
            dlg.CheckPathExists = true;
2088
            dlg.CheckFileExists = false;
2089
            dlg.AddExtension = true;
2090
            dlg.DefaultExt = "gmdb";
2091
            dlg.ValidateNames = true;
2092
            dlg.Title = "GMap.NET: Import to db, only new data will be added";
2093
            dlg.FileName = "DataImport";
2094
            dlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
2095
            dlg.Filter = "GMap.NET DB files (*.gmdb)|*.gmdb";
2096
            dlg.FilterIndex = 1;
2097
            dlg.RestoreDirectory = true;
2098
 
2099
            if(dlg.ShowDialog() == true)
2100
            {
2101
               Cursor = Cursors.Wait;
2102
 
2103
               bool ok = GMaps.Instance.ImportFromGMDB(dlg.FileName);
2104
               if(ok)
2105
               {
2106
                  MessageBox.Show("Complete!", "GMap.NET", MessageBoxButton.OK, MessageBoxImage.Information);
2107
                  ReloadMap();
2108
               }
2109
               else
2110
               {
2111
                  MessageBox.Show("  Failed!", "GMap.NET", MessageBoxButton.OK, MessageBoxImage.Warning);
2112
               }
2113
 
2114
               Cursor = Cursors.Arrow;
2115
 
2116
               return ok;
2117
            }
2118
         }
2119
 
2120
         return false;
2121
      }
2122
 
2123
      /// <summary>
2124
      /// current coordinates of the map center
2125
      /// </summary>
2126
      [Browsable(false)]
2127
      public PointLatLng Position
2128
      {
2129
         get
2130
         {
2131
            return Core.Position;
2132
         }
2133
         set
2134
         {
2135
            Core.Position = value;
2136
 
2137
            if(Core.IsStarted)
2138
            {
2139
               ForceUpdateOverlays();
2140
            }
2141
         }
2142
      }
2143
 
2144
      [Browsable(false)]
2145
      public GPoint PositionPixel
2146
      {
2147
         get
2148
         {
2149
            return Core.PositionPixel;
2150
         }
2151
      }
2152
 
2153
      [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
2154
      [Browsable(false)]
2155
      public string CacheLocation
2156
      {
2157
         get
2158
         {
2159
            return CacheLocator.Location;
2160
         }
2161
         set
2162
         {
2163
            CacheLocator.Location = value;
2164
         }
2165
      }
2166
 
2167
      bool isDragging = false;
2168
 
2169
      [Browsable(false)]
2170
      public bool IsDragging
2171
      {
2172
         get
2173
         {
2174
            return isDragging;
2175
         }
2176
      }
2177
 
2178
      [Browsable(false)]
2179
      public RectLatLng ViewArea
2180
      {
2181
         get
2182
         {
2183
             if(!IsRotated)
2184
             {
2185
                 return Core.ViewArea;
2186
             }
2187
             else if(Core.Provider.Projection != null)
2188
             {
2189
                 var p = FromLocalToLatLng(0, 0);
2190
                 var p2 = FromLocalToLatLng((int)Width, (int)Height);
2191
 
2192
                 return RectLatLng.FromLTRB(p.Lng, p.Lat, p2.Lng, p2.Lat);
2193
             }
2194
             return RectLatLng.Empty;
2195
         }
2196
      }
2197
 
2198
      [Category("GMap.NET")]
2199
      public bool CanDragMap
2200
      {
2201
         get
2202
         {
2203
            return Core.CanDragMap;
2204
         }
2205
         set
2206
         {
2207
            Core.CanDragMap = value;
2208
         }
2209
      }
2210
 
2211
      public GMap.NET.RenderMode RenderMode
2212
      {
2213
         get
2214
         {
2215
            return GMap.NET.RenderMode.WPF;
2216
         }
2217
      }
2218
 
2219
      #endregion
2220
 
2221
      #region IGControl event Members
2222
 
2223
      public event PositionChanged OnPositionChanged
2224
      {
2225
         add
2226
         {
2227
            Core.OnCurrentPositionChanged += value;
2228
         }
2229
         remove
2230
         {
2231
            Core.OnCurrentPositionChanged -= value;
2232
         }
2233
      }
2234
 
2235
      public event TileLoadComplete OnTileLoadComplete
2236
      {
2237
         add
2238
         {
2239
            Core.OnTileLoadComplete += value;
2240
         }
2241
         remove
2242
         {
2243
            Core.OnTileLoadComplete -= value;
2244
         }
2245
      }
2246
 
2247
      public event TileLoadStart OnTileLoadStart
2248
      {
2249
         add
2250
         {
2251
            Core.OnTileLoadStart += value;
2252
         }
2253
         remove
2254
         {
2255
            Core.OnTileLoadStart -= value;
2256
         }
2257
      }
2258
 
2259
      public event MapDrag OnMapDrag
2260
      {
2261
         add
2262
         {
2263
            Core.OnMapDrag += value;
2264
         }
2265
         remove
2266
         {
2267
            Core.OnMapDrag -= value;
2268
         }
2269
      }
2270
 
2271
      public event MapZoomChanged OnMapZoomChanged
2272
      {
2273
         add
2274
         {
2275
            Core.OnMapZoomChanged += value;
2276
         }
2277
         remove
2278
         {
2279
            Core.OnMapZoomChanged -= value;
2280
         }
2281
      }
2282
 
2283
      /// <summary>
2284
      /// occures on map type changed
2285
      /// </summary>
2286
      public event MapTypeChanged OnMapTypeChanged
2287
      {
2288
         add
2289
         {
2290
            Core.OnMapTypeChanged += value;
2291
         }
2292
         remove
2293
         {
2294
            Core.OnMapTypeChanged -= value;
2295
         }
2296
      }
2297
 
2298
      /// <summary>
2299
      /// occurs on empty tile displayed
2300
      /// </summary>
2301
      public event EmptyTileError OnEmptyTileError
2302
      {
2303
         add
2304
         {
2305
            Core.OnEmptyTileError += value;
2306
         }
2307
         remove
2308
         {
2309
            Core.OnEmptyTileError -= value;
2310
         }
2311
      }
2312
      #endregion
2313
 
2314
      #region IDisposable Members
2315
 
2316
      public virtual void Dispose()
2317
      {
2318
         if(Core.IsStarted)
2319
         {
2320
            Core.OnMapZoomChanged -= new MapZoomChanged(ForceUpdateOverlays);
2321
            Loaded -= new RoutedEventHandler(GMapControl_Loaded);
2322
            Dispatcher.ShutdownStarted -= new EventHandler(Dispatcher_ShutdownStarted);
2323
            SizeChanged -= new SizeChangedEventHandler(GMapControl_SizeChanged);
2324
            if(loadedApp != null)
2325
            {
2326
               loadedApp.SessionEnding -= new SessionEndingCancelEventHandler(Current_SessionEnding);
2327
            }
2328
            Core.OnMapClose();
2329
         }
2330
      }
2331
 
2332
      #endregion
2333
   }
2334
 
2335
   public enum HelperLineOptions
2336
   {
2337
      DontShow = 0,
2338
      ShowAlways = 1,
2339
      ShowOnModifierKey = 2
2340
   }
2341
 
2342
   public enum ScaleModes
2343
   {
2344
      /// <summary>
2345
      /// no scaling
2346
      /// </summary>
2347
      Integer,
2348
 
2349
      /// <summary>
2350
      /// scales to fractional level using a stretched tiles, any issues -> http://greatmaps.codeplex.com/workitem/16046
2351
      /// </summary>
2352
      ScaleUp,
2353
 
2354
      /// <summary>
2355
      /// scales to fractional level using a narrowed tiles, any issues -> http://greatmaps.codeplex.com/workitem/16046
2356
      /// </summary>
2357
      ScaleDown,
2358
 
2359
      /// <summary>
2360
      /// scales to fractional level using a combination both stretched and narrowed tiles, any issues -> http://greatmaps.codeplex.com/workitem/16046
2361
      /// </summary>
2362
      Dynamic
2363
   }
2364
 
2365
   public delegate void SelectionChange(RectLatLng Selection, bool ZoomToFit);
2366
}