private static Tuple <int, int> GetFieldPoint_XY(Point point, FluidField2D field) { int x = Convert.ToInt32(Math.Round(point.X * field.XSize)); if (x < 0) { x = 0; } else if (x >= field.XSize) { x = field.XSize - 1; } int y = Convert.ToInt32(Math.Round(point.Y * field.XSize)); if (y < 0) { y = 0; } else if (y >= field.YSize) { y = field.YSize - 1; } return(Tuple.Create(x, y)); }
private static void DrawField(WriteableBitmap bitmap, FluidField2D field, bool showBlockedCells) { Int32Rect rect = new Int32Rect(0, 0, field.XSize, field.YSize); int size = rect.Width * rect.Height * 4; byte[] pixels = new byte[size]; double[] reds = field.GetLayer(0); double[] greens = field.GetLayer(1); double[] blues = field.GetLayer(2); var blockedCells = field.Blocked; //NOTE: The field's arrays happen to be the same layout as the rect, so there's no need to call field.GetK // Setup the pixel array for (int i = 0; i < rect.Height * rect.Width; i++) { if (blockedCells[i] && showBlockedCells) { pixels[i * 4 + 0] = 255; // Blue pixels[i * 4 + 1] = 255; // Green pixels[i * 4 + 2] = 255; // Red pixels[i * 4 + 3] = 255; // Alpha } else { pixels[i * 4 + 0] = ConvertToByteCapped(blues[i] * 256); // Blue pixels[i * 4 + 1] = ConvertToByteCapped(greens[i] * 256); // Green pixels[i * 4 + 2] = ConvertToByteCapped(reds[i] * 256); // Red pixels[i * 4 + 3] = 255; // Alpha } } bitmap.WritePixels(rect, pixels, rect.Width * 4, 0); }
private static Tuple <int, double>[] GetFieldCircle(Point point, double radiusX, double radiusY, double valueCenter, double valueEdge, FluidField2D field) { // Get the box that contains the return circle var center = GetFieldPoint_XY(new Point(point.X, point.Y), field); var min = GetFieldPoint_XY(new Point(point.X - radiusX, point.Y - radiusY), field); var max = GetFieldPoint_XY(new Point(point.X + radiusX, point.Y + radiusY), field); // Get points that are inside the circle List <Tuple <int, double> > retVal = new List <Tuple <int, double> >(); Vector radius = new Vector(radiusX * field.XSize, radiusY * field.YSize); double maxDistance = ((radiusX * field.XSize) + (radiusY * field.YSize)) * .5d; // just take the average. TODO: see if inside the ellipse double maxDistanceSquared = maxDistance * maxDistance; for (int x = min.Item1; x <= max.Item1; x++) { for (int y = min.Item2; y <= max.Item2; y++) { double dx = x - center.Item1; double dy = y - center.Item2; double distanceSquared = (dx * dx) + (dy * dy); if (distanceSquared <= maxDistanceSquared) { double distance = Math.Sqrt(distanceSquared); retVal.Add(Tuple.Create( field.GetK(x, y), // coordinates that the field wants UtilityCore.GetScaledValue(valueCenter, valueEdge, 0, maxDistance, distance) // LERP )); } } } // Exit Function return(retVal.ToArray()); }
private static int[] GetFieldCircle(Point point, double radiusX, double radiusY, FluidField2D field) { // Get the box that contains the return circle var center = GetFieldPoint_XY(point, field); var min = GetFieldPoint_XY(new Point(point.X - radiusX, point.Y - radiusY), field); var max = GetFieldPoint_XY(new Point(point.X + radiusX, point.Y + radiusY), field); // Get points that are inside the circle List <int> retVal = new List <int>(); double maxDistance = ((radiusX * field.XSize) + (radiusY * field.YSize)) * .5d; // just take the average. TODO: see if inside the ellipse double maxDistanceSquared = maxDistance * maxDistance; for (int x = min.Item1; x <= max.Item1; x++) { for (int y = min.Item2; y <= max.Item2; y++) { double dx = x - center.Item1; double dy = y - center.Item2; double distanceSquared = (dx * dx) + (dy * dy); if (distanceSquared <= maxDistanceSquared) { retVal.Add(field.GetK(x, y)); } } } // Exit Function return(retVal.ToArray()); }
/// <summary> /// This takes a point from 0 to 1, and returns the corresponding position in the field (what the field calls k) /// </summary> private static int GetFieldPoint(Point point, FluidField2D field) { var xy = GetFieldPoint_XY(point, field); return(field.GetK(xy.Item1, xy.Item2)); }
private void Window_Loaded(object sender, RoutedEventArgs e) { try { // Field _field = new FluidField2D(200, 200, 3); _field.UseCheapDiffusion = !chkUseStandardDiffusion.IsChecked.Value; _field.Vorticity = 0; //this is currently broken // Sliders PropertyInfo[] propsOptions = typeof(FluidField2D).GetProperties(); _propLinks.Add(new SliderShowValues.PropSync(trkDiffusion, propsOptions.Where(o => o.Name == "Diffusion").First(), _field, 0, .1)); _propLinks.Add(new SliderShowValues.PropSync(trkViscocity, propsOptions.Where(o => o.Name == "Viscosity").First(), _field, 0, .1)); _propLinks.Add(new SliderShowValues.PropSync(trkWallReflection, propsOptions.Where(o => o.Name == "WallReflectivity").First(), _field, 0, 1)); _propLinks.Add(new SliderShowValues.PropSync(trkVorticity, propsOptions.Where(o => o.Name == "Vorticity").First(), _field, 0, 1)); _propLinks.Add(new SliderShowValues.PropSync(trkTimestep, propsOptions.Where(o => o.Name == "TimeStep").First(), _field, 0, 100)); _propLinks.Add(new SliderShowValues.PropSync(trkIterations, propsOptions.Where(o => o.Name == "Iterations").First(), _field, 0, 20)); _colorBrushSize = new SliderSettings() { Min = 0, Max = .5, Value = .125 }; _wallBrushSize = new SliderSettings() { Min = 0, Max = .1, Value = .033 }; trkBrushSize.Minimum = _colorBrushSize.Min; trkBrushSize.Maximum = _colorBrushSize.Max; trkBrushSize.Value = _colorBrushSize.Value; trkVelocityMultiplier.Minimum = .1; trkVelocityMultiplier.Maximum = 100; //NOTE: the right side scales from 1 to 100, but the left side scales from 1/10 to 1 (because large multipliers are more interesting) trkVelocityMultiplier.Value = 8; ResetField(); // Create a new image Image img = new Image(); RenderOptions.SetBitmapScalingMode(img, BitmapScalingMode.NearestNeighbor); RenderOptions.SetEdgeMode(img, EdgeMode.Aliased); // Add this image to the canvas grdFluid.Children.Add(img); // Create the bitmap, and set _bitmap = new WriteableBitmap(_field.XSize, _field.YSize, UtilityWPF.DPI, UtilityWPF.DPI, PixelFormats.Bgra32, null); img.Source = _bitmap; img.Stretch = Stretch.Fill; // Timer _timer = new DispatcherTimer(); _timer.Interval = TimeSpan.FromMilliseconds(1); _timer.Tick += Timer_Tick; _timer.IsEnabled = true; // Need to manually set the scrollviewer's height (a binding can't be conditional - see Window_SizeChanged) expanderScrollViewer.MaxHeight = expanderRow.ActualHeight; _isInitialized = true; } catch (Exception ex) { MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error); } }
public void Update() { const int NUMSAMPLES = 20; double width = this.ActualWidth; double height = this.ActualHeight; if (double.IsNaN(width) || double.IsInfinity(width)) { // This control isn't visible yet return; } DrawingContext drawing = _visual.RenderOpen(); double[] xVel, yVel; xVel = _field.XVel; yVel = _field.YVel; int xSize = _field.XSize; int ySize = _field.YSize; double cellWidth = width / xSize; double cellHeight = height / ySize; double cellHalfWidth = cellWidth / 2d; double cellHalfHeight = cellHeight / 2d; double scale = (width + height) / 2d; double dotRadius = (cellWidth + cellHeight) / 5d; // Always include 0 and size - 1. The rest should be evenly distributed double incX = Convert.ToDouble(xSize - 1) / (NUMSAMPLES - 1); // subtracting 1 to guarantee the edges get one double incY = Convert.ToDouble(ySize - 1) / (NUMSAMPLES - 1); for (double xd = 0; xd < xSize; xd += incX) { for (double yd = 0; yd < ySize; yd += incY) { int x = Convert.ToInt32(Math.Round(xd)); if (x > xSize - 1) { x = xSize - 1; } int y = Convert.ToInt32(Math.Round(yd)); if (y > ySize - 1) { y = ySize - 1; } // Figure out the center of this cell Point center = new Point((cellWidth * x) + cellHalfWidth, (cellHeight * y) + cellHalfHeight); // Add the velocity at this cell int index = FluidField2D.GetK(xSize, x, y); Point end = new Point(center.X + (xVel[index] * scale), center.Y + (yVel[index] * scale)); drawing.DrawLine(_pen, center, end); //drawing.DrawEllipse(Brushes.Gold, _pen, center, dotRadius, dotRadius); // too expensive } } drawing.Close(); this.InvalidateVisual(); }
public VelocityVisualizerVisualHost(FluidField2D field) { _field = field; this.AddVisualChild(_visual); }