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); }
public FluidFieldField(FluidField3D field) { _field = field; }
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); } }
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; }
public static int[] GetBlockedCells(FluidField3D field, ITriangleIndexed[] hull) { return GetBlockedCells(field, new ITriangleIndexed[][] { hull }); }