コード例 #1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="field"></param>
        /// <param name="parallel"></param>
        /// <returns></returns>
        public static GridField2d <double> GetCurl(this GridField2d <Vector2d> field, bool parallel = false)
        {
            var result = GridField2d.Double.Create(field);

            GetCurl(field, result, parallel);
            return(result);
        }
コード例 #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="field"></param>
        /// <param name="parallel"></param>
        /// <returns></returns>
        public static GridField2d <Vector2d> GetGradient(this GridField2d <double> field, bool parallel = false)
        {
            var result = GridField2d.Vector2d.Create(field);

            GetGradient(field, result, parallel);
            return(result);
        }
コード例 #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="field"></param>
        /// <param name="parallel"></param>
        /// <returns></returns>
        public static GridField2d <double> GetLaplacian(this GridField2d <double> field, bool parallel = false)
        {
            var result = GridField2d.Double.Create(field);

            GetLaplacian(field, result, parallel);
            return(result);
        }
コード例 #4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public GridField2d <T> CreateCopy(GridField2d <T> other)
        {
            var result = Create(other);

            result.Set(other);
            return(result);
        }
コード例 #5
0
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="U"></typeparam>
        /// <param name="other"></param>
        /// <param name="converter"></param>
        /// <param name="parallel"></param>
        /// <returns></returns>
        public GridField2d <T> CreateCopy <U>(GridField2d <U> other, Func <U, T> converter, bool parallel = false)
            where U : struct
        {
            var result = Create(other);

            other.Convert(converter, result, parallel);
            return(result);
        }
コード例 #6
0
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="U"></typeparam>
        /// <param name="other"></param>
        /// <returns></returns>
        public GridField2d <T> Create <U>(GridField2d <U> other)
            where U : struct
        {
            var result = Create((Grid2d)other);

            result.SampleMode = other.SampleMode;
            return(result);
        }
コード例 #7
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="field"></param>
        /// <param name="point"></param>
        /// <param name="value"></param>
        public static void SetAt(this GridField2d <Vector2d> field, ref GridPoint2d point, Vector2d value)
        {
            var vals = field.Values;

            vals[point.Index0] += (value - vals[point.Index0]) * point.Weight0;
            vals[point.Index1] += (value - vals[point.Index1]) * point.Weight1;
            vals[point.Index2] += (value - vals[point.Index2]) * point.Weight2;
            vals[point.Index3] += (value - vals[point.Index3]) * point.Weight3;
        }
コード例 #8
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="field"></param>
        /// <param name="point"></param>
        /// <param name="amount"></param>
        public static void IncrementAt(this GridField2d <Vector2d> field, ref GridPoint2d point, Vector2d amount)
        {
            var vals = field.Values;

            vals[point.Index0] += amount * point.Weight0;
            vals[point.Index1] += amount * point.Weight1;
            vals[point.Index2] += amount * point.Weight2;
            vals[point.Index3] += amount * point.Weight3;
        }
コード例 #9
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="field"></param>
        /// <param name="result"></param>
        /// <param name="parallel"></param>
        public static void GetLaplacian(this GridField2d <double> field, double[] result, bool parallel = false)
        {
            if (parallel)
            {
                Parallel.ForEach(Partitioner.Create(0, field.CountXY), range => Body(range.Item1, range.Item2));
            }
            else
            {
                Body(0, field.CountXY);
            }

            void Body(int from, int to)
            {
                var vals = field.Values;

                (var nx, var ny) = field.Count;
                (var dx, var dy) = field.Scale;
                dx = 1.0 / (dx * dx);
                dy = 1.0 / (dy * dy);

                (int di, int dj) = field.GetBoundaryOffsets();
                (int i, int j)   = field.ToGridSpace(from);

                for (int index = from; index < to; index++, i++)
                {
                    if (i == nx)
                    {
                        j++; i = 0;
                    }

                    double tx0 = (i == 0) ? vals[index + di] : vals[index - 1];
                    double tx1 = (i == nx - 1) ? vals[index - di] : vals[index + 1];

                    double ty0 = (j == 0) ? vals[index + dj] : vals[index - nx];
                    double ty1 = (j == ny - 1) ? vals[index - dj] : vals[index + nx];

                    double t = vals[index] * 2.0;
                    result[index] = (tx0 + tx1 - t) * dx + (ty0 + ty1 - t) * dy;
                }
            }
        }
