PageRenderTime 57ms CodeModel.GetById 8ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/Main/src/DynamicDataDisplay.Maps/Charts/NewMap.cs

#
C# | 613 lines | 503 code | 99 blank | 11 comment | 76 complexity | 443c320682ccfb99a7bfd01c264b26cb MD5 | raw file
  1using System;
  2using System.Collections.Specialized;
  3using System.ComponentModel;
  4using System.Diagnostics;
  5using System.Globalization;
  6using System.Linq;
  7using System.Windows;
  8using System.Windows.Controls;
  9using System.Windows.Input;
 10using System.Windows.Markup;
 11using System.Windows.Media;
 12using System.Windows.Media.Imaging;
 13using Microsoft.Research.DynamicDataDisplay;
 14using Microsoft.Research.DynamicDataDisplay.Charts.Navigation;
 15using Microsoft.Research.DynamicDataDisplay.Maps.Servers.Network;
 16using Microsoft.Research.DynamicDataDisplay.ViewportConstraints;
 17using Microsoft.Research.DynamicDataDisplay.Maps;
 18using System.Collections.Generic;
 19using Microsoft.Research.DynamicDataDisplay.Common;
 20using Microsoft.Research.DynamicDataDisplay.Maps.Charts;
 21using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
 22
 23
 24namespace Microsoft.Research.DynamicDataDisplay.Charts.Maps
 25{
 26    [ContentProperty("SourceTileServer")]
 27    public class NewMap : FrameworkElement, IPlotterElement
 28    {
 29        public NewMap()
 30        {
 31            server.ImageLoaded += OnTileLoaded;
 32            server.SourceServerChanged += OnNetworkServerChanged;
 33
 34#if DEBUG
 35            drawDebugBounds = false;
 36#endif
 37        }
 38
 39        private TileProvider tileProvider = new MapTileProvider();
 40        public TileProvider TileProvider
 41        {
 42            get { return tileProvider; }
 43            set
 44            {
 45                if (value == null)
 46                    throw new ArgumentNullException("value");
 47                tileProvider = value;
 48            }
 49        }
 50
 51        private readonly TileServerSystem server = new TileServerSystem();
 52        public TileServerSystem TileSystem
 53        {
 54            get { return server; }
 55        }
 56
 57        [NotNull]
 58        public SourceTileServer SourceTileServer
 59        {
 60            get { return server.SourceServer; }
 61            set { server.SourceServer = value; }
 62        }
 63
 64        public TileSystemMode Mode
 65        {
 66            get { return server.Mode; }
 67            set { server.Mode = value; }
 68        }
 69
 70        public IWriteableTileServer FileTileServer
 71        {
 72            get { return server.FileServer; }
 73            set { server.FileServer = value; }
 74        }
 75
 76        private readonly ViewportHostPanel panel = new ViewportHostPanel();
 77        public ViewportHostPanel Panel
 78        {
 79            get { return panel; }
 80        }
 81
 82        protected virtual void OnTileLoaded(object sender, TileLoadResultEventArgs e)
 83        {
 84            if (e.Result == TileLoadResult.Success)
 85            {
 86                DataRect tileBounds = tileProvider.GetTileBounds(e.ID);
 87
 88                bool containsInDrawn = drawnBounds.Contains(tileBounds) || drawnBounds.IsEmpty;
 89                bool shouldDraw = containsInDrawn && !invalidatePending && e.ID.Level <= tileProvider.Level;
 90                if (shouldDraw)
 91                {
 92                    DrawImage(e.Image, tileBounds, e.ID);
 93                }
 94            }
 95        }
 96
 97        private int tileWidth = 256;
 98        private int tileHeight = 256;
 99        protected virtual void OnNetworkServerChanged(object sender, ValueChangedEventArgs<SourceTileServer> e)
100        {
101            if (e.PreviousValue != null)
102            {
103                RemoveLogicalChild(e.PreviousValue);
104            }
105            if (e.CurrentValue != null)
106            {
107                AddLogicalChild(e.CurrentValue);
108            }
109
110            SourceTileServer networkServer = server.SourceServer;
111            if (networkServer != null)
112            {
113                tileProvider.MinLevel = networkServer.MinLevel;
114                tileProvider.MaxLevel = networkServer.MaxLevel;
115
116                MapTileProvider mapProvider = tileProvider as MapTileProvider;
117                if (mapProvider != null)
118                {
119                    mapProvider.MaxLatitude = networkServer.MaxLatitude;
120                }
121                tileWidth = networkServer.TileWidth;
122                tileHeight = networkServer.TileHeight;
123            }
124
125            BeginInvalidateVisual();
126        }
127
128        private bool drawDebugBounds = false;
129        public bool DrawDebugBounds
130        {
131            get { return drawDebugBounds; }
132            set { drawDebugBounds = value; }
133        }
134
135        private readonly Pen debugBoundsPen = new Pen(Brushes.Red.MakeTransparent(0.5), 1);
136
137        bool showsWholeMap = false;
138        DataRect drawnBounds = DataRect.Empty;
139        DataRect visibleBounds;
140        bool invalidatePending = false;
141        bool rendering = false;
142        protected void OnRender()
143        {
144            if (DesignerProperties.GetIsInDesignMode(this))
145                return;
146
147            if (plotter == null)
148                return;
149
150            panel.Children.Clear();
151
152            freeChildren = new List<MapElement>(panel.Children.Count);
153            for (int i = 0; i < panel.Children.Count; i++)
154            {
155                freeChildren.Add((MapElement)panel.Children[i]);
156            }
157
158            rendering = true;
159            invalidatePending = false;
160
161            var transform = plotter.Viewport.Transform;
162            Rect output = plotter.Viewport.Output;
163            DataRect visible = plotter.Viewport.Visible;
164            visibleBounds = visible;
165
166            drawnBounds = DataRect.Empty;
167
168            var tileInfos = GetVisibleTiles();
169
170            var lowerTilesList = GetLoadedLowerTiles(tileInfos);
171            // displaying lower tiles
172            foreach (var tile in lowerTilesList)
173            {
174                if (server.IsLoaded(tile))
175                {
176                    var bmp = server[tile];
177                    DataRect visibleRect = tileProvider.GetTileBounds(tile);
178                    DrawImage(bmp, visibleRect, tile);
179                }
180                else
181                {
182                    server.BeginLoadImage(tile);
183                }
184            }
185
186            int count = 0;
187            foreach (var tileInfo in tileInfos)
188            {
189                drawnBounds.Union(tileInfo.VisibleBounds);
190
191                count++;
192                if (server.IsLoaded(tileInfo.Tile))
193                {
194                    var bmp = server[tileInfo.Tile];
195                    DrawImage(bmp, tileInfo.VisibleBounds, tileInfo.Tile);
196                }
197                else
198                {
199                    server.BeginLoadImage(tileInfo.Tile);
200                }
201            }
202            showsWholeMap = count == MapTileProvider.GetTotalTilesCount(tileProvider.Level);
203
204            foreach (var item in freeChildren)
205            {
206                panel.Children.Remove(item);
207                pool.Put(item);
208            }
209
210            foreach (MapElement item in panel.Children)
211            {
212                if (item.Bitmap == null)
213                {
214                    panel.Children.Remove(item);
215                    pool.Put(item);
216                }
217            }
218
219            rendering = false;
220
221            Debug.WriteLine("Drawn " + Environment.TickCount);
222        }
223
224        private List<MapElement> freeChildren = new List<MapElement>();
225        private readonly ResourcePool<MapElement> pool = new ResourcePool<MapElement>();
226        private void DrawImage(BitmapSource bmp, DataRect bounds, TileIndex id)
227        {
228            MapElement element = null;
229            bool onPanel = false;
230            if (freeChildren.Count > 0)
231            {
232                element = (MapElement)freeChildren[freeChildren.Count - 1];
233                freeChildren.RemoveAt(freeChildren.Count - 1);
234                onPanel = true;
235            }
236            else
237            {
238                element = pool.GetOrCreate();
239            }
240
241            element.Bitmap = bmp;
242            ViewportPanel.SetViewportBounds(element, bounds);
243            System.Windows.Controls.Panel.SetZIndex(element, (int)id.Level);
244
245            if (!onPanel)
246            {
247                panel.Children.Add(element);
248                panel.InvalidateMeasure();
249            }
250        }
251
252        protected virtual DataRect Transform(DataRect visibleRect)
253        {
254            return visibleRect;
255        }
256
257        protected virtual DataRect TransformRegion(DataRect visibleRect)
258        {
259            return visibleRect;
260        }
261
262        protected List<VisibleTileInfo> GetVisibleTiles()
263        {
264            var transform = plotter.Viewport.Transform;
265            Rect output = plotter.Viewport.Output;
266            DataRect visible = plotter.Viewport.Visible;
267
268            var tileInfos = (from tile in tileProvider.GetTilesForRegion(TransformRegion(visible), tileProvider.Level)
269                             let visibleRect = Transform(tileProvider.GetTileBounds(tile))
270                             let screenRect = visibleRect.ViewportToScreen(transform)
271                             where output.IntersectsWith(screenRect)
272                             select new VisibleTileInfo { Tile = tile, ScreenBounds = screenRect, VisibleBounds = visibleRect }).ToList();
273
274            if (tileInfos.Count > MapTileProvider.GetTotalTilesCount(tileProvider.Level))
275            {
276                //Debugger.Break();
277            }
278
279            return tileInfos;
280        }
281
282        protected virtual IEnumerable<TileIndex> GetLoadedLowerTiles(IEnumerable<VisibleTileInfo> visibleTiles)
283        {
284            Set<TileIndex> result = new Set<TileIndex>();
285
286            foreach (var tileInfo in visibleTiles)
287            {
288                if (!server.IsLoaded(tileInfo.Tile))
289                {
290                    bool found = false;
291                    var tile = tileInfo.Tile;
292                    do
293                    {
294                        if (tile.HasLowerTile)
295                        {
296                            tile = tile.GetLowerTile();
297                            if (server.IsLoaded(tile) || tile.Level == 1)
298                            {
299                                found = true;
300                                result.TryAdd(tile);
301                            }
302                        }
303                        else
304                        {
305                            found = true;
306                        }
307                    }
308                    while (!found);
309                }
310            }
311
312            return result.OrderBy(id => id.Level);
313        }
314
315        protected Rect EnlargeRect(Rect rect)
316        {
317            double coeff = 1 + 1.0 / tileWidth;
318            return EnlargeRect(rect, coeff);
319        }
320
321        protected Rect EnlargeRect(Rect rect, double rectZoomCoeff)
322        {
323            Rect res = rect;
324            res = res.Zoom(res.GetCenter(), rectZoomCoeff);
325            return res;
326        }
327
328        private FormattedText CreateText(TileIndex tileIndex)
329        {
330            FormattedText text = new FormattedText(tileIndex.ToString(),
331                CultureInfo.CurrentCulture,
332                FlowDirection.LeftToRight, new Typeface("Arial"), 8, Brushes.Red);
333            return text;
334        }
335
336        #region ChangesTextFormat property
337
338        public bool ChangesTextFormat
339        {
340            get { return (bool)GetValue(ChangesTextFormatProperty); }
341            set { SetValue(ChangesTextFormatProperty, value); }
342        }
343
344        public static readonly DependencyProperty ChangesTextFormatProperty = DependencyProperty.Register(
345          "ChangesTextFormat",
346          typeof(bool),
347          typeof(NewMap),
348          new FrameworkPropertyMetadata(true, OnChangesTextFormatChanged));
349
350        private static void OnChangesTextFormatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
351        {
352            NewMap map = (NewMap)d;
353            map.OnChangesTextFormatChanged();
354        }
355
356        private void OnChangesTextFormatChanged()
357        {
358            // do nothing if disconnected
359            if (plotter == null)
360                return;
361
362            if (ChangesTextFormat)
363            {
364                plotter.Children.CollectionChanged += PlotterChildren_CollectionChanged;
365                ChangeTextFormat();
366            }
367            else
368            {
369                plotter.Children.CollectionChanged -= PlotterChildren_CollectionChanged;
370                RevertTextFormat();
371            }
372        }
373
374        #endregion
375
376        protected virtual void BeginInvalidateVisual()
377        {
378            if (!rendering)
379            {
380                invalidatePending = true;
381                OnRender();
382            }
383            else
384            {
385                Dispatcher.BeginInvoke(((Action)(() => { OnRender(); })));
386            }
387        }
388
389        #region IPlotterElement Members
390
391        Func<double, string> prevXMapping;
392        Func<double, string> prevYMapping;
393        PhysicalProportionsConstraint proportionsConstraint = new PhysicalProportionsConstraint(2.0);
394        protected PhysicalProportionsConstraint ProportionsConstraint
395        {
396            get { return proportionsConstraint; }
397        }
398
399        MaximalSizeConstraint maxSizeConstraint = new MaximalSizeConstraint();
400        protected MaximalSizeConstraint MaxSizeConstraint
401        {
402            get { return maxSizeConstraint; }
403        }
404
405        void IPlotterElement.OnPlotterAttached(Plotter plotter)
406        {
407            this.plotter = (Plotter2D)plotter;
408            this.plotter.Viewport.PropertyChanged += Viewport_PropertyChanged;
409
410            this.plotter.Viewport.Constraints.Add(maxSizeConstraint);
411            this.plotter.Viewport.Constraints.Add(proportionsConstraint);
412
413            this.plotter.KeyDown += new KeyEventHandler(plotter_KeyDown);
414
415            if (ChangesTextFormat)
416            {
417                plotter.Children.CollectionChanged += PlotterChildren_CollectionChanged;
418                // changing text mappings of CursorCoordinateGraph, if it exists,
419                // to display text labels with degrees.
420                ChangeTextFormat();
421            }
422
423            plotter.Children.BeginAdd(panel);
424
425            OnPlotterAttached(plotter);
426
427            BeginInvalidateVisual();
428        }
429
430        protected virtual void OnPlotterAttached(Plotter plotter)
431        {
432        }
433
434        private void plotter_KeyDown(object sender, KeyEventArgs e)
435        {
436            if (e.Key == Key.Q)
437            {
438                tileProvider.IncreaseLevel();
439                BeginInvalidateVisual();
440            }
441            else if (e.Key == Key.W)
442            {
443                tileProvider.DecreaseLevel();
444                BeginInvalidateVisual();
445            }
446        }
447
448        void PlotterChildren_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
449        {
450            if (ChangesTextFormat)
451            {
452                ChangeTextFormat();
453            }
454        }
455
456        bool changedTextFormat = false;
457        private void ChangeTextFormat()
458        {
459            if (changedTextFormat)
460                return;
461
462
463            // todo discover why sometimes we arrive here from PlotterChildren_CollectionChanged when we have removed this handler from
464            // plotter.Children.CollectionChanged invocation list.
465            if (plotter == null)
466                return;
467
468            var cursorGraph = plotter.Children.OfType<CursorCoordinateGraph>().FirstOrDefault<CursorCoordinateGraph>();
469            if (cursorGraph != null)
470            {
471                changedTextFormat = true;
472
473                // saving previous text mappings
474                prevXMapping = cursorGraph.XTextMapping;
475                prevYMapping = cursorGraph.YTextMapping;
476
477
478                // setting new text mappings
479                cursorGraph.XTextMapping = value =>
480                {
481                    if (Double.IsNaN(value))
482                        return "";
483
484                    if (-180 <= value && value <= 180)
485                    {
486                        Degree degree = Degree.CreateLongitude(value);
487                        return degree.ToString();
488                    }
489                    else return null;
490                };
491
492                cursorGraph.YTextMapping = value =>
493                {
494                    if (Double.IsNaN(value))
495                        return "";
496
497                    var mapTileProvider = tileProvider as MapTileProvider;
498                    if (mapTileProvider != null)
499                    {
500                        if (mapTileProvider.MinLatitude <= value && value <= mapTileProvider.MaxLatitude)
501                        {
502                            Degree degree = Degree.CreateLatitude(value);
503                            return degree.ToString();
504                        }
505                    }
506                    return null;
507                };
508            }
509        }
510
511
512        private void Viewport_PropertyChanged(object sender, ExtendedPropertyChangedEventArgs e)
513        {
514            var transform = plotter.Viewport.Transform;
515
516            double prevLevel = tileProvider.Level;
517            UpdateLevel(transform);
518
519            bool shouldRedraw = prevLevel != tileProvider.Level;
520
521            if (e.PropertyName == "Visible")
522            {
523                DataRect currVisible = (DataRect)e.NewValue;
524                shouldRedraw |= !(drawnBounds.Contains(currVisible) || showsWholeMap);
525            }
526            else if (e.PropertyName == "Transform") { }
527
528            if (shouldRedraw)
529            {
530                BeginInvalidateVisual();
531            }
532        }
533
534        protected virtual void UpdateLevel(CoordinateTransform transform)
535        {
536            bool ok = false;
537            do
538            {
539                double width = tileProvider.GetTileWidth(tileProvider.Level);
540                double height = tileProvider.GetTileHeight(tileProvider.Level);
541
542                DataRect size = new DataRect(new Size(width, height));
543                Rect onScreen = size.ViewportToScreen(transform);
544
545                // todo написать нормально
546                if (onScreen.Width > tileWidth * 1.45)
547                {
548                    if (tileProvider.IncreaseLevel())
549                    {
550                        continue;
551                    }
552                }
553                else if (onScreen.Width < tileWidth / 1.45)
554                {
555                    if (tileProvider.DecreaseLevel())
556                    {
557                        continue;
558                    }
559                }
560                ok = true;
561            } while (!ok);
562        }
563
564        protected virtual void OnPlotterDetaching(Plotter plotter) { }
565
566        void IPlotterElement.OnPlotterDetaching(Plotter plotter)
567        {
568            OnPlotterDetaching(plotter);
569
570            visibleBounds = new Rect();
571
572            this.plotter.Children.BeginRemove(panel);
573            this.plotter.Viewport.PropertyChanged -= Viewport_PropertyChanged;
574
575			this.plotter.Viewport.Constraints.Remove(proportionsConstraint);
576			this.plotter.Viewport.Constraints.Remove(maxSizeConstraint);
577
578            this.plotter.Children.CollectionChanged -= PlotterChildren_CollectionChanged;
579
580            RevertTextFormat();
581
582            this.plotter = null;
583        }
584
585        private void RevertTextFormat()
586        {
587            if (changedTextFormat)
588            {
589                // revert test mappings of CursorCoordinateGraph, if it exists.
590                var cursorGraph = plotter.Children.OfType<CursorCoordinateGraph>().FirstOrDefault<CursorCoordinateGraph>();
591                if (cursorGraph != null)
592                {
593                    cursorGraph.XTextMapping = prevXMapping;
594                    cursorGraph.YTextMapping = prevYMapping;
595                }
596                changedTextFormat = false;
597            }
598        }
599
600        private Plotter2D plotter;
601        public Plotter2D Plotter
602        {
603            get { return plotter; }
604        }
605
606        Plotter IPlotterElement.Plotter
607        {
608            get { return plotter; }
609        }
610
611        #endregion
612    }
613}