/// <summary> /// /// </summary> /// <param name="parallel"></param> /// <returns></returns> public static GridField2d <Vec2d> GetGradient(this GridField2d <double> field, bool parallel = false) { var result = GridField2d.Vec2d.Create(field); GetGradient(field, result, parallel); return(result); }
/// <summary> /// /// </summary> /// <param name="parallel"></param> /// <returns></returns> public static GridField2d <Vec2d> GetLaplacian(this GridField2d <Vec2d> field, bool parallel = false) { var result = GridField2d.Vec2d.Create(field); GetLaplacian(field, result, parallel); return(result); }
/// <summary> /// /// </summary> /// <typeparam name="U"></typeparam> /// <param name="other"></param> /// <param name="converter"></param> /// <param name="parallel"></param> /// <returns></returns> public GridField2d <T> CreateCopy(GridField2d <T> other) { var result = Create(other); result.Set(other); return(result); }
/// <summary> /// /// </summary> /// <param name="parallel"></param> /// <returns></returns> public static GridField2d <double> GetCurl(this GridField2d <Vec2d> field, bool parallel = false) { var result = GridField2d.Double.Create(field); GetCurl(field, result, parallel); return(result); }
/// <summary> /// /// </summary> /// <typeparam name="U"></typeparam> /// <param name="other"></param> /// <param name="converter"></param> /// <param name="parallel"></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); }
/// <summary> /// /// </summary> /// <param name="field"></param> /// <param name="path"></param> /// <param name="mapper"></param> public static void SaveAsImage(GridField2d <T> field, string path, Func <T, Color> mapper) { using (Bitmap bmp = new Bitmap(field.CountX, field.CountY, PixelFormat.Format32bppArgb)) { FieldIO.WriteToImage(field, bmp, mapper); bmp.Save(path); } }
/// <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); }
/// <summary> /// Sets this field to the values of another. /// </summary> /// <param name="other"></param> /// <param name="parallel"></param> public void Sample(GridField2d <T> other, bool parallel = false) { if (ResolutionEquals(other)) { _values.Set(other._values); return; } this.Sample((IField2d <T>)other, parallel); }
/// <summary> /// Sets this field to the values of another. /// </summary> /// <typeparam name="U"></typeparam> /// <param name="other"></param> /// <param name="converter"></param> /// <param name="parallel"></param> public void Sample <U>(GridField2d <U> other, Func <U, T> converter, bool parallel = false) where U : struct { if (ResolutionEquals(other)) { other._values.Convert(converter, _values); return; } this.Sample((IField2d <U>)other, converter, parallel); }
/// <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(GridField2d <double> field, double[] deltas, double rate, bool parallel = false) { var vals = field.Values; int nx = field.CountX; int ny = field.CountY; (double dx, double dy) = field.Scale.Components; dx = 1.0 / (dx * dx); dy = 1.0 / (dy * dy); (int di, int dj) = field.GetBoundaryOffsets(); Action <Tuple <int, int> > body = range => { (int i, int j) = field.IndicesAt(range.Item1); for (int index = range.Item1; index < range.Item2; 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; deltas[index] += ((tx0 + tx1 - t) * dx + (ty0 + ty1 - t) * dy) * rate; } }; if (parallel) { Parallel.ForEach(Partitioner.Create(0, field.Count), body); } else { body(Tuple.Create(0, field.Count)); } }
/// <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> /// Calculates L1 (Manhattan) geodesic distance via Dijksta's algorithm as detailed in /// http://www.numerical-tours.com/matlab/fastmarching_0_implementing/ /// </summary> /// <param name="cost"></param> /// <param name="sources"></param> /// <param name="field"></param> public static void GeodesicDistanceL1(GridField2d <double> field, IEnumerable <int> sources, IEnumerable <int> exclude = null) { // TODO handle additonal wrap modes var dists = field.Values; int nx = field.CountX; int ny = field.CountY; (double dx, double dy) = Vec2d.Abs(field.Scale); var queue = new Queue <int>(); dists.Set(double.PositiveInfinity); // enqueue sources foreach (int i in sources) { dists[i] = 0.0; queue.Enqueue(i); } // exclude if (exclude != null) { foreach (int i in exclude) { dists[i] = 0.0; } } // breadth first search from sources while (queue.Count > 0) { int i0 = queue.Dequeue(); var d0 = dists[i0]; (int x0, int y0) = field.IndicesAt(i0); // -x if (x0 > 0) { TryUpdate(d0 + dx, i0 - 1); } // +x if (x0 < nx - 1) { TryUpdate(d0 + dx, i0 + 1); } // -y if (y0 > 0) { TryUpdate(d0 + dy, i0 - nx); } // +y if (y0 < ny - 1) { TryUpdate(d0 + dy, i0 + nx); } // add to queue if less than current min void TryUpdate(double distance, int index) { if (distance < dists[index]) { dists[index] = distance; queue.Enqueue(index); } } } }
/// <summary> /// /// </summary> /// <param name="field"></param> /// <param name="cost"></param> /// <param name="sources"></param> /// <param name="exclude"></param> public static void GeodesicDistanceL2(GridField2d <double> field, double[] cost, IEnumerable <int> sources, IEnumerable <int> exclude = null) { // TODO handle additonal wrap modes var dists = field.Values; var nx = field.CountX; var ny = field.CountY; (var dx, var dy) = Vec2d.Abs(field.Scale); var eikonal = new Eikonal2d(dx, dy); var queue = new PriorityQueue <double, int>(); dists.Set(double.PositiveInfinity); // enqueue sources foreach (int i in sources) { dists[i] = 0.0; queue.Insert(0.0, i); } // exclude if (exclude != null) { foreach (var i in exclude) { dists[i] = 0.0; } } // breadth first search from sources while (queue.Count > 0) { (double d0, int i0) = queue.RemoveMin(); if (dists[i0] < d0) { continue; // skip if lower value has been assigned } (int x0, int y0) = field.IndicesAt(i0); if (x0 > 0) { X(i0 - 1); } if (x0 < nx - 1) { X(i0 + 1); } if (y0 > 0) { Y(i0 - nx); } if (y0 < ny - 1) { Y(i0 + nx); } // process x neighbor void X(int index) { var d1 = dists[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.Evaluate(d0, minY, cost[index], out d2)) { d2 = d0 + dx * cost[index]; } // add to queue if less than current min if (d2 < d1) { dists[index] = d2; queue.Insert(d2, index); } } // process y neighbor void Y(int index) { var d1 = dists[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.Evaluate(minX, d0, cost[index], out d2)) { d2 = d0 + dy * cost[index]; } // add to queue if less than current min if (d2 < d1) { dists[index] = d2; queue.Insert(d2, index); } } // returns the minimum adjacent value in the x double GetMinX(int index) { if (x0 == 0) { return(dists[index + 1]); } else if (x0 == nx - 1) { return(dists[index - 1]); } return(Math.Min(dists[index - 1], dists[index + 1])); } // returns the minimum adjacent value in the y double GetMinY(int index) { if (y0 == 0) { return(dists[index + nx]); } else if (y0 == ny - 1) { return(dists[index - nx]); } return(Math.Min(dists[index - nx], dists[index + nx])); } } }
/// <summary> /// Calculates L1 (Manhattan) geodesic distance via Dijksta's algorithm as detailed in /// http://www.numerical-tours.com/matlab/fastmarching_0_implementing/ /// </summary> /// <param name="cost"></param> /// <param name="sources"></param> /// <param name="result"></param> public static void GeodesicDistanceL1(GridField2d <double> field, double[] cost, IEnumerable <int> sources, IEnumerable <int> exclude = null) { // TODO handle additonal wrap modes var dists = field.Values; int nx = field.CountX; int ny = field.CountY; (double dx, double dy) = Vec2d.Abs(field.Scale); var queue = new PriorityQueue <double, int>(); dists.Set(double.PositiveInfinity); // enqueue sources foreach (int i in sources) { dists[i] = 0.0; queue.Insert(0.0, i); } // exclude if (exclude != null) { foreach (int i in exclude) { dists[i] = 0.0; } } // breadth first search from sources while (queue.Count > 0) { (var d0, int i0) = queue.RemoveMin(); if (dists[i0] < d0) { continue; // skip if lower value has been assigned } (int x0, int y0) = field.IndicesAt(i0); // -x if (x0 > 0) { TryUpdate(d0 + dx * cost[i0 - 1], i0 - 1); } // +x if (x0 < nx - 1) { TryUpdate(d0 + dx * cost[i0 + 1], i0 + 1); } // -y if (y0 > 0) { TryUpdate(d0 + dy * cost[i0 - nx], i0 - nx); } // +y if (y0 < ny - 1) { TryUpdate(d0 + dy * cost[i0 + nx], i0 + nx); } // add to queue if less than current min void TryUpdate(double distance, int index) { if (distance < dists[index]) { dists[index] = distance; queue.Insert(distance, index); } } } }
/// <summary> /// /// </summary> /// <param name="cost"></param> /// <param name="sources"></param> /// <param name="tags"></param> /// <param name="result"></param> private static void GeodesicDistanceL2Impl(GridField2d <double> cost, IEnumerable <int> sources, bool[] tags, double[] result) { // TODO handle wrap modes var costVals = cost.Values; var nx = cost.CountX; var ny = cost.CountY; (var dx, var dy) = Vec2d.Abs(cost.Scale).Components; var pq = new PriorityQueue <(double, int)>((a, b) => a.Item1.CompareTo(b.Item1)); var eikonal = new Eikonal2d(dx, dy); result.SetRange(double.PositiveInfinity, 0, cost.Count); // enqueue sources foreach (int index in sources) { result[index] = 0.0; pq.Insert((0.0, index)); } // breadth first search from sources while (pq.Count > 0) { (double dist0, int index0) = pq.RemoveMin(); if (tags[index0]) { continue; // skip if already accepted } tags[index0] = true; (int i0, int j0) = cost.IndicesAt(index0); // x neigbours for (int i = -1; i < 2; i += 2) { if (!SlurMath.Contains(i0 + i, nx)) { continue; // skip if out of bounds } int index1 = index0 + i; if (!tags[index1]) { double minAdj = (j0 == 0) ? result[index1 + nx] : (j0 == ny - 1) ? result[index1 - nx] : Math.Min(result[index1 - nx], result[index1 + nx]); double dist1 = (minAdj > double.MaxValue) ? dist0 + dx * costVals[index1] : eikonal.Evaluate(dist0, minAdj, costVals[index1]); if (dist1 < result[index1]) { result[index1] = dist1; pq.Insert((dist1, index1)); } } } // y neigbours for (int j = -1; j < 2; j += 2) { if (!SlurMath.Contains(j0 + j, ny)) { continue; // skip if out of bounds } int index1 = index0 + j * nx; if (!tags[index1]) { double minAdj = (i0 == 0) ? result[index1 + 1] : (i0 == nx - 1) ? result[index1 - 1] : Math.Min(result[index1 - 1], result[index1 + 1]); double dist1 = (minAdj > double.MaxValue) ? dist0 + dy * costVals[index1] : eikonal.Evaluate(minAdj, dist0, costVals[index1]); if (dist1 < result[index1]) { result[index1] = dist1; pq.Insert((dist1, index1)); } } } } }
/// <summary> /// Calculates L2 (Euclidean) geodesic distance via the Fast marching algorithm as detailed in /// http://www.numerical-tours.com/matlab/fastmarching_0_implementing/ /// </summary> /// <param name="cost"></param> /// <param name="sources"></param> /// <param name="tags"></param> /// <param name="result"></param> public static void GeodesicDistanceL2(GridField2d <double> cost, IEnumerable <int> sources, bool[] tags, double[] result) { tags.Clear(); GeodesicDistanceL2Impl(cost, sources, tags, result); }
/// <summary> /// Calculates L2 (Euclidean) geodesic distance via the Fast marching algorithm as detailed in /// http://www.numerical-tours.com/matlab/fastmarching_0_implementing/ /// </summary> /// <param name="cost"></param> /// <param name="sources"></param> /// <param name="result"></param> /// <returns></returns> public static void GeodesicDistanceL2(GridField2d <double> cost, IEnumerable <int> sources, double[] result) { var tags = new bool[cost.Count]; GeodesicDistanceL2Impl(cost, sources, tags, result); }
/// <summary> /// Calculates L2 (Euclidean) geodesic distance via the Fast marching algorithm as detailed in /// http://www.numerical-tours.com/matlab/fastmarching_0_implementing/ /// </summary> /// <param name="cost"></param> /// <param name="sources"></param> /// <param name="result"></param> public static void GeodesicDistanceL2(GridField2d <double> cost, IEnumerable <int> sources, GridField2d <double> result) { var states = new bool[cost.Count]; GeodesicDistanceL2Impl(cost, sources, states, result.Values); }
/// <summary> /// Calculates L1 (Manhattan) geodesic distance via Dijksta's algorithm as detailed in /// http://www.numerical-tours.com/matlab/fastmarching_0_implementing/ /// </summary> /// <param name="cost"></param> /// <param name="sources"></param> /// <param name="result"></param> public static void GeodesicDistanceL1(GridField2d <double> cost, IEnumerable <int> sources, double[] result) { // TODO handle wrap modes var costVals = cost.Values; int nx = cost.CountX; int ny = cost.CountY; (double dx, double dy) = Vec2d.Abs(cost.Scale).Components; var pq = new PriorityQueue <(double, int)>((a, b) => a.Item1.CompareTo(b.Item1)); result.SetRange(double.PositiveInfinity, 0, cost.Count); // enqueue sources foreach (int index in sources) { result[index] = 0.0; pq.Insert((0.0, index)); } // breadth first search from sources while (pq.Count > 0) { (double dist0, int index0) = pq.RemoveMin(); if (dist0 > result[index0]) { continue; // skip if node has already been processed } (int i0, int j0) = cost.IndicesAt(index0); // x neighbours for (int i = -1; i < 2; i += 2) { if (!SlurMath.Contains(i0 + i, nx)) { continue; } int index1 = index0 + i; double dist1 = dist0 + costVals[index1] * dx; if (dist1 < result[index1]) { result[index1] = dist1; pq.Insert((dist1, index1)); } } // y neigbours for (int j = -1; j < 2; j += 2) { if (!SlurMath.Contains(j0 + j, ny)) { continue; } int index1 = index0 + j * nx; double dist1 = dist0 + costVals[index1] * dy; if (dist1 < result[index1]) { result[index1] = dist1; pq.Insert((dist1, index1)); } } } }
/// <summary> /// Calculates L1 (Manhattan) geodesic distance via Dijksta's algorithm as detailed in /// http://www.numerical-tours.com/matlab/fastmarching_0_implementing/ /// </summary> /// <param name="cost"></param> /// <param name="sources"></param> /// <param name="result"></param> public static void GeodesicDistanceL1(GridField2d <double> cost, IEnumerable <int> sources, GridField2d <double> result) { GeodesicDistanceL1(cost, sources, result.Values); }
/// <summary> /// /// </summary> /// <param name="point"></param> /// <param name="value"></param> public static void SetAt(this GridField2d <Vec2d> field, GridPoint2d point, Vec2d value) { FieldUtil.SetAt(field, point.Corners, point.Weights, value); }
/// <summary> /// /// </summary> /// <param name="point"></param> /// <param name="amount"></param> public static void IncrementAt(this GridField2d <Vec2d> field, GridPoint2d point, Vec2d amount) { FieldUtil.IncrementAt(field, point.Corners, point.Weights, amount); }
/// <summary> /// /// </summary> /// <typeparam name="T"></typeparam> /// <param name="field"></param> /// <param name="mapper"></param> /// <param name="bitmap"></param> public static void ReadFromImage <T>(Bitmap bitmap, GridField2d <T> field, Func <Color, T> mapper) where T : struct { ReadFromImage(bitmap, field.Values, 0, mapper); }
/// <summary> /// Adds the Laplacian of the field to the delta field. /// http://en.wikipedia.org/wiki/Discrete_Laplace_operator /// </summary> /// <param name="field"></param> /// <param name="delta"></param> /// <param name="rate"></param> /// <param name="parallel"></param> public static void Diffuse(GridField2d <double> field, GridField2d <double> delta, double rate, bool parallel = false) { Diffuse(field, delta.Values, rate, parallel); }
/// <summary> /// Writes the given field to an existing image. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="field"></param> /// <param name="mapper"></param> /// <param name="bitmap"></param> public static void WriteToImage <T>(GridField2d <T> field, Bitmap bitmap, Func <T, Color> mapper) where T : struct { WriteToImage(field.Values, 0, bitmap, mapper); }
/* * /// <summary> * /// Adds the Laplacian of the field to the delta field. * /// http://en.wikipedia.org/wiki/Discrete_Laplace_operator * /// </summary> * /// <param name="field"></param> * /// <param name="delta"></param> * /// <param name="rate"></param> * /// <param name="parallel"></param> * public static void Diffuse(HeVertexScalarField field, HeVertexScalarField delta, double rate, bool parallel = false) * { * Diffuse(field, delta.Values, rate, parallel); * } * * * /// <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 delta field. * /// http://en.wikipedia.org/wiki/Discrete_Laplace_operator * /// </summary> * /// <param name="field"></param> * /// <param name="delta"></param> * /// <param name="rate"></param> * /// <param name="hedgeWeights"></param> * /// <param name="parallel"></param> * public static void Diffuse(HeVertexScalarField field, HeVertexScalarField delta, double rate, IReadOnlyList<double> hedgeWeights, bool parallel = false) * { * Diffuse(field, delta.Values, rate, hedgeWeights, parallel); * } * * * /// <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="delta"></param> /// <param name="slope"></param> /// <param name="rate"></param> /// <param name="parallel"></param> public static void ErodeThermal(GridField2d <double> field, GridField2d <double> delta, double slope, double rate, bool parallel = false) { ErodeThermal(field, delta.Values, slope, rate, parallel); }
/// <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) { var vals = field.Values; int nx = field.CountX; int ny = field.CountY; (double dx, double dy) = field.Scale.Components; dx = 1.0 / Math.Abs(dx); dy = 1.0 / Math.Abs(dy); (int di, int dj) = field.GetBoundaryOffsets(); Action <Tuple <int, int> > body = range => { (int i, int j) = field.IndicesAt(range.Item1); for (int index = range.Item1; index < range.Item2; 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; } }; if (parallel) { Parallel.ForEach(Partitioner.Create(0, field.Count), body); } else { body(Tuple.Create(0, field.Count)); } }
/// <summary> /// Calculates L1 (Manhattan) geodesic distance via Dijksta's algorithm as detailed in /// http://www.numerical-tours.com/matlab/fastmarching_0_implementing/ /// </summary> /// <param name="cost"></param> /// <param name="sources"></param> /// <param name="result"></param> public static void GeodesicDistanceL1(GridField2d <double> cost, IEnumerable <int> sources, double[] result) { // TODO // handle additonal wrap modes // add simplified bfs based version with obstacle threshold var costVals = cost.Values; int nx = cost.CountX; int ny = cost.CountY; (double dx, double dy) = Vec2d.Abs(cost.Scale); var pq = new PriorityQueue <double, int>(); result.SetRange(double.PositiveInfinity, 0, cost.Count); // enqueue sources foreach (int index in sources) { result[index] = 0.0; pq.Insert(0.0, index); } // breadth first search from sources while (pq.Count > 0) { (double dist0, int index0) = pq.RemoveMin(); if (dist0 > result[index0]) { continue; // skip if node has already been processed (TODO check if necessary) } (int i0, int j0) = cost.IndicesAt(index0); // x neighbours for (int i = -1; i < 2; i += 2) { if (!SlurMath.Contains(i0 + i, nx)) { continue; } int index1 = index0 + i; double dist1 = dist0 + costVals[index1] * dx; if (dist1 < result[index1]) { result[index1] = dist1; pq.Insert(dist1, index1); } } // y neigbours for (int j = -1; j < 2; j += 2) { if (!SlurMath.Contains(j0 + j, ny)) { continue; } int index1 = index0 + j * nx; double dist1 = dist0 + costVals[index1] * dy; if (dist1 < result[index1]) { result[index1] = dist1; pq.Insert(dist1, index1); } } } }