Adding initial files

This commit is contained in:
nathan@daedalus
2012-03-19 18:57:59 -05:00
commit 5bdc5db408
162 changed files with 43840 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
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
}
}

View File

@@ -0,0 +1,99 @@
using System;
namespace FarseerPhysics.Common.ConvexHull
{
public static class GiftWrap
{
// From Eric Jordan's convex decomposition library (box2D rev 32)
/// <summary>
/// Find the convex hull of a point cloud using "Gift-wrap" algorithm - start
/// with an extremal point, and walk around the outside edge by testing
/// angles.
///
/// Runs in O(N*S) time where S is number of sides of resulting polygon.
/// Worst case: point cloud is all vertices of convex polygon: O(N^2).
/// There may be faster algorithms to do this, should you need one -
/// this is just the simplest. You can get O(N log N) expected time if you
/// try, I think, and O(N) if you restrict inputs to simple polygons.
/// Returns null if number of vertices passed is less than 3.
/// Results should be passed through convex decomposition afterwards
/// to ensure that each shape has few enough points to be used in Box2d.
///
/// Warning: May be buggy with colinear points on hull.
/// </summary>
/// <param name="vertices">The vertices.</param>
/// <returns></returns>
public static Vertices GetConvexHull(Vertices vertices)
{
if (vertices.Count < 3)
return vertices;
int[] edgeList = new int[vertices.Count];
int numEdges = 0;
float minY = float.MaxValue;
int minYIndex = vertices.Count;
for (int i = 0; i < vertices.Count; ++i)
{
if (vertices[i].Y < minY)
{
minY = vertices[i].Y;
minYIndex = i;
}
}
int startIndex = minYIndex;
int winIndex = -1;
float dx = -1.0f;
float dy = 0.0f;
while (winIndex != minYIndex)
{
float maxDot = -2.0f;
float nrm;
for (int i = 0; i < vertices.Count; ++i)
{
if (i == startIndex)
continue;
float newdx = vertices[i].X - vertices[startIndex].X;
float newdy = vertices[i].Y - vertices[startIndex].Y;
nrm = (float)Math.Sqrt(newdx * newdx + newdy * newdy);
nrm = (nrm == 0.0f) ? 1.0f : nrm;
newdx /= nrm;
newdy /= nrm;
//Dot products act as proxy for angle
//without requiring inverse trig.
float newDot = newdx * dx + newdy * dy;
if (newDot > maxDot)
{
maxDot = newDot;
winIndex = i;
}
}
edgeList[numEdges++] = winIndex;
dx = vertices[winIndex].X - vertices[startIndex].X;
dy = vertices[winIndex].Y - vertices[startIndex].Y;
nrm = (float)Math.Sqrt(dx * dx + dy * dy);
nrm = (nrm == 0.0f) ? 1.0f : nrm;
dx /= nrm;
dy /= nrm;
startIndex = winIndex;
}
Vertices returnVal = new Vertices(numEdges);
for (int i = 0; i < numEdges; i++)
{
returnVal.Add(vertices[edgeList[i]]);
//Debug.WriteLine(string.Format("{0}, {1}", vertices[edgeList[i]].X, vertices[edgeList[i]].Y));
}
//Not sure if we need this
//returnVal.MergeParallelEdges(Settings.b2_angularSlop);
return returnVal;
}
}
}

View File

