private static Tuple<int, int, int> GetFieldPoint_XYZ(Point3D point, FluidField3D field)
        {
            int x = Convert.ToInt32(Math.Round(point.X * field.Size));
            if (x < 0)
            {
                x = 0;
            }
            else if (x >= field.Size)
            {
                x = field.Size - 1;
            }

            int y = Convert.ToInt32(Math.Round(point.Y * field.Size));
            if (y < 0)
            {
                y = 0;
            }
            else if (y >= field.Size)
            {
                y = field.Size - 1;
            }

            int z = Convert.ToInt32(Math.Round(point.Z * field.Size));
            if (z < 0)
            {
                z = 0;
            }
            else if (z >= field.Size)
            {
                z = field.Size - 1;
            }

            return Tuple.Create(x, y, z);
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                // Field
                _field = new FluidField3D(40);
                _field.Diffusion = 0;
                _field.Damping = 0;

                // Sliders
                PropertyInfo[] propsOptions = typeof(FluidField3D).GetProperties();
                _propLinks.Add(new SliderShowValues.PropSync(trkDiffusion, propsOptions.Where(o => o.Name == "Diffusion").First(), _field, 0, .03));
                _propLinks.Add(new SliderShowValues.PropSync(trkDamping, propsOptions.Where(o => o.Name == "Damping").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));

                trkBrushSize.Minimum = 0;
                trkBrushSize.Maximum = .5;
                trkBrushSize.Value = .15;

                trkVelocityMultiplier.Minimum = .1;
                trkVelocityMultiplier.Maximum = 20;
                trkVelocityMultiplier.Value = 3;

                trkBrushDepth.Minimum = 0;
                trkBrushDepth.Maximum = 1;
                trkBrushDepth.Value = .5;

                // 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.Size, _field.Size, 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);
            }
        }
        private static int[] GetFieldSphere(Point3D point, double radius, FluidField3D field)
        {
            // Get the box that contains the return circle
            var center = GetFieldPoint_XYZ(point, field);
            var min = GetFieldPoint_XYZ(new Point3D(point.X - radius, point.Y - radius, point.Z - radius), field);
            var max = GetFieldPoint_XYZ(new Point3D(point.X + radius, point.Y + radius, point.Z + radius), field);

            // Get points that are inside the circle
            List<int> retVal = new List<int>();
            double maxDistance = radius * field.Size;
            double maxDistanceSquared = maxDistance * maxDistance;

            for (int x = min.Item1; x <= max.Item1; x++)
            {
                for (int y = min.Item2; y <= max.Item2; y++)
                {
                    for (int z = min.Item3; z <= max.Item3; z++)
                    {
                        double dx = x - center.Item1;
                        double dy = y - center.Item2;
                        double dz = z - center.Item3;
                        double distanceSquared = (dx * dx) + (dy * dy) + (dz * dz);

                        if (distanceSquared <= maxDistanceSquared)
                        {
                            retVal.Add(field.Get1DIndex(x, y, z));
                        }
                    }
                }
            }

            // Exit Function
            return retVal.ToArray();
        }
        private static void DrawField(WriteableBitmap bitmap, FluidField3D field, ViewDirection viewDirection, byte[] colorZFront, byte[] colorZBack)
        {
            Int32Rect rect = new Int32Rect(0, 0, field.Size, field.Size);
            int size = rect.Width * rect.Height * 4;
            byte[] pixels = new byte[size];

            double[] ink = field.Ink;
            bool[] blocked = field.Blocked;

            switch (viewDirection)
            {
                case ViewDirection.Front:
                    #region Front

                    DrawFieldSprtDoIt(pixels, ink, blocked, field.Size, colorZFront, colorZBack,
                        new AxisFor(Axis.X, 0, field.Size - 1),
                        new AxisFor(Axis.Y, 0, field.Size - 1),
                        new AxisFor(Axis.Z, field.Size - 1, 0));        // pixel z needs to start at the back, because the colors are overlaid

                    #endregion
                    break;

                case ViewDirection.Right:
                    #region Right

                    DrawFieldSprtDoIt(pixels, ink, blocked, field.Size, colorZFront, colorZBack,
                        new AxisFor(Axis.Z, 0, field.Size - 1),
                        new AxisFor(Axis.Y, 0, field.Size - 1),
                        new AxisFor(Axis.X, 0, field.Size - 1));

                    #endregion
                    break;

                case ViewDirection.Left:
                    #region Left

                    DrawFieldSprtDoIt(pixels, ink, blocked, field.Size, colorZFront, colorZBack,
                        new AxisFor(Axis.Z, field.Size - 1, 0),
                        new AxisFor(Axis.Y, 0, field.Size - 1),
                        new AxisFor(Axis.X, field.Size - 1, 0));

                    #endregion
                    break;

                case ViewDirection.Top:
                    #region Top

                    DrawFieldSprtDoIt(pixels, ink, blocked, field.Size, colorZFront, colorZBack,
                        new AxisFor(Axis.X, 0, field.Size - 1),
                        new AxisFor(Axis.Z, field.Size - 1, 0),
                        new AxisFor(Axis.Y, field.Size - 1, 0));

                    #endregion
                    break;

                case ViewDirection.Bottom:
                    #region Bottom

                    DrawFieldSprtDoIt(pixels, ink, blocked, field.Size, colorZFront, colorZBack,
                        new AxisFor(Axis.X, 0, field.Size - 1),
                        new AxisFor(Axis.Z, 0, field.Size - 1),
                        new AxisFor(Axis.Y, 0, field.Size - 1));

                    #endregion
                    break;

                case ViewDirection.Back:
                    #region Back

                    //NOTE: This one is up for interpretation.  I will rotate left to right, because I think that is more intuitive.  If rotating
                    //top to bottom, it would be upside down from the way I am presenting
                    DrawFieldSprtDoIt(pixels, ink, blocked, field.Size, colorZFront, colorZBack,
                        new AxisFor(Axis.X, field.Size - 1, 0),
                        new AxisFor(Axis.Y, 0, field.Size - 1),
                        new AxisFor(Axis.Z, 0, field.Size - 1));

                    // The alternate
                    //DrawField_DoIt(pixels, ink, blocked, field.Size, colorZFront, colorZBack,
                    //    new AxisFor(Axis.X, 0, field.Size - 1),
                    //    new AxisFor(Axis.Y, field.Size - 1, 0),
                    //    new AxisFor(Axis.Z, 0, field.Size - 1));

                    #endregion
                    break;

                default:
                    throw new ApplicationException("Unknown ViewDirection: " + viewDirection.ToString());
            }

            bitmap.WritePixels(rect, pixels, rect.Width * 4, 0);
        }