コード例 #10
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="field"></param>
        /// <param name="result"></param>
        /// <param name="parallel"></param>
        public static void GetCurl(this GridField2d <Vector2d> field, double[] result, bool parallel = false)
        {
            // implementation reference
            // http://www.math.harvard.edu/archive/21a_spring_09/PDF/13-05-curl-and-divergence.pdf

            if (parallel)
            {
                Parallel.ForEach(Partitioner.Create(0, field.CountXY), range => Body(range.Item1, range.Item2));
            }
            else
            {
                Body(0, field.CountXY);
            }

            void Body(int from, int to)
            {
                var vals = field.Values;

                (var nx, var ny) = field.Count;
                (var tx, var ty) = (0.5 / field.Scale);
                (int di, int dj) = field.GetBoundaryOffsets();
                (int i, int j)   = field.ToGridSpace(from);

                for (int index = from; index < to; index++, i++)
                {
                    if (i == nx)
                    {
                        j++; i = 0;
                    }

                    Vector2d tx0 = (i == 0) ? vals[index + di] : vals[index - 1];
                    Vector2d tx1 = (i == nx - 1) ? vals[index - di] : vals[index + 1];

                    Vector2d ty0 = (j == 0) ? vals[index + dj] : vals[index - nx];
                    Vector2d ty1 = (j == ny - 1) ? vals[index - dj] : vals[index + nx];

                    result[index] = (tx1.Y - tx0.Y) * tx - (ty1.X - ty0.X) * ty;
                }
            }
        }
コード例 #11
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="field"></param>
        /// <param name="result"></param>
        /// <param name="parallel"></param>
        public static void GetDivergence(this GridField2d <Vector2d> field, double[] result, bool parallel = false)
        {
            if (parallel)
            {
                Parallel.ForEach(Partitioner.Create(0, field.CountXY), range => Body(range.Item1, range.Item2));
            }
            else
            {
                Body(0, field.CountXY);
            }

            void Body(int from, int to)
            {
                var vals = field.Values;

                (var nx, var ny) = field.Count;
                (var dx, var dy) = (0.5 / field.Scale);
                (int di, int dj) = field.GetBoundaryOffsets();
                (int i, int j)   = field.ToGridSpace(from);

                for (int index = from; index < to; index++, i++)
                {
                    if (i == nx)
                    {
                        j++; i = 0;
                    }

                    Vector2d tx0 = (i == 0) ? vals[index + di] : vals[index - 1];
                    Vector2d tx1 = (i == nx - 1) ? vals[index - di] : vals[index + 1];

                    Vector2d ty0 = (j == 0) ? vals[index + dj] : vals[index - nx];
                    Vector2d ty1 = (j == ny - 1) ? vals[index - dj] : vals[index + nx];

                    result[index] = (tx1.X - tx0.X) * dx + (ty1.Y - ty0.Y) * dy;
                }
            }
        }