@@ -0,0 +1,122 @@
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Common.ConvexHull
{
public static class Melkman
{
//Melkman based convex hull algorithm contributed by Cowdozer
/// <summary>
/// Creates a convex hull.
/// Note:
/// 1. Vertices must be of a simple polygon, i.e. edges do not overlap.
/// 2. Melkman does not work on point clouds
/// </summary>
/// <remarks>
/// Implemented using Melkman's Convex Hull Algorithm - O(n) time complexity.
/// Reference: http://www.ams.sunysb.edu/~jsbm/courses/345/melkman.pdf
/// </remarks>
/// <returns>A convex hull in counterclockwise winding order.</returns>
public static Vertices GetConvexHull(Vertices vertices)
{
//With less than 3 vertices, this is about the best we can do for a convex hull
if (vertices.Count < 3)
return vertices;
//We'll never need a queue larger than the current number of Vertices +1
//Create double-ended queue
Vector2[] deque = new Vector2[vertices.Count + 1];
int qf = 3, qb = 0; //Queue front index, queue back index
int qfm1, qbm1; //qfm1 = second element, qbm1 = second last element
//Start by placing first 3 vertices in convex CCW order
int startIndex = 3;
float k = MathUtils.Area(vertices[0], vertices[1], vertices[2]);
if (k == 0)
{
//Vertices are collinear.
deque[0] = vertices[0];
deque[1] = vertices[2]; //We can skip vertex 1 because it should be between 0 and 2
deque[2] = vertices[0];
qf = 2;
//Go until the end of the collinear sequence of vertices
for (startIndex = 3; startIndex < vertices.Count; startIndex++)
{
Vector2 tmp = vertices[startIndex];
if (MathUtils.Area(ref deque[0], ref deque[1], ref tmp) == 0) //This point is also collinear
deque[1] = vertices[startIndex];
else break;
}
}
else
{
deque[0] = deque[3] = vertices[2];
if (k > 0)
{
//Is Left. Set deque = {2, 0, 1, 2}
deque[1] = vertices[0];
deque[2] = vertices[1];
}
else
{
//Is Right. Set deque = {2, 1, 0, 2}
deque[1] = vertices[1];
deque[2] = vertices[0];
}
}
qfm1 = qf == 0 ? deque.Length - 1 : qf - 1; //qfm1 = qf - 1;
qbm1 = qb == deque.Length - 1 ? 0 : qb + 1; //qbm1 = qb + 1;
//Add vertices one at a time and adjust convex hull as needed
for (int i = startIndex; i < vertices.Count; i++)
{
Vector2 nextPt = vertices[i];
//Ignore if it is already within the convex hull we have constructed
if (MathUtils.Area(ref deque[qfm1], ref deque[qf], ref nextPt) > 0 &&
MathUtils.Area(ref deque[qb], ref deque[qbm1], ref nextPt) > 0)
continue;
//Pop front until convex
while (!(MathUtils.Area(ref deque[qfm1], ref deque[qf], ref nextPt) > 0))
{
//Pop the front element from the queue
qf = qfm1; //qf--;
qfm1 = qf == 0 ? deque.Length - 1 : qf - 1; //qfm1 = qf - 1;
}
//Add vertex to the front of the queue
qf = qf == deque.Length - 1 ? 0 : qf + 1; //qf++;
qfm1 = qf == 0 ? deque.Length - 1 : qf - 1; //qfm1 = qf - 1;
deque[qf] = nextPt;
//Pop back until convex
while (!(MathUtils.Area(ref deque[qb], ref deque[qbm1], ref nextPt) > 0))
{
//Pop the back element from the queue
qb = qbm1; //qb++;
qbm1 = qb == deque.Length - 1 ? 0 : qb + 1; //qbm1 = qb + 1;
}
//Add vertex to the back of the queue
qb = qb == 0 ? deque.Length - 1 : qb - 1; //qb--;
qbm1 = qb == deque.Length - 1 ? 0 : qb + 1; //qbm1 = qb + 1;
deque[qb] = nextPt;
}
//Create the convex hull from what is left in the deque
Vertices convexHull = new Vertices(vertices.Count + 1);
if (qb < qf)
for (int i = qb; i < qf; i++)
convexHull.Add(deque[i]);
else
{
for (int i = 0; i < qf; i++)
convexHull.Add(deque[i]);
for (int i = qb; i < deque.Length; i++)
convexHull.Add(deque[i]);
}
return convexHull;
}
}
}