PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/Main/src/DynamicDataDisplay.Maps/Charts/VectorFields/Convolution/VectorFieldConvolutionChart.cs

#
C# | 364 lines | 266 code | 77 blank | 21 comment | 19 complexity | e899564d6727ece461be25a82bd2c95a MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows;
  6. using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
  7. using Microsoft.Research.DynamicDataDisplay.DataSources;
  8. using DataSource = Microsoft.Research.DynamicDataDisplay.DataSources.INonUniformDataSource2D<System.Windows.Vector>;
  9. using System.Windows.Media.Imaging;
  10. using System.Windows.Media;
  11. using Microsoft.Research.DynamicDataDisplay.Maps.Charts.VectorFields;
  12. using Microsoft.Research.DynamicDataDisplay.Charts.Isolines;
  13. using System.Threading;
  14. using System.Windows.Controls;
  15. using System.Threading.Tasks;
  16. using System.Windows.Threading;
  17. using Microsoft.Research.DynamicDataDisplay.Common.Palettes;
  18. using Microsoft.Research.DynamicDataDisplay.Charts;
  19. namespace Microsoft.Research.DynamicDataDisplay.Maps.Charts
  20. {
  21. public class VectorFieldConvolutionChart : Image
  22. {
  23. public VectorFieldConvolutionChart()
  24. {
  25. Stretch = Stretch.Fill;
  26. }
  27. #region Properties
  28. public DataSource DataSource
  29. {
  30. get { return (DataSource)GetValue(DataSourceProperty); }
  31. set { SetValue(DataSourceProperty, value); }
  32. }
  33. public static readonly DependencyProperty DataSourceProperty = DependencyProperty.Register(
  34. "DataSource",
  35. typeof(DataSource),
  36. typeof(VectorFieldConvolutionChart),
  37. new FrameworkPropertyMetadata(null, OnDataSourceReplaced));
  38. private static void OnDataSourceReplaced(DependencyObject d, DependencyPropertyChangedEventArgs e)
  39. {
  40. VectorFieldConvolutionChart owner = (VectorFieldConvolutionChart)d;
  41. owner.OnDataSourceReplaced((DataSource)e.OldValue, (DataSource)e.NewValue);
  42. }
  43. private void OnDataSourceReplaced(IDataSource2D<Vector> prevDataSource, IDataSource2D<Vector> currDataSource)
  44. {
  45. var dataSource = this.GetValueSync<IDataSource2D<Vector>>(DataSourceProperty);
  46. var contentBounds = dataSource.Grid.GetGridBounds();
  47. if (Parent != null)
  48. Viewport2D.SetContentBounds(Parent, contentBounds);
  49. ViewportPanel.SetViewportBounds(this, contentBounds);
  50. int width = currDataSource.Width;
  51. int height = currDataSource.Height;
  52. bmp = new WriteableBitmap(width, height, 96, 96, PixelFormats.Pbgra32, null);
  53. Source = bmp;
  54. Task task = new Task(() => CreateConvolutionBmp(width, height));
  55. task.Start();
  56. }
  57. #endregion // end of Properties
  58. WriteableBitmap bmp;
  59. private void UpdateBitmap(int[] pixels)
  60. {
  61. bmp.Dispatcher.BeginInvoke(() =>
  62. {
  63. int width = (int)bmp.Width;
  64. int height = (int)bmp.Height;
  65. bmp.WritePixels(new Int32Rect(0, 0, width, height), pixels, (width * bmp.Format.BitsPerPixel + 7) / 8, 0);
  66. });
  67. }
  68. private readonly NormalizeFilter normalizeFilter = new NormalizeFilter();
  69. public NormalizeFilter NormalizeFilter
  70. {
  71. get { return normalizeFilter; }
  72. }
  73. private readonly MagnitudeFilter magnitudeFilter = new MagnitudeFilter { Palette = new UniformLinearPalette(Colors.Green, Colors.GreenYellow, Colors.Red) };
  74. public MagnitudeFilter MagnitudeFilter
  75. {
  76. get { return magnitudeFilter; }
  77. }
  78. private void CreateConvolutionBmp(int width, int height)
  79. {
  80. int[] pixels = new int[width * height];
  81. var dataSource = this.GetValueSync<IDataSource2D<Vector>>(DataSourceProperty); ;
  82. GenerateWhiteNoizeImage(width, height, pixels);
  83. //GenerateWhiteCirclesImage(width, height, pixels);
  84. UpdateBitmap(pixels);
  85. int[] effectivePixels = CreateConvolutionArray(width, height, pixels);
  86. UpdateBitmap(effectivePixels);
  87. normalizeFilter.ApplyFilter(effectivePixels, width, height, dataSource.Data);
  88. magnitudeFilter.ApplyFilter(effectivePixels, width, height, dataSource.Data);
  89. UpdateBitmap(effectivePixels);
  90. }
  91. private static void GenerateWhiteNoizeImage(int width, int height, int[] pixels)
  92. {
  93. Random rnd = new Random();
  94. for (int i = 0; i < width * height; i++)
  95. {
  96. HsbColor color = new HsbColor(0, 0, Math.Round(5 * rnd.NextDouble()) / 4);
  97. int argb = color.ToArgb();
  98. pixels[i] = argb;
  99. }
  100. }
  101. private static void GenerateWhiteCirclesImage(int width, int height, int[] pixels)
  102. {
  103. DrawingImage image = new DrawingImage();
  104. Random rnd = new Random();
  105. const double radius = 4;
  106. const int circlesNum = 100;
  107. DrawingGroup group = new DrawingGroup();
  108. var dc = group.Open();
  109. for (int i = 0; i < circlesNum; i++)
  110. {
  111. dc.DrawEllipse(Brushes.White, null, new Point(rnd.NextDouble() * width, rnd.NextDouble() * height), radius, radius);
  112. }
  113. dc.Close();
  114. image.Drawing = group;
  115. RenderTargetBitmap renderBmp = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
  116. renderBmp.Render(new Image { Source = image });
  117. renderBmp.CopyPixels(pixels, (width * renderBmp.Format.BitsPerPixel + 7) / 8, 0);
  118. }
  119. private int[] CreateConvolutionArray(int width, int height, int[] pixels)
  120. {
  121. var dataSource = this.GetValueSync<DataSource>(DataSourceProperty); ;
  122. const int Length = 20;
  123. const int maxIterations = 20;
  124. int pixelsCount = width * height;
  125. int[] effectivePixels = new int[pixelsCount];
  126. pixels.CopyTo(effectivePixels, 0);
  127. System.Threading.Tasks.Parallel.For(0, pixelsCount, i =>
  128. {
  129. if (i % 1000 == 0)
  130. UpdateBitmap(effectivePixels);
  131. int ix = i % width;
  132. int iy = i / width;
  133. double sumDistance = 1;
  134. double positiveDistance = 0;
  135. Point position = dataSource.Grid[ix, iy];
  136. ConvolutionColor color = ConvolutionColor.FromArgb(pixels[ix + width * iy]);
  137. int iterationsCounter = 0;
  138. do
  139. {
  140. int i_x = ix;
  141. int i_y = iy;
  142. iterationsCounter++;
  143. Vector vector =
  144. //GetVector(dataSource, new IntPoint(i_x, i_y), position);
  145. dataSource.Data[i_x, i_y];
  146. if (vector.Length > 0)
  147. vector.Normalize();
  148. position += vector;
  149. positiveDistance += vector.Length;
  150. IntPoint coordinate;
  151. bool found = GetCoordinate(dataSource, position, out coordinate);
  152. if (found)
  153. {
  154. i_x = coordinate.X;
  155. i_y = coordinate.Y;
  156. var currentColor = ConvolutionColor.FromArgb(pixels[i_x + i_y * width]);
  157. color += currentColor;
  158. sumDistance += 1;
  159. }
  160. else
  161. break;
  162. }
  163. while (positiveDistance < Length && iterationsCounter < maxIterations);
  164. var negativeDistance = 0.0;
  165. iterationsCounter = 0;
  166. do
  167. {
  168. int i_x = ix;
  169. int i_y = iy;
  170. iterationsCounter++;
  171. Vector vector =
  172. //GetVector(dataSource, new IntPoint(i_x, i_y), position);
  173. dataSource.Data[i_x, i_y];
  174. if (vector.Length > 0)
  175. vector.Normalize();
  176. position -= vector;
  177. negativeDistance += vector.Length;
  178. IntPoint coordinate;
  179. bool found = GetCoordinate(dataSource, position, out coordinate);
  180. if (found)
  181. {
  182. i_x = coordinate.X;
  183. i_y = coordinate.Y;
  184. var currentColor = ConvolutionColor.FromArgb(pixels[i_x + i_y * width]);
  185. color += currentColor;
  186. sumDistance += 1;
  187. }
  188. else
  189. break;
  190. }
  191. while (negativeDistance < Length && iterationsCounter < maxIterations);
  192. color /= sumDistance;
  193. effectivePixels[i] = color.ToArgb();
  194. });
  195. return effectivePixels;
  196. }
  197. private static ConvolutionColor GetColor(DataSource dataSource, int[] pixels, IntPoint coordinate, Point point)
  198. {
  199. int x = coordinate.X;
  200. int y = coordinate.Y;
  201. var x0 = dataSource.XCoordinates[x];
  202. var x1 = dataSource.XCoordinates[x + 1];
  203. var y0 = dataSource.YCoordinates[y];
  204. var y1 = dataSource.YCoordinates[y + 1];
  205. double xRatio = GetRatio(x0, x1, point.X);
  206. double yRatio = GetRatio(y0, y1, point.Y);
  207. int width = dataSource.Width;
  208. var v00 = pixels[x + y * width];
  209. var v01 = pixels[x + 1 + y * width];
  210. var v10 = pixels[x + (y + 1) * width];
  211. var v11 = pixels[x + 1 + (y + 1) * width];
  212. var result = (int)(((1 - xRatio) * v00 + xRatio * v10 +
  213. (1 - xRatio) * v01 + xRatio * v11 +
  214. (1 - yRatio) * v00 + yRatio * v01 +
  215. (1 - yRatio) * v10 + yRatio * v11) * 0.25);
  216. //var result = v00;
  217. return ConvolutionColor.FromArgb(result);
  218. }
  219. private static Vector GetVector(DataSource dataSource, IntPoint index, Point position)
  220. {
  221. int ix0 = index.X;
  222. int iy0 = index.Y;
  223. int ix1 = ix0 + 1 < dataSource.Width ? ix0 + 1 : ix0;
  224. int iy1 = iy0 + 1 < dataSource.Height ? iy0 + 1 : iy0;
  225. var x0 = dataSource.XCoordinates[ix0];
  226. var x1 = dataSource.XCoordinates[ix1];
  227. var y0 = dataSource.YCoordinates[iy0];
  228. var y1 = dataSource.YCoordinates[iy1];
  229. double xRatio = GetRatio(x0, x1, position.X);
  230. double yRatio = GetRatio(y0, y1, position.Y);
  231. Vector v00 = dataSource.Data[ix0, iy0];
  232. Vector v01 = dataSource.Data[ix0, iy1];
  233. Vector v10 = dataSource.Data[ix1, iy0];
  234. Vector v11 = dataSource.Data[ix1, iy1];
  235. Vector result = (1 - xRatio) * v00 + xRatio * v10 +
  236. (1 - xRatio) * v01 + xRatio * v11 +
  237. (1 - yRatio) * v00 + yRatio * v01 +
  238. (1 - yRatio) * v10 + yRatio * v11;
  239. result *= 0.25;
  240. return result;
  241. }
  242. private static double GetRatio(double a, double b, double x)
  243. {
  244. if (a != b)
  245. return (x - a) / (b - a);
  246. else
  247. return x;
  248. }
  249. private static bool GetCoordinate(DataSource dataSource, Point point, out IntPoint coordinate)
  250. {
  251. var ix = IndexOf(dataSource.XCoordinates, point.X);
  252. int iy = IndexOf(dataSource.YCoordinates, point.Y);
  253. coordinate = new IntPoint(ix, iy);
  254. return ix > -1 && iy > -1;
  255. }
  256. private static int IndexOf(double[] coordinates, double x)
  257. {
  258. int ix = -1;
  259. for (int i = 0; i < coordinates.Length - 1; i++)
  260. {
  261. if (coordinates[i + 1] >= x)
  262. {
  263. ix = i;
  264. break;
  265. }
  266. }
  267. return ix;
  268. }
  269. //#region IPlotterElement Members
  270. //Plotter2D plotter;
  271. //public void OnPlotterAttached(Plotter plotter)
  272. //{
  273. // this.plotter = (Plotter2D)plotter;
  274. // plotter.CentralGrid.Children.Add(this);
  275. //}
  276. //public void OnPlotterDetaching(Plotter plotter)
  277. //{
  278. // plotter.CentralGrid.Children.Remove(this);
  279. // this.plotter = null;
  280. //}
  281. //public Plotter Plotter
  282. //{
  283. // get { return plotter; }
  284. //}
  285. //#endregion
  286. }
  287. }