コード例 #1
0
        /// <summary>
        /// Shifts values (the new margins get zero)
        /// </summary>
        /// <param name="sweep">The other axis (if x's are getting shifted, then do it for each y)</param>
        /// <param name="shift">The row/column that has values changing. ex: [x] = [x+1]</param>
        private void TranslateValues(AxisFor sweep, AxisFor shift)
        {
            int amount;
            if (!int.TryParse(txtMoveAmount.Text, out amount))
            {
                amount = 1;
            }

            amount *= shift.IsPos ? 1 : -1;

            foreach (int sweepIndex in sweep.Iterate())
            {
                foreach (int shiftIndex in shift.Iterate())
                {
                    int toX = -1;
                    int toY = -1;
                    sweep.Set2DIndex(ref toX, ref toY, sweepIndex);
                    shift.Set2DIndex(ref toX, ref toY, shiftIndex);

                    int fromX = -1;
                    int fromY = -1;
                    sweep.Set2DIndex(ref fromX, ref fromY, sweepIndex);
                    shift.Set2DIndex(ref fromX, ref fromY, shiftIndex + amount);

                    double value = 0;
                    if (fromX >= 0 && fromX < _width && fromY >= 0 && fromY < _height)
                    {
                        value = _values[fromY * _width + fromX];
                    }

                    _values[toY * _width + toX] = value;
                }
            }

            RebuildBars();
            PixelValueChanged();
        }
コード例 #2
0
        private static void DrawFieldSprtDoIt(byte[] pixels, double[] ink, bool[] blocked, int size, byte[] colorZFront, byte[] colorZBack, AxisFor pixelX, AxisFor pixelY, AxisFor pixelZ)
        {
            List<Mapping_2D_1D> flattened = new List<Mapping_2D_1D>();

            // Setup the pixel array
            //for (int y2D = pixelY.Start; pixelY.IsPos ? y2D <= pixelY.Stop : y2D >= pixelY.Stop; y2D += pixelY.Increment)
            foreach (int y2D in pixelY.Iterate())
            {
                int offsetY = pixelY.GetValueForOffset(y2D) * size;

                //for (int x2D = pixelX.Start; pixelX.IsPos ? x2D <= pixelX.Stop : x2D >= pixelX.Stop; x2D += pixelX.Increment)
                foreach (int x2D in pixelX.Iterate())
                {
                    int offset = offsetY + pixelX.GetValueForOffset(x2D);

                    flattened.Add(new Mapping_2D_1D(x2D, y2D, offset));
                }
            }

            // Each pixel of the output bitmap can be added up independently, so employ some threading
            flattened.AsParallel().ForAll(o =>
                {
                    //TODO: Color is 6.5 times slower than byte array
                    List<byte[]> colorColumn = new List<byte[]>();

                    for (int z2D = pixelZ.Start; pixelZ.IsPos ? z2D <= pixelZ.Stop : z2D >= pixelZ.Stop; z2D += pixelZ.Increment)
                    {
                        int x = -1, y = -1, z = -1;
                        pixelX.Set3DIndex(ref x, ref y, ref z, o.X);
                        pixelY.Set3DIndex(ref x, ref y, ref z, o.Y);
                        pixelZ.Set3DIndex(ref x, ref y, ref z, z2D);

                        int index = FluidField3D.Get1DIndex(x, y, z, size);
                        if (blocked[index])
                        {
                            // Blocked cells are all white, so save the overlay method a bit of work, and throw out everything behind this
                            colorColumn.Clear();
                            colorColumn.Add(new byte[] { 255, 255, 255, 255 });
                            continue;
                        }

                        double inkCell = ink[index];

                        if (Math1D.IsNearZero(inkCell))
                        {
                            continue;
                        }

                        byte[] depthColor = UtilityWPF.AlphaBlend(colorZBack, colorZFront, UtilityCore.GetScaledValue_Capped(0, 1, 0, size - 1, z));

                        int alpha = Convert.ToInt32(Math.Round(inkCell * 255));
                        if (alpha < 0)
                        {
                            alpha = 0;
                        }
                        else if (alpha > 255)
                        {
                            alpha = 255;
                        }

                        colorColumn.Add(new byte[] { Convert.ToByte(alpha), depthColor[1], depthColor[2], depthColor[3] });
                    }

                    byte[] color = colorColumn.Count > 0 ? UtilityWPF.OverlayColors(colorColumn) : new byte[] { 0, 0, 0, 0 };

                    pixels[o.Offset1D * 4 + 0] = color[3];   // Blue
                    pixels[o.Offset1D * 4 + 1] = color[2];     // Green
                    pixels[o.Offset1D * 4 + 2] = color[1];     // Red
                    pixels[o.Offset1D * 4 + 3] = color[0];   // Alpha
                });
        }