Пример #5
0
 public FluidFieldField(FluidField3D field)
 {
     _field = field;
 }
Пример #6
0
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                // Init World
                _world = new World();
                _world.Updating += new EventHandler<WorldUpdatingArgs>(World_Updating);
                _world.SetWorldSize(new Point3D(-100, -100, -100), new Point3D(100, 100, 100));
                _world.UnPause();

                // Camera Trackball
                _trackball = new TrackBallRoam(_camera);
                //_trackball.ShouldHitTestOnOrbit = true;
                _trackball.EventSource = grdViewPort;		//NOTE:  If this control doesn't have a background color set, the trackball won't see events (I think transparent is ok, just not null)
                _trackball.AllowZoomOnMouseWheel = true;
                _trackball.Mappings.AddRange(TrackBallMapping.GetPrebuilt(TrackBallMapping.PrebuiltMapping.MouseComplete));
                //_trackball.GetOrbitRadius += new GetOrbitRadiusHandler(Trackball_GetOrbitRadius);

                // Trackball Controls
                SetupModelTrackball();
                SetupFlowTrackball();

                // Fluid lines
                AddFluidVisuals(Convert.ToInt32(NUMFLUIDVISUALS * _flowViscosity));

                // Force lines
                _fluidHullForceLines = new ScreenSpaceLines3D(true);
                _fluidHullForceLines.Color = _colors.ForceLine;
                _fluidHullForceLines.Thickness = 2d;

                _viewport.Children.Add(_fluidHullForceLines);

                // Field - may want to only add this when a body is added
                _field = new FluidField3D(20);
                _field.Diffusion = 0;
                _field.Damping = 0; //GetFluidViscocity();        // this stays zero (see comments in VelocityViscocityChanged)

                _field.BoundryType = FluidFieldBoundryType3D.Open_Slaved;
                _fieldUniform = new FluidFieldUniform();
                _field.OpenBoundryParent = _fieldUniform;
                _field.SizeWorld = 10d;     // This changes whenever a body is swapped out

                _fieldCells = _field.GetCells();

                _fieldField = new FluidFieldField(_field);
                _fieldField.Viscosity = GetFluidViscocity();

                _isInitialized = true;

                ShowHideFluidBoundry();
                ShowHideBlockedCells();

                VelocityViscocityChanged();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
Пример #7
0
            public static int[] GetBlockedCells(FluidField3D field, IEnumerable<ITriangleIndexed[]> hulls)
            {
                //NOTE: The hulls need to be in model coords

                // Get populated hulls
                ITriangleIndexed[][] hulls1 = hulls.Where(o => o.Length > 0).ToArray();
                if (hulls1.Length == 0)
                {
                    return new int[0];      // no hulls were passed in
                }

                // Get the location of all the cells
                Rectangle3DIndexedMapped[] cells1 = field.GetCells();

                #region Filter AABB

                // Remove non aabb matches
                Rect3D[] aabbs = hulls1.Select(o => Math3D.GetAABB_Rect(o[0].AllPoints)).ToArray();

                Rectangle3DIndexedMapped[] cells2 = cells1.Where(o =>
                {
                    Rect3D cellRect = o.ToRect3D();
                    return aabbs.Any(p => p.OverlapsWith(cellRect));
                }).ToArray();

                if (cells2.Length == 0)
                {
                    return new int[0];      // this should never happen
                }

                #endregion

                //TODO: When multiple hulls are passed in, ignore cells that are outside of a particular hull's aabb

                #region Test triangles

                // Look for intersecting edges
                int[] edgeMatches = new int[0];
                if (cells2.Length > 0)
                {
                    // aabbs is for entire hulls.  This needs to be for each triangle in each hull
                    Tuple<ITriangle, Rect3D>[] hullTrianglesAABBs = hulls.SelectMany(o => o.Select(p => new Tuple<ITriangle, Rect3D>(p, Math3D.GetAABB_Rect(p)))).ToArray();

                    // Now compare each remaining candidate cell to each triangle of each hull
                    edgeMatches = GetBlockedCellsSprtEdgeMap(cells2).
                        AsParallel().
                        Where(o => hullTrianglesAABBs.Any(p => IsEdgeMatch(p, o.Item1))).
                        SelectMany(o => o.Item2.Select(p => cells2[p].Mapping.Offset1D)).       // add all the cells that neighbor this corner point
                        Distinct().     // need distinct, since cells were added multiple times
                        ToArray();
                }

                #endregion

                // Exit Function
                return edgeMatches;
            }
Пример #8
0
 public static int[] GetBlockedCells(FluidField3D field, ITriangleIndexed[] hull)
 {
     return GetBlockedCells(field, new ITriangleIndexed[][] { hull });
 }