Пример #1
0
        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));
        }
Пример #2
0
        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);
        }
Пример #3
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());
        }
Пример #4
0
        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());
        }
Пример #5
0
        /// <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));
        }
Пример #6
0
        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);
            }
        }
Пример #7
0
        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();
        }
Пример #8
0
        public VelocityVisualizerVisualHost(FluidField2D field)
        {
            _field = field;

            this.AddVisualChild(_visual);
        }