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