コード例 #3
0
 private static int GetOrthIncrement(AxisFor orth)
 {
     if (orth.Start == orth.Stop)
     {
         if (orth.Start == 0)
         {
             return 1;        // it's sitting on the zero edge.  Need to pull from the positive side
         }
         else
         {
             return -1;       // likely sitting on the other edge
         }
     }
     else
     {
         return orth.Increment * -1;
     }
 }
コード例 #4
0
        public static Convolution2D ExtendBorders(Convolution2D conv, int width, int height)
        {
            if (width < conv.Width || height < conv.Height)
            {
                throw new ArgumentException(string.Format("The new size can't be smaller than old.  Old={0},{1}  --  New={2},{3}", conv.Width, conv.Height, width, height));
            }

            VectorInt offset = new VectorInt()
            {
                X = (width - conv.Width) / 2,
                Y = (height - conv.Height) / 2,
            };

            double[] values = new double[width * height];

            #region Copy the image

            for (int y = 0; y < conv.Height; y++)
            {
                int offsetOrigY = y * conv.Width;
                int offsetNewY = (y + offset.Y) * width;

                for (int x = 0; x < conv.Width; x++)
                {
                    values[offsetNewY + offset.X + x] = conv.Values[offsetOrigY + x];
                }
            }

            #endregion

            #region Edges

            bool hasNegX = offset.X > 0;
            AxisFor forNegX = new AxisFor(Axis.X, offset.X - 1, 0);
            if (hasNegX)
            {
                ExtendEdge(values, width, conv.Width, forNegX, new AxisFor(Axis.Y, offset.Y, offset.Y + conv.Height - 1));
            }

            bool hasNegY = offset.Y > 0;
            AxisFor forNegY = new AxisFor(Axis.Y, offset.Y - 1, 0);
            if (hasNegY)
            {
                ExtendEdge(values, width, conv.Height, forNegY, new AxisFor(Axis.X, offset.X, offset.X + conv.Width - 1));
            }

            bool hasPosX = width > offset.X + conv.Width;
            AxisFor forPosX = new AxisFor(Axis.X, offset.X + conv.Width, width - 1);
            if (hasPosX)
            {
                ExtendEdge(values, width, conv.Width, forPosX, new AxisFor(Axis.Y, offset.Y, offset.Y + conv.Height - 1));
            }

            bool hasPosY = height > offset.Y + conv.Height;
            AxisFor forPosY = new AxisFor(Axis.Y, offset.Y + conv.Height, height - 1);
            if (hasPosY)
            {
                ExtendEdge(values, width, conv.Height, forPosY, new AxisFor(Axis.X, offset.X, offset.X + conv.Width - 1));
            }

            #endregion
            #region Corners

            if (hasNegX && hasNegY)
            {
                ExtendCorner(values, width, forNegX, forNegY);
            }

            if (hasPosX && hasNegY)
            {
                ExtendCorner(values, width, forPosX, forNegY);
            }

            if (hasPosX && hasPosY)
            {
                ExtendCorner(values, width, forPosX, forPosY);
            }

            if (hasNegX && hasPosY)
            {
                ExtendCorner(values, width, forNegX, forPosY);
            }

            #endregion

            return new Convolution2D(values, width, height, conv.IsNegPos);
        }
