123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- using System.Collections.Generic;
- using Microsoft.Xna.Framework;
- namespace FarseerPhysics.Common.ConvexHull
- {
- public static class ChainHull
- {
- //Andrew's monotone chain 2D convex hull algorithm.
- //Copyright 2001, softSurfer (www.softsurfer.com)
- /// <summary>
- /// Gets the convex hull.
- /// </summary>
- /// <remarks>
- /// http://www.softsurfer.com/Archive/algorithm_0109/algorithm_0109.htm
- /// </remarks>
- /// <returns></returns>
- public static Vertices GetConvexHull(Vertices P)
- {
- P.Sort(new PointComparer());
- Vector2[] H = new Vector2[P.Count];
- Vertices res = new Vertices();
- int n = P.Count;
- int bot, top = -1; // indices for bottom and top of the stack
- int i; // array scan index
- // Get the indices of points with min x-coord and min|max y-coord
- int minmin = 0, minmax;
- float xmin = P[0].X;
- for (i = 1; i < n; i++)
- if (P[i].X != xmin) break;
- minmax = i - 1;
- if (minmax == n - 1)
- {
- // degenerate case: all x-coords == xmin
- H[++top] = P[minmin];
- if (P[minmax].Y != P[minmin].Y) // a nontrivial segment
- H[++top] = P[minmax];
- H[++top] = P[minmin]; // add polygon endpoint
- for (int j = 0; j < top + 1; j++)
- {
- res.Add(H[j]);
- }
- return res;
- }
- top = res.Count - 1;
- // Get the indices of points with max x-coord and min|max y-coord
- int maxmin, maxmax = n - 1;
- float xmax = P[n - 1].X;
- for (i = n - 2; i >= 0; i--)
- if (P[i].X != xmax) break;
- maxmin = i + 1;
- // Compute the lower hull on the stack H
- H[++top] = P[minmin]; // push minmin point onto stack
- i = minmax;
- while (++i <= maxmin)
- {
- // the lower line joins P[minmin] with P[maxmin]
- if (MathUtils.Area(P[minmin], P[maxmin], P[i]) >= 0 && i < maxmin)
- continue; // ignore P[i] above or on the lower line
- while (top > 0) // there are at least 2 points on the stack
- {
- // test if P[i] is left of the line at the stack top
- if (MathUtils.Area(H[top - 1], H[top], P[i]) > 0)
- break; // P[i] is a new hull vertex
- else
- top--; // pop top point off stack
- }
- H[++top] = P[i]; // push P[i] onto stack
- }
- // Next, compute the upper hull on the stack H above the bottom hull
- if (maxmax != maxmin) // if distinct xmax points
- H[++top] = P[maxmax]; // push maxmax point onto stack
- bot = top; // the bottom point of the upper hull stack
- i = maxmin;
- while (--i >= minmax)
- {
- // the upper line joins P[maxmax] with P[minmax]
- if (MathUtils.Area(P[maxmax], P[minmax], P[i]) >= 0 && i > minmax)
- continue; // ignore P[i] below or on the upper line
- while (top > bot) // at least 2 points on the upper stack
- {
- // test if P[i] is left of the line at the stack top
- if (MathUtils.Area(H[top - 1], H[top], P[i]) > 0)
- break; // P[i] is a new hull vertex
- else
- top--; // pop top point off stack
- }
- H[++top] = P[i]; // push P[i] onto stack
- }
- if (minmax != minmin)
- H[++top] = P[minmin]; // push joining endpoint onto stack
- for (int j = 0; j < top + 1; j++)
- {
- res.Add(H[j]);
- }
- return res;
- }
- #region Nested type: PointComparer
- public class PointComparer : Comparer<Vector2>
- {
- public override int Compare(Vector2 a, Vector2 b)
- {
- int f = a.X.CompareTo(b.X);
- return f != 0 ? f : a.Y.CompareTo(b.Y);
- }
- }
- #endregion
- }
- }
|