/// <summary>
        ///
        /// </summary>
        /// <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.Count), range => Body(range.Item1, range.Item2));
            }
            else
            {
                Body(0, field.Count);
            }

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

                (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.IndicesAt(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;
                }
            }
        }
        /// <summary>
        ///
        /// </summary>
        public static void GetCurl(this GridField2d <Vec2d> 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.Count), range => Body(range.Item1, range.Item2));
            }
            else
            {
                Body(0, field.Count);
            }

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

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

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

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

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

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

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

                (var dx, var dy) = (0.5 / field.Scale);
                (int di, int dj) = field.GetBoundaryOffsets();
                (int i, int j)   = field.IndicesAt(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];

                    result[index] = new Vec2d((tx1 - tx0) * dx, (ty1 - ty0) * dy);
                }
            }
        }
Beispiel #4
0
        /*
         * /// <summary>
         * /// Adds the Laplacian of the field to the deltas array.
         * /// http://en.wikipedia.org/wiki/Discrete_Laplace_operator
         * /// </summary>
         * /// <param name="field"></param>
         * /// <param name="deltas"></param>
         * /// <param name="rate"></param>
         * /// <param name="parallel"></param>
         * public static void Diffuse(HeVertexScalarField field, double[] deltas, double rate, bool parallel = false)
         * {
         *  var vals = field.Values;
         *  var verts = field.Vertices;
         *
         *  Action<Tuple<int, int>> func = range =>
         *  {
         *      for (int i = range.Item1; i < range.Item2; i++)
         *      {
         *          double sum = 0.0;
         *          int n = 0;
         *
         *          foreach (var he in verts[i].IncomingHalfedges)
         *          {
         *              sum += vals[he.Start.Index];
         *              n++;
         *          }
         *
         *          deltas[i] += (sum / n - vals[i]) * rate;
         *      }
         *  };
         *
         *  if (parallel)
         *      Parallel.ForEach(Partitioner.Create(0, field.Count), func);
         *  else
         *      func(Tuple.Create(0, field.Count));
         * }
         *
         *
         * /// <summary>
         * /// Adds the Laplacian of the field to the deltas array.
         * /// The Laplacian is calculated with a user-defined weighting scheme.
         * /// http://www.cs.princeton.edu/courses/archive/fall10/cos526/papers/sorkine05.pdf
         * /// http://www.igl.ethz.ch/projects/Laplacian-mesh-processing/Laplacian-mesh-optimization/lmo.pdf
         * /// </summary>
         * /// <param name="field"></param>
         * /// <param name="deltas"></param>
         * /// <param name="rate"></param>
         * /// <param name="hedgeWeights"></param>
         * /// <param name="parallel"></param>
         * public static void Diffuse(HeVertexScalarField field, double[] deltas, double rate, IReadOnlyList<double> hedgeWeights, bool parallel = false)
         * {
         *  var vals = field.Values;
         *  var verts = field.Vertices;
         *
         *  Action<Tuple<int, int>> func = range =>
         *  {
         *      for (int i = range.Item1; i < range.Item2; i++)
         *      {
         *          double value = vals[i];
         *          double sum = 0.0;
         *
         *          foreach (var he in verts[i].OutgoingHalfedges)
         *              sum += (vals[he.End.Index] - value) * hedgeWeights[he.Index];
         *
         *          deltas[i] += sum * rate;
         *      }
         *  };
         *
         *  if (parallel)
         *      Parallel.ForEach(Partitioner.Create(0, field.Count), func);
         *  else
         *      func(Tuple.Create(0, field.Count));
         * }
         */


        /// <summary>
        /// http://micsymposium.org/mics_2011_proceedings/mics2011_submission_30.pdf
        /// </summary>
        /// <param name="field"></param>
        /// <param name="deltas"></param>
        /// <param name="slope"></param>
        /// <param name="rate"></param>
        /// <param name="parallel"></param>
        public static void ErodeThermal(GridField2d <double> field, double[] deltas, double slope, double rate, bool parallel = false)
        {
            if (parallel)
            {
                Parallel.ForEach(Partitioner.Create(0, field.Count), range => Body(range.Item1, range.Item2));
            }
            else
            {
                Body(0, field.Count);
            }

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

                (double dx, double dy) = field.Scale;
                dx = 1.0 / Math.Abs(dx);
                dy = 1.0 / Math.Abs(dy);

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

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

                    double value = vals[index];
                    double sum = 0.0;
                    double m, md;

                    //-x
                    m  = ((i == 0) ? vals[index + di] : vals[index - 1]) - value;
                    m *= dx;
                    md = Math.Abs(m) - slope;
                    if (md > 0.0)
                    {
                        sum += Math.Sign(m) * md;
                    }

                    //+x
                    m  = ((i == nx - 1) ? vals[index - di] : vals[index + 1]) - value;
                    m *= dx;
                    md = Math.Abs(m) - slope;
                    if (md > 0.0)
                    {
                        sum += Math.Sign(m) * md;
                    }

                    //-y
                    m  = ((j == 0) ? vals[index + dj] : vals[index - nx]) - value;
                    m *= dy;
                    md = Math.Abs(m) - slope;
                    if (md > 0.0)
                    {
                        sum += Math.Sign(m) * md;
                    }

                    //+y
                    m  = ((j == ny - 1) ? vals[index - dj] : vals[index + nx]) - value;
                    m *= dy;
                    md = Math.Abs(m) - slope;
                    if (md > 0.0)
                    {
                        sum += Math.Sign(m) * md;
                    }

                    deltas[index] += sum * rate;
                }
            }
        }