Adding initial files
This commit is contained in:
126
axios/Common/ConvexHull/ChainHull.cs
Normal file
126
axios/Common/ConvexHull/ChainHull.cs
Normal 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
|
||||
}
|
||||
}
|
99
axios/Common/ConvexHull/GiftWrap.cs
Normal file
99
axios/Common/ConvexHull/GiftWrap.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
122
axios/Common/ConvexHull/Melkman.cs
Normal file
122
axios/Common/ConvexHull/Melkman.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user