コード例 #5
0
        private static Convolution2D CopyRect(double[] values, int width, AxisFor edge, AxisFor orth, bool shouldRotate180)
        {
            if (shouldRotate180)
            {
                return CopyRect(values, width, new AxisFor(edge.Axis, edge.Stop, edge.Start), new AxisFor(orth.Axis, orth.Stop, orth.Start), false);
            }

            double[] retVal = new double[edge.Length * orth.Length];

            int index = 0;

            foreach (int orthIndex in orth.Iterate())
            {
                int x = -1;
                int y = -1;
                orth.Set2DIndex(ref x, ref y, orthIndex);

                foreach (int edgeIndex in edge.Iterate())
                {
                    edge.Set2DIndex(ref x, ref y, edgeIndex);

                    retVal[index] = values[(y * width) + x];

                    index++;
                }
            }

            return new Convolution2D(retVal, edge.Length, orth.Length, false);
        }
コード例 #6
0
        private static void OverlayRow(double[] values, int width, int orthIndex, double[] overlay, AxisFor orth, AxisFor edge, /*double opacity,*/ bool isLeftToRight)
        {
            int x = -1;
            int y = -1;
            orth.Set2DIndex(ref x, ref y, orthIndex);

            for (int cntr = 0; cntr < overlay.Length; cntr++)
            {
                int edgeIndex = -1;
                if (isLeftToRight)
                {
                    //edgeIndex = edge.Start + (cntr * edge.Increment);
                    edgeIndex = edge.Start + ((cntr + 1) * edge.Increment);
                }
                else
                {
                    //edgeIndex = edge.Stop - (cntr * edge.Increment);
                    edgeIndex = edge.Stop - ((cntr + 1) * edge.Increment);
                }

                edge.Set2DIndex(ref x, ref y, edgeIndex);

                int index = (y * width) + x;
                //values[index] = UtilityCore.GetScaledValue(values[index], overlay[cntr], 0d, 1d, opacity);
                values[index] = overlay[cntr];
            }
        }
コード例 #7
0
        /// <summary>
        /// Runs a gaussian over the current row and the two prior.  Then copies those blurred values onto this row
        /// </summary>
        /// <param name="orthIndex">The row being copied to</param>
        private static void OverlayBlurredPixels(double[] values, int width, int orthHeight, int orthIndex, int orthInc, int edgeMidStart, int edgeMidStop, AxisFor orth, AxisFor edge, Convolution2D gauss, /*int opacityDistance,*/ Random rand)
        {
            if (orthHeight < 2 || edgeMidStop < edgeMidStart)
            {
                // There's not enough to do a full 3x3 blur.  A smaller sized blur could be done, but that's a lot of extra logic, and not really worth the trouble
                return;
            }

            //double opacity = UtilityCore.GetScaledValue_Capped(0d, 1d, 0, opacityDistance, Math.Abs(orthIndex - orth.Start));

            // Get a random midpoint
            int edgeMid = rand.Next(edgeMidStart, edgeMidStop + 1);

            AxisFor orth3 = new AxisFor(orth.Axis, orthIndex + (orthInc * 2), orthIndex);
            AxisFor leftEdge = new AxisFor(edge.Axis, edge.Start, edgeMid + (edge.Increment * 2));
            AxisFor rightEdge = new AxisFor(edge.Axis, edgeMid - (edge.Increment * 2), edge.Stop);

            // Copy the values (these are 3 tall, and edgeMid-edgeStart+2 wide)
            Convolution2D leftRect = CopyRect(values, width, leftEdge, orth3, false);
            Convolution2D rightRect = CopyRect(values, width, rightEdge, orth3, true);      // this one is rotated 180 so that when the gaussian is applied, it will be from the right border to the mid

            // Apply a gaussian (these are 1 tall, and edgeMid-edgeStart wide)
            Convolution2D leftBlurred = Convolutions.Convolute(leftRect, gauss);
            Convolution2D rightBlurred = Convolutions.Convolute(rightRect, gauss);

            // Overlay onto this newest row
            //TODO: use an opacity LERP from original edge
            OverlayRow(values, width, orthIndex, leftBlurred.Values, orth, edge, /*opacity,*/ true);
            OverlayRow(values, width, orthIndex, rightBlurred.Values, orth, edge, /*opacity,*/ false);
        }