コード例 #12
0
        /// <summary>
        /// Calculates the L2 (Euclidiean) geodesic distance from the given sources.
        /// </summary>
        /// <param name="cost"></param>
        /// <param name="sources"></param>
        /// <param name="result"></param>
        /// <param name="exclude"></param>
        public static void CalculateL2(GridField2d <double> cost, IEnumerable <int> sources, double[] result, IEnumerable <int> exclude = null)
        {
            // impl ref
            // http://www.numerical-tours.com/matlab/fastmarching_0_implementing/

            var costVals = cost.Values;

            (var nx, var ny) = cost.Count;
            (var dx, var dy) = Vector2d.Abs(cost.Scale);
            var eikonal = new Eikonal2d(dx, dy);

            var queue = new PriorityQueue <double, int>();

            result.SetRange(double.PositiveInfinity, cost.CountXY);

            // enqueue sources
            foreach (int i in sources)
            {
                result[i] = 0.0;
                queue.Insert(0.0, i);
            }

            // exclude
            if (exclude != null)
            {
                foreach (var i in exclude)
                {
                    result[i] = 0.0;
                }
            }

            // breadth first search from sources
            while (queue.Count > 0)
            {
                (double d0, int i0) = queue.RemoveMin();
                if (result[i0] < d0)
                {
                    continue;                  // skip if lower value has been assigned
                }
                (int x0, int y0) = cost.ToGridSpace(i0);

                if (x0 > 0)
                {
                    TryUpdateX(i0 - 1);
                }

                if (x0 < nx - 1)
                {
                    TryUpdateX(i0 + 1);
                }

                if (y0 > 0)
                {
                    TryUpdateY(i0 - nx);
                }

                if (y0 < ny - 1)
                {
                    TryUpdateY(i0 + nx);
                }

                // process x neighbor
                void TryUpdateX(int index)
                {
                    var d1 = result[index];

                    if (d1 < d0)
                    {
                        return;          // no backtracking
                    }
                    double d2;
                    double minY = GetMinY(index); // will return infinity if neither neighbor has been visited

                    if (minY > double.MaxValue || !eikonal.Solve(d0, minY, costVals[index], out d2))
                    {
                        d2 = d0 + dx * costVals[index];
                    }

                    // add to queue if less than current min
                    if (d2 < d1)
                    {
                        result[index] = d2;
                        queue.Insert(d2, index);
                    }
                }

                // process y neighbor
                void TryUpdateY(int index)
                {
                    var d1 = result[index];

                    if (d1 < d0)
                    {
                        return;          // no backtracking
                    }
                    double d2;
                    double minX = GetMinX(index); // will return infinity if neither neighbor has been visited

                    if (minX > double.MaxValue || !eikonal.Solve(minX, d0, costVals[index], out d2))
                    {
                        d2 = d0 + dy * costVals[index];
                    }

                    // add to queue if less than current min
                    if (d2 < d1)
                    {
                        result[index] = d2;
                        queue.Insert(d2, index);
                    }
                }

                // returns the minimum adjacent value in the x
                double GetMinX(int index)
                {
                    if (x0 == 0)
                    {
                        return(result[index + 1]);
                    }
                    else if (x0 == nx - 1)
                    {
                        return(result[index - 1]);
                    }

                    return(Math.Min(result[index - 1], result[index + 1]));
                }

                // returns the minimum adjacent value in the y
                double GetMinY(int index)
                {
                    if (y0 == 0)
                    {
                        return(result[index + nx]);
                    }
                    else if (y0 == ny - 1)
                    {
                        return(result[index - nx]);
                    }

                    return(Math.Min(result[index - nx], result[index + nx]));
                }
            }
        }
コード例 #13
0
        /// <summary>
        /// Calculates the L1 (Manhattan) geodesic distance from the given sources.
        /// </summary>
        /// <param name="cost"></param>
        /// <param name="sources"></param>
        /// <param name="result"></param>
        /// <param name="exclude"></param>
        public static void CalculateL1(GridField2d <double> cost, IEnumerable <int> sources, double[] result, IEnumerable <int> exclude = null)
        {
            // impl ref
            // http://www.numerical-tours.com/matlab/fastmarching_0_implementing/

            var costVals = cost.Values;

            (var nx, var ny)       = cost.Count;
            (double dx, double dy) = Vector2d.Abs(cost.Scale);

            var queue = new PriorityQueue <double, int>();

            result.SetRange(double.PositiveInfinity, cost.CountXY);

            // enqueue sources
            foreach (int i in sources)
            {
                result[i] = 0.0;
                queue.Insert(0.0, i);
            }

            // exclude
            if (exclude != null)
            {
                foreach (int i in exclude)
                {
                    result[i] = 0.0;
                }
            }

            // breadth first search from sources
            while (queue.Count > 0)
            {
                (var d0, int i0) = queue.RemoveMin();
                if (result[i0] < d0)
                {
                    continue;                  // skip if lower value has been assigned
                }
                (int x0, int y0) = cost.ToGridSpace(i0);

                // -x
                if (x0 > 0)
                {
                    TryUpdate(d0 + dx * costVals[i0 - 1], i0 - 1);
                }

                // +x
                if (x0 < nx - 1)
                {
                    TryUpdate(d0 + dx * costVals[i0 + 1], i0 + 1);
                }

                // -y
                if (y0 > 0)
                {
                    TryUpdate(d0 + dy * costVals[i0 - nx], i0 - nx);
                }

                // +y
                if (y0 < ny - 1)
                {
                    TryUpdate(d0 + dy * costVals[i0 + nx], i0 + nx);
                }

                // add to queue if less than current min
                void TryUpdate(double distance, int index)
                {
                    if (distance < result[index])
                    {
                        result[index] = distance;
                        queue.Insert(distance, index);
                    }
                }
            }
        }