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