コード例 #8
0
        /// <summary>
        /// For each pixel in this row, pick a random pixel from a box above
        /// </summary>
        /// <remarks>
        /// At each pixel, this draws from a box of size orthDepth x (edgeDepth*2)+1
        /// </remarks>
        /// <param name="orthIndex">The row being copied to</param>
        private static void CopyRandomPixels(double[] values, int width, int orthIndex, int orthInc, int orthDepth, int edgeDepth, AxisFor orth, AxisFor edge, Random rand)
        {
            // See how many rows to randomly pull from
            int orthDepthStart = orthIndex + orthInc;
            int orthDepthStop = orthIndex + (orthDepth * orthInc);
            UtilityCore.MinMax(ref orthDepthStart, ref orthDepthStop);
            int orthAdd = orthInc < 0 ? 1 : 0;

            foreach (int edgeIndex in edge.Iterate())
            {
                // Figure out which column to pull from
                int toEdge = -1;
                do
                {
                    toEdge = rand.Next(edgeIndex - edgeDepth, edgeIndex + edgeDepth + 1);
                } while (!edge.IsBetween(toEdge));

                // Figure out which row to pull from
                int toOrth = rand.Next(orthDepthStart, orthDepthStop) + orthAdd;

                // From XY
                int fromX = -1;
                int fromY = -1;
                orth.Set2DIndex(ref fromX, ref fromY, toOrth);
                edge.Set2DIndex(ref fromX, ref fromY, toEdge);

                // To XY
                int toX = -1;
                int toY = -1;
                orth.Set2DIndex(ref toX, ref toY, orthIndex);
                edge.Set2DIndex(ref toX, ref toY, edgeIndex);

                // Copy pixel
                values[(toY * width) + toX] = values[(fromY * width) + fromX];
            }
        }
コード例 #9
0
        //TODO: Implement this properly
        private static void ExtendCorner(double[] values, int width, AxisFor orth, AxisFor edge)
        {
            Random rand = StaticRandom.GetRandomForThread();

            foreach (int edgeIndex in edge.Iterate())
            {
                foreach (int orthIndex in orth.Iterate())
                {
                    int x = -1;
                    int y = -1;
                    orth.Set2DIndex(ref x, ref y, orthIndex);
                    edge.Set2DIndex(ref x, ref y, edgeIndex);

                    values[(y * width) + x] = rand.Next(256);
                }
            }
        }
コード例 #10
0
        private static void ExtendEdge(double[] values, int width, int orthHeight, AxisFor orth, AxisFor edge)
        {
            const int EDGEDEPTH = 4;
            int ORTHDEPTH = Math.Min(5, orthHeight) + 1;

            const int EDGEMIDOFFSET = 5;

            // This isn't worth implementing, you just get a pixelated band
            //const int GAUSSOPACITYDIST = 1;       // how many pixels before the gaussian is full strength

            Random rand = StaticRandom.GetRandomForThread();

            Convolution2D gauss = Convolutions.GetGaussian(3);

            // Figure out which direction to copy rows from
            int orthInc = GetOrthIncrement(orth);

            #region Edge midpoint range

            // Each row, a random midpoint is chosen.  This way, an artifact won't be created down the middle.
            // mid start and stop are the range of possible values that the random midpoint can be from

            int edgeMidStart = edge.Start;
            int edgeMidStop = edge.Stop;

            UtilityCore.MinMax(ref edgeMidStart, ref edgeMidStop);

            edgeMidStart += EDGEMIDOFFSET;
            edgeMidStop -= EDGEMIDOFFSET;

            #endregion

            foreach (int orthIndex in orth.Iterate())
            {
                CopyRandomPixels(values, width, orthIndex, orthInc, ORTHDEPTH, EDGEDEPTH, orth, edge, rand);

                OverlayBlurredPixels(values, width, orthHeight, orthIndex, orthInc, edgeMidStart, edgeMidStop, orth, edge, gauss, /*GAUSSOPACITYDIST,*/ rand);
            }
        }
コード例 #11
0
        private void DrawLines_Plate(int numSamples, double half, double lineThickness, AxisFor axisX, AxisFor axisY, AxisFor axisZ)
        {
            const double ELAPSEDURATIONSECONDS = 1;

            // Figure out how wide to make the plate
            int totalSamples = numSamples * numSamples * numSamples;        // numsamples is per axis, so cube it
            int cellsPerSlice = _field.Size * _field.Size;
            int numSlices = Convert.ToInt32(Math.Round(Convert.ToDouble(totalSamples) / Convert.ToDouble(cellsPerSlice)));
            if (numSlices == 0)
            {
                numSlices = 1;
            }

            int toOffset = numSlices / 2;
            int fromOffset = numSlices - toOffset - 1;

            DateTime now = DateTime.UtcNow;

            bool isOverField = false;

            if (_mousePoint != null)
            {
                #region Snap to mouse

                // Cast a ray (Copied this from ItemSelectDragLogic.ChangeDragPlane, DragItem)

                Point3D point = new Point3D(0, 0, 0);

                RayHitTestParameters cameraLookCenter = UtilityWPF.RayFromViewportPoint(_camera, _viewport, new Point(_viewport.ActualWidth * .5d, _viewport.ActualHeight * .5d));

                // Come up with a snap plane
                Vector3D standard = Math3D.GetArbitraryOrhonganal(cameraLookCenter.Direction);
                Vector3D orth = Vector3D.CrossProduct(standard, cameraLookCenter.Direction);
                ITriangle plane = new Triangle(point, point + standard, point + orth);

                DragHitShape dragPlane = new DragHitShape();
                dragPlane.SetShape_Plane(plane);

                // Cast a ray onto that plane from the current mouse position
                RayHitTestParameters mouseRay = UtilityWPF.RayFromViewportPoint(_camera, _viewport, _mousePoint.Value);
                Point3D? hitPoint = dragPlane.CastRay(mouseRay);

                if (hitPoint != null)
                {
                    // Find the nearest Z cell
                    double halfSize = (_field.Size * _sizeMult) / 2d;
                    double cellSize = (_field.Size * _sizeMult) / _field.Size;

                    int zIndex = Convert.ToInt32((halfSize - axisZ.GetValue(hitPoint.Value)) / cellSize);

                    if (zIndex >= 0 && zIndex < _field.Size)
                    {
                        isOverField = true;

                        // Cap to field
                        _plateCurrentIndex = _field.Size - zIndex;        // it's actually the opposite
                        if (_plateCurrentIndex - fromOffset < 0)
                        {
                            _plateCurrentIndex = fromOffset;
                        }
                        else if (_plateCurrentIndex + toOffset > _field.Size - 1)
                        {
                            _plateCurrentIndex = _field.Size - toOffset - 1;
                        }

                        _sceneRemaining = now + TimeSpan.FromSeconds(ELAPSEDURATIONSECONDS);
                    }
                }

                #endregion
            }

            if (!isOverField)
            {
                #region Shift the plate

                if (_plateCurrentIndex + toOffset > _field.Size - 1)
                {
                    _plateCurrentIndex = _field.Size - toOffset - 1;
                    _sceneRemaining = now + TimeSpan.FromSeconds(ELAPSEDURATIONSECONDS);
                }
                else if (now > _sceneRemaining)
                {
                    _plateCurrentIndex--;

                    if (_plateCurrentIndex - fromOffset <= 0)
                    {
                        _plateCurrentIndex = _field.Size - toOffset - 1;
                    }

                    _sceneRemaining = now + TimeSpan.FromSeconds(ELAPSEDURATIONSECONDS);
                }

                #endregion
            }

            double[] velX = _field.VelocityX;
            double[] velY = _field.VelocityY;
            double[] velZ = _field.VelocityZ;

            bool[] blocked = _field.Blocked;

            _velocityLines.BeginAddingLines();

            for (int z = _plateCurrentIndex - fromOffset; z <= _plateCurrentIndex + toOffset; z++)
            {
                for (int x = 0; x < _field.Size; x++)
                {
                    for (int y = 0; y < _field.Size; y++)
                    {
                        int xRef = -1;
                        int yRef = -1;
                        int zRef = -1;

                        axisX.Set3DIndex(ref xRef, ref yRef, ref zRef, x);
                        axisY.Set3DIndex(ref xRef, ref yRef, ref zRef, y);
                        axisZ.Set3DIndex(ref xRef, ref yRef, ref zRef, z);

                        int index1D = _field.Get1DIndex(xRef, yRef, zRef);

                        if (blocked[index1D])
                        {
                            continue;
                        }

                        DrawLinesSprtAddLine(xRef, yRef, zRef, index1D, half, lineThickness, velX, velY, velZ);
                    }
                }
            }

            _velocityLines.EndAddingLines();
        }