/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
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}