/// <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); } } }
/* * /// <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; } } }