Server job assigning logic, submarine movement syncing, submarine collision improvements, spawnpoints in levels
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition
|
||||
{
|
||||
//From phed rev 36: http://code.google.com/p/phed/source/browse/trunk/Polygon.cpp
|
||||
|
||||
/// <summary>
|
||||
/// Convex decomposition algorithm created by Mark Bayazit (http://mnbayazit.com/)
|
||||
///
|
||||
/// Properties:
|
||||
/// - Tries to decompose using polygons instead of triangles.
|
||||
/// - Tends to produce optimal results with low processing time.
|
||||
/// - Running time is O(nr), n = number of vertices, r = reflex vertices.
|
||||
/// - Does not support holes.
|
||||
///
|
||||
/// For more information about this algorithm, see http://mnbayazit.com/406/bayazit
|
||||
/// </summary>
|
||||
internal static class BayazitDecomposer
|
||||
{
|
||||
/// <summary>
|
||||
/// Decompose the polygon into several smaller non-concave polygon.
|
||||
/// If the polygon is already convex, it will return the original polygon, unless it is over Settings.MaxPolygonVertices.
|
||||
/// </summary>
|
||||
public static List<Vertices> ConvexPartition(Vertices vertices)
|
||||
{
|
||||
Debug.Assert(vertices.Count > 3);
|
||||
Debug.Assert(vertices.IsCounterClockWise());
|
||||
|
||||
return TriangulatePolygon(vertices);
|
||||
}
|
||||
|
||||
private static List<Vertices> TriangulatePolygon(Vertices vertices)
|
||||
{
|
||||
List<Vertices> list = new List<Vertices>();
|
||||
Vector2 lowerInt = new Vector2();
|
||||
Vector2 upperInt = new Vector2(); // intersection points
|
||||
int lowerIndex = 0, upperIndex = 0;
|
||||
Vertices lowerPoly, upperPoly;
|
||||
|
||||
for (int i = 0; i < vertices.Count; ++i)
|
||||
{
|
||||
if (Reflex(i, vertices))
|
||||
{
|
||||
float upperDist;
|
||||
float lowerDist = upperDist = float.MaxValue;
|
||||
for (int j = 0; j < vertices.Count; ++j)
|
||||
{
|
||||
// if line intersects with an edge
|
||||
float d;
|
||||
Vector2 p;
|
||||
if (Left(At(i - 1, vertices), At(i, vertices), At(j, vertices)) && RightOn(At(i - 1, vertices), At(i, vertices), At(j - 1, vertices)))
|
||||
{
|
||||
// find the point of intersection
|
||||
p = LineTools.LineIntersect(At(i - 1, vertices), At(i, vertices), At(j, vertices), At(j - 1, vertices));
|
||||
|
||||
if (Right(At(i + 1, vertices), At(i, vertices), p))
|
||||
{
|
||||
// make sure it's inside the poly
|
||||
d = SquareDist(At(i, vertices), p);
|
||||
if (d < lowerDist)
|
||||
{
|
||||
// keep only the closest intersection
|
||||
lowerDist = d;
|
||||
lowerInt = p;
|
||||
lowerIndex = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Left(At(i + 1, vertices), At(i, vertices), At(j + 1, vertices)) && RightOn(At(i + 1, vertices), At(i, vertices), At(j, vertices)))
|
||||
{
|
||||
p = LineTools.LineIntersect(At(i + 1, vertices), At(i, vertices), At(j, vertices), At(j + 1, vertices));
|
||||
|
||||
if (Left(At(i - 1, vertices), At(i, vertices), p))
|
||||
{
|
||||
d = SquareDist(At(i, vertices), p);
|
||||
if (d < upperDist)
|
||||
{
|
||||
upperDist = d;
|
||||
upperIndex = j;
|
||||
upperInt = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there are no vertices to connect to, choose a point in the middle
|
||||
if (lowerIndex == (upperIndex + 1) % vertices.Count)
|
||||
{
|
||||
Vector2 p = ((lowerInt + upperInt) / 2);
|
||||
|
||||
lowerPoly = Copy(i, upperIndex, vertices);
|
||||
lowerPoly.Add(p);
|
||||
upperPoly = Copy(lowerIndex, i, vertices);
|
||||
upperPoly.Add(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
double highestScore = 0, bestIndex = lowerIndex;
|
||||
while (upperIndex < lowerIndex)
|
||||
upperIndex += vertices.Count;
|
||||
|
||||
for (int j = lowerIndex; j <= upperIndex; ++j)
|
||||
{
|
||||
if (CanSee(i, j, vertices))
|
||||
{
|
||||
double score = 1 / (SquareDist(At(i, vertices), At(j, vertices)) + 1);
|
||||
if (Reflex(j, vertices))
|
||||
{
|
||||
if (RightOn(At(j - 1, vertices), At(j, vertices), At(i, vertices)) && LeftOn(At(j + 1, vertices), At(j, vertices), At(i, vertices)))
|
||||
score += 3;
|
||||
else
|
||||
score += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
score += 1;
|
||||
}
|
||||
if (score > highestScore)
|
||||
{
|
||||
bestIndex = j;
|
||||
highestScore = score;
|
||||
}
|
||||
}
|
||||
}
|
||||
lowerPoly = Copy(i, (int)bestIndex, vertices);
|
||||
upperPoly = Copy((int)bestIndex, i, vertices);
|
||||
}
|
||||
list.AddRange(TriangulatePolygon(lowerPoly));
|
||||
list.AddRange(TriangulatePolygon(upperPoly));
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
// polygon is already convex
|
||||
if (vertices.Count > Settings.MaxPolygonVertices)
|
||||
{
|
||||
lowerPoly = Copy(0, vertices.Count / 2, vertices);
|
||||
upperPoly = Copy(vertices.Count / 2, 0, vertices);
|
||||
list.AddRange(TriangulatePolygon(lowerPoly));
|
||||
list.AddRange(TriangulatePolygon(upperPoly));
|
||||
}
|
||||
else
|
||||
list.Add(vertices);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private static Vector2 At(int i, Vertices vertices)
|
||||
{
|
||||
int s = vertices.Count;
|
||||
return vertices[i < 0 ? s - 1 - ((-i - 1) % s) : i % s];
|
||||
}
|
||||
|
||||
private static Vertices Copy(int i, int j, Vertices vertices)
|
||||
{
|
||||
while (j < i)
|
||||
j += vertices.Count;
|
||||
|
||||
Vertices p = new Vertices(j);
|
||||
|
||||
for (; i <= j; ++i)
|
||||
{
|
||||
p.Add(At(i, vertices));
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
private static bool CanSee(int i, int j, Vertices vertices)
|
||||
{
|
||||
if (Reflex(i, vertices))
|
||||
{
|
||||
if (LeftOn(At(i, vertices), At(i - 1, vertices), At(j, vertices)) && RightOn(At(i, vertices), At(i + 1, vertices), At(j, vertices)))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RightOn(At(i, vertices), At(i + 1, vertices), At(j, vertices)) || LeftOn(At(i, vertices), At(i - 1, vertices), At(j, vertices)))
|
||||
return false;
|
||||
}
|
||||
if (Reflex(j, vertices))
|
||||
{
|
||||
if (LeftOn(At(j, vertices), At(j - 1, vertices), At(i, vertices)) && RightOn(At(j, vertices), At(j + 1, vertices), At(i, vertices)))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RightOn(At(j, vertices), At(j + 1, vertices), At(i, vertices)) || LeftOn(At(j, vertices), At(j - 1, vertices), At(i, vertices)))
|
||||
return false;
|
||||
}
|
||||
for (int k = 0; k < vertices.Count; ++k)
|
||||
{
|
||||
if ((k + 1) % vertices.Count == i || k == i || (k + 1) % vertices.Count == j || k == j)
|
||||
continue; // ignore incident edges
|
||||
|
||||
Vector2 intersectionPoint;
|
||||
|
||||
if (LineTools.LineIntersect(At(i, vertices), At(j, vertices), At(k, vertices), At(k + 1, vertices), out intersectionPoint))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool Reflex(int i, Vertices vertices)
|
||||
{
|
||||
return Right(i, vertices);
|
||||
}
|
||||
|
||||
private static bool Right(int i, Vertices vertices)
|
||||
{
|
||||
return Right(At(i - 1, vertices), At(i, vertices), At(i + 1, vertices));
|
||||
}
|
||||
|
||||
private static bool Left(Vector2 a, Vector2 b, Vector2 c)
|
||||
{
|
||||
return MathUtils.Area(ref a, ref b, ref c) > 0;
|
||||
}
|
||||
|
||||
private static bool LeftOn(Vector2 a, Vector2 b, Vector2 c)
|
||||
{
|
||||
return MathUtils.Area(ref a, ref b, ref c) >= 0;
|
||||
}
|
||||
|
||||
private static bool Right(Vector2 a, Vector2 b, Vector2 c)
|
||||
{
|
||||
return MathUtils.Area(ref a, ref b, ref c) < 0;
|
||||
}
|
||||
|
||||
private static bool RightOn(Vector2 a, Vector2 b, Vector2 c)
|
||||
{
|
||||
return MathUtils.Area(ref a, ref b, ref c) <= 0;
|
||||
}
|
||||
|
||||
private static float SquareDist(Vector2 a, Vector2 b)
|
||||
{
|
||||
float dx = b.X - a.X;
|
||||
float dy = b.Y - a.Y;
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,420 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Changes from the Java version
|
||||
// attributification
|
||||
// Future possibilities
|
||||
// Flattening out the number of indirections
|
||||
// Replacing arrays of 3 with fixed-length arrays?
|
||||
// Replacing bool[3] with a bit array of some sort?
|
||||
// Bundling everything into an AoS mess?
|
||||
// Hardcode them all as ABC ?
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using FarseerPhysics.Common.Decomposition.CDT.Delaunay.Sweep;
|
||||
using FarseerPhysics.Common.Decomposition.CDT.Util;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Delaunay
|
||||
{
|
||||
internal class DelaunayTriangle
|
||||
{
|
||||
/** Neighbor pointers */
|
||||
|
||||
/** Flags to determine if an edge is a Delauney edge */
|
||||
public FixedBitArray3 EdgeIsConstrained;
|
||||
|
||||
/** Flags to determine if an edge is a Constrained edge */
|
||||
public FixedBitArray3 EdgeIsDelaunay;
|
||||
public Util.FixedArray3<DelaunayTriangle> Neighbors;
|
||||
|
||||
/** Has this triangle been marked as an interior triangle? */
|
||||
|
||||
public Util.FixedArray3<TriangulationPoint> Points;
|
||||
|
||||
public DelaunayTriangle(TriangulationPoint p1, TriangulationPoint p2, TriangulationPoint p3)
|
||||
{
|
||||
Points[0] = p1;
|
||||
Points[1] = p2;
|
||||
Points[2] = p3;
|
||||
}
|
||||
|
||||
public bool IsInterior { get; set; }
|
||||
|
||||
public int IndexOf(TriangulationPoint p)
|
||||
{
|
||||
int i = Points.IndexOf(p);
|
||||
if (i == -1) throw new Exception("Calling index with a point that doesn't exist in triangle");
|
||||
return i;
|
||||
}
|
||||
|
||||
//TODO: Port note - different implementation
|
||||
public int IndexCW(TriangulationPoint p)
|
||||
{
|
||||
int index = IndexOf(p);
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return 2;
|
||||
case 1:
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Port note - different implementation
|
||||
public int IndexCCW(TriangulationPoint p)
|
||||
{
|
||||
int index = IndexOf(p);
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return 1;
|
||||
case 1:
|
||||
return 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(TriangulationPoint p)
|
||||
{
|
||||
return (p == Points[0] || p == Points[1] || p == Points[2]);
|
||||
}
|
||||
|
||||
public bool Contains(DTSweepConstraint e)
|
||||
{
|
||||
return (Contains(e.P) && Contains(e.Q));
|
||||
}
|
||||
|
||||
public bool Contains(TriangulationPoint p, TriangulationPoint q)
|
||||
{
|
||||
return (Contains(p) && Contains(q));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update neighbor pointers
|
||||
/// </summary>
|
||||
/// <param name="p1">Point 1 of the shared edge</param>
|
||||
/// <param name="p2">Point 2 of the shared edge</param>
|
||||
/// <param name="t">This triangle's new neighbor</param>
|
||||
private void MarkNeighbor(TriangulationPoint p1, TriangulationPoint p2, DelaunayTriangle t)
|
||||
{
|
||||
if ((p1 == Points[2] && p2 == Points[1]) || (p1 == Points[1] && p2 == Points[2]))
|
||||
{
|
||||
Neighbors[0] = t;
|
||||
}
|
||||
else if ((p1 == Points[0] && p2 == Points[2]) || (p1 == Points[2] && p2 == Points[0]))
|
||||
{
|
||||
Neighbors[1] = t;
|
||||
}
|
||||
else if ((p1 == Points[0] && p2 == Points[1]) || (p1 == Points[1] && p2 == Points[0]))
|
||||
{
|
||||
Neighbors[2] = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine("Neighbor error, please report!");
|
||||
// throw new Exception("Neighbor error, please report!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exhaustive search to update neighbor pointers
|
||||
/// </summary>
|
||||
public void MarkNeighbor(DelaunayTriangle t)
|
||||
{
|
||||
if (t.Contains(Points[1], Points[2]))
|
||||
{
|
||||
Neighbors[0] = t;
|
||||
t.MarkNeighbor(Points[1], Points[2], this);
|
||||
}
|
||||
else if (t.Contains(Points[0], Points[2]))
|
||||
{
|
||||
Neighbors[1] = t;
|
||||
t.MarkNeighbor(Points[0], Points[2], this);
|
||||
}
|
||||
else if (t.Contains(Points[0], Points[1]))
|
||||
{
|
||||
Neighbors[2] = t;
|
||||
t.MarkNeighbor(Points[0], Points[1], this);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine("markNeighbor failed");
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearNeighbors()
|
||||
{
|
||||
Neighbors[0] = Neighbors[1] = Neighbors[2] = null;
|
||||
}
|
||||
|
||||
public void ClearNeighbor(DelaunayTriangle triangle)
|
||||
{
|
||||
if (Neighbors[0] == triangle)
|
||||
{
|
||||
Neighbors[0] = null;
|
||||
}
|
||||
else if (Neighbors[1] == triangle)
|
||||
{
|
||||
Neighbors[1] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Neighbors[2] = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all references to all other triangles and points
|
||||
*/
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
DelaunayTriangle t;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
t = Neighbors[i];
|
||||
if (t != null)
|
||||
{
|
||||
t.ClearNeighbor(this);
|
||||
}
|
||||
}
|
||||
ClearNeighbors();
|
||||
Points[0] = Points[1] = Points[2] = null;
|
||||
}
|
||||
|
||||
/// <param name="t">Opposite triangle</param>
|
||||
/// <param name="p">The point in t that isn't shared between the triangles</param>
|
||||
public TriangulationPoint OppositePoint(DelaunayTriangle t, TriangulationPoint p)
|
||||
{
|
||||
Debug.Assert(t != this, "self-pointer error");
|
||||
return PointCW(t.PointCW(p));
|
||||
}
|
||||
|
||||
public DelaunayTriangle NeighborCW(TriangulationPoint point)
|
||||
{
|
||||
return Neighbors[(Points.IndexOf(point) + 1)%3];
|
||||
}
|
||||
|
||||
public DelaunayTriangle NeighborCCW(TriangulationPoint point)
|
||||
{
|
||||
return Neighbors[(Points.IndexOf(point) + 2)%3];
|
||||
}
|
||||
|
||||
public DelaunayTriangle NeighborAcross(TriangulationPoint point)
|
||||
{
|
||||
return Neighbors[Points.IndexOf(point)];
|
||||
}
|
||||
|
||||
public TriangulationPoint PointCCW(TriangulationPoint point)
|
||||
{
|
||||
return Points[(IndexOf(point) + 1)%3];
|
||||
}
|
||||
|
||||
public TriangulationPoint PointCW(TriangulationPoint point)
|
||||
{
|
||||
return Points[(IndexOf(point) + 2)%3];
|
||||
}
|
||||
|
||||
private void RotateCW()
|
||||
{
|
||||
var t = Points[2];
|
||||
Points[2] = Points[1];
|
||||
Points[1] = Points[0];
|
||||
Points[0] = t;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Legalize triangle by rotating clockwise around oPoint
|
||||
/// </summary>
|
||||
/// <param name="oPoint">The origin point to rotate around</param>
|
||||
/// <param name="nPoint">???</param>
|
||||
public void Legalize(TriangulationPoint oPoint, TriangulationPoint nPoint)
|
||||
{
|
||||
RotateCW();
|
||||
Points[IndexCCW(oPoint)] = nPoint;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Points[0] + "," + Points[1] + "," + Points[2];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalize edge marking
|
||||
/// </summary>
|
||||
public void MarkNeighborEdges()
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
if (EdgeIsConstrained[i] && Neighbors[i] != null)
|
||||
{
|
||||
Neighbors[i].MarkConstrainedEdge(Points[(i + 1)%3], Points[(i + 2)%3]);
|
||||
}
|
||||
}
|
||||
|
||||
public void MarkEdge(DelaunayTriangle triangle)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
if (EdgeIsConstrained[i])
|
||||
{
|
||||
triangle.MarkConstrainedEdge(Points[(i + 1)%3], Points[(i + 2)%3]);
|
||||
}
|
||||
}
|
||||
|
||||
public void MarkEdge(List<DelaunayTriangle> tList)
|
||||
{
|
||||
foreach (DelaunayTriangle t in tList)
|
||||
for (int i = 0; i < 3; i++)
|
||||
if (t.EdgeIsConstrained[i])
|
||||
{
|
||||
MarkConstrainedEdge(t.Points[(i + 1)%3], t.Points[(i + 2)%3]);
|
||||
}
|
||||
}
|
||||
|
||||
public void MarkConstrainedEdge(int index)
|
||||
{
|
||||
EdgeIsConstrained[index] = true;
|
||||
}
|
||||
|
||||
public void MarkConstrainedEdge(DTSweepConstraint edge)
|
||||
{
|
||||
MarkConstrainedEdge(edge.P, edge.Q);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark edge as constrained
|
||||
/// </summary>
|
||||
public void MarkConstrainedEdge(TriangulationPoint p, TriangulationPoint q)
|
||||
{
|
||||
int i = EdgeIndex(p, q);
|
||||
if (i != -1) EdgeIsConstrained[i] = true;
|
||||
}
|
||||
|
||||
public double Area()
|
||||
{
|
||||
double b = Points[0].X - Points[1].X;
|
||||
double h = Points[2].Y - Points[1].Y;
|
||||
|
||||
return Math.Abs((b*h*0.5f));
|
||||
}
|
||||
|
||||
public TriangulationPoint Centroid()
|
||||
{
|
||||
double cx = (Points[0].X + Points[1].X + Points[2].X)/3f;
|
||||
double cy = (Points[0].Y + Points[1].Y + Points[2].Y)/3f;
|
||||
return new TriangulationPoint(cx, cy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the neighbor that shares this edge (or -1 if it isn't shared)
|
||||
/// </summary>
|
||||
/// <returns>index of the shared edge or -1 if edge isn't shared</returns>
|
||||
public int EdgeIndex(TriangulationPoint p1, TriangulationPoint p2)
|
||||
{
|
||||
int i1 = Points.IndexOf(p1);
|
||||
int i2 = Points.IndexOf(p2);
|
||||
|
||||
// Points of this triangle in the edge p1-p2
|
||||
bool a = (i1 == 0 || i2 == 0);
|
||||
bool b = (i1 == 1 || i2 == 1);
|
||||
bool c = (i1 == 2 || i2 == 2);
|
||||
|
||||
if (b && c) return 0;
|
||||
if (a && c) return 1;
|
||||
if (a && b) return 2;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public bool GetConstrainedEdgeCCW(TriangulationPoint p)
|
||||
{
|
||||
return EdgeIsConstrained[(IndexOf(p) + 2)%3];
|
||||
}
|
||||
|
||||
public bool GetConstrainedEdgeCW(TriangulationPoint p)
|
||||
{
|
||||
return EdgeIsConstrained[(IndexOf(p) + 1)%3];
|
||||
}
|
||||
|
||||
public bool GetConstrainedEdgeAcross(TriangulationPoint p)
|
||||
{
|
||||
return EdgeIsConstrained[IndexOf(p)];
|
||||
}
|
||||
|
||||
public void SetConstrainedEdgeCCW(TriangulationPoint p, bool ce)
|
||||
{
|
||||
EdgeIsConstrained[(IndexOf(p) + 2)%3] = ce;
|
||||
}
|
||||
|
||||
public void SetConstrainedEdgeCW(TriangulationPoint p, bool ce)
|
||||
{
|
||||
EdgeIsConstrained[(IndexOf(p) + 1)%3] = ce;
|
||||
}
|
||||
|
||||
public void SetConstrainedEdgeAcross(TriangulationPoint p, bool ce)
|
||||
{
|
||||
EdgeIsConstrained[IndexOf(p)] = ce;
|
||||
}
|
||||
|
||||
public bool GetDelaunayEdgeCCW(TriangulationPoint p)
|
||||
{
|
||||
return EdgeIsDelaunay[(IndexOf(p) + 2)%3];
|
||||
}
|
||||
|
||||
public bool GetDelaunayEdgeCW(TriangulationPoint p)
|
||||
{
|
||||
return EdgeIsDelaunay[(IndexOf(p) + 1)%3];
|
||||
}
|
||||
|
||||
public bool GetDelaunayEdgeAcross(TriangulationPoint p)
|
||||
{
|
||||
return EdgeIsDelaunay[IndexOf(p)];
|
||||
}
|
||||
|
||||
public void SetDelaunayEdgeCCW(TriangulationPoint p, bool ce)
|
||||
{
|
||||
EdgeIsDelaunay[(IndexOf(p) + 2)%3] = ce;
|
||||
}
|
||||
|
||||
public void SetDelaunayEdgeCW(TriangulationPoint p, bool ce)
|
||||
{
|
||||
EdgeIsDelaunay[(IndexOf(p) + 1)%3] = ce;
|
||||
}
|
||||
|
||||
public void SetDelaunayEdgeAcross(TriangulationPoint p, bool ce)
|
||||
{
|
||||
EdgeIsDelaunay[IndexOf(p)] = ce;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Changes from the Java version
|
||||
// Removed BST code, but not all artifacts of it
|
||||
// Future possibilities
|
||||
// Eliminate Add/RemoveNode ?
|
||||
// Comments comments and more comments!
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Delaunay.Sweep
|
||||
{
|
||||
/**
|
||||
* @author Thomas Åhlen (thahlen@gmail.com)
|
||||
*/
|
||||
|
||||
internal class AdvancingFront
|
||||
{
|
||||
public AdvancingFrontNode Head;
|
||||
protected AdvancingFrontNode Search;
|
||||
public AdvancingFrontNode Tail;
|
||||
|
||||
public AdvancingFront(AdvancingFrontNode head, AdvancingFrontNode tail)
|
||||
{
|
||||
Head = head;
|
||||
Tail = tail;
|
||||
Search = head;
|
||||
AddNode(head);
|
||||
AddNode(tail);
|
||||
}
|
||||
|
||||
public void AddNode(AdvancingFrontNode node)
|
||||
{
|
||||
//_searchTree.put(node.key, node);
|
||||
}
|
||||
|
||||
public void RemoveNode(AdvancingFrontNode node)
|
||||
{
|
||||
//_searchTree.delete( node.key );
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
AdvancingFrontNode node = Head;
|
||||
while (node != Tail)
|
||||
{
|
||||
sb.Append(node.Point.X).Append("->");
|
||||
node = node.Next;
|
||||
}
|
||||
sb.Append(Tail.Point.X);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MM: This seems to be used by LocateNode to guess a position in the implicit linked list of AdvancingFrontNodes near x
|
||||
/// Removed an overload that depended on this being exact
|
||||
/// </summary>
|
||||
private AdvancingFrontNode FindSearchNode(double x)
|
||||
{
|
||||
// TODO: implement BST index
|
||||
return Search;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We use a balancing tree to locate a node smaller or equal to given key value
|
||||
/// </summary>
|
||||
public AdvancingFrontNode LocateNode(TriangulationPoint point)
|
||||
{
|
||||
return LocateNode(point.X);
|
||||
}
|
||||
|
||||
private AdvancingFrontNode LocateNode(double x)
|
||||
{
|
||||
AdvancingFrontNode node = FindSearchNode(x);
|
||||
if (x < node.Value)
|
||||
{
|
||||
while ((node = node.Prev) != null)
|
||||
if (x >= node.Value)
|
||||
{
|
||||
Search = node;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((node = node.Next) != null)
|
||||
if (x < node.Value)
|
||||
{
|
||||
Search = node.Prev;
|
||||
return node.Prev;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This implementation will use simple node traversal algorithm to find a point on the front
|
||||
/// </summary>
|
||||
public AdvancingFrontNode LocatePoint(TriangulationPoint point)
|
||||
{
|
||||
double px = point.X;
|
||||
AdvancingFrontNode node = FindSearchNode(px);
|
||||
double nx = node.Point.X;
|
||||
|
||||
if (px == nx)
|
||||
{
|
||||
if (point != node.Point)
|
||||
{
|
||||
// We might have two nodes with same x value for a short time
|
||||
if (point == node.Prev.Point)
|
||||
{
|
||||
node = node.Prev;
|
||||
}
|
||||
else if (point == node.Next.Point)
|
||||
{
|
||||
node = node.Next;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Failed to find Node for given afront point");
|
||||
//node = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (px < nx)
|
||||
{
|
||||
while ((node = node.Prev) != null)
|
||||
{
|
||||
if (point == node.Point)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((node = node.Next) != null)
|
||||
{
|
||||
if (point == node.Point)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Search = node;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Changes from the Java version
|
||||
// Removed getters
|
||||
// Has* turned into attributes
|
||||
// Future possibilities
|
||||
// Comments!
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Delaunay.Sweep
|
||||
{
|
||||
internal class AdvancingFrontNode
|
||||
{
|
||||
public AdvancingFrontNode Next;
|
||||
public TriangulationPoint Point;
|
||||
public AdvancingFrontNode Prev;
|
||||
public DelaunayTriangle Triangle;
|
||||
public double Value;
|
||||
|
||||
public AdvancingFrontNode(TriangulationPoint point)
|
||||
{
|
||||
Point = point;
|
||||
Value = point.X;
|
||||
}
|
||||
|
||||
public bool HasNext
|
||||
{
|
||||
get { return Next != null; }
|
||||
}
|
||||
|
||||
public bool HasPrev
|
||||
{
|
||||
get { return Prev != null; }
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+66
@@ -0,0 +1,66 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Delaunay.Sweep
|
||||
{
|
||||
internal class DTSweepConstraint : TriangulationConstraint
|
||||
{
|
||||
/// <summary>
|
||||
/// Give two points in any order. Will always be ordered so
|
||||
/// that q.y > p.y and q.x > p.x if same y value
|
||||
/// </summary>
|
||||
public DTSweepConstraint(TriangulationPoint p1, TriangulationPoint p2)
|
||||
{
|
||||
P = p1;
|
||||
Q = p2;
|
||||
if (p1.Y > p2.Y)
|
||||
{
|
||||
Q = p1;
|
||||
P = p2;
|
||||
}
|
||||
else if (p1.Y == p2.Y)
|
||||
{
|
||||
if (p1.X > p2.X)
|
||||
{
|
||||
Q = p1;
|
||||
P = p2;
|
||||
}
|
||||
else if (p1.X == p2.X)
|
||||
{
|
||||
// logger.info( "Failed to create constraint {}={}", p1, p2 );
|
||||
// throw new DuplicatePointException( p1 + "=" + p2 );
|
||||
// return;
|
||||
}
|
||||
}
|
||||
Q.AddEdge(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Delaunay.Sweep
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @author Thomas Åhlén, thahlen@gmail.com
|
||||
*
|
||||
*/
|
||||
|
||||
internal class DTSweepContext : TriangulationContext
|
||||
{
|
||||
// Inital triangle factor, seed triangle will extend 30% of
|
||||
// PointSet width to both left and right.
|
||||
private const float ALPHA = 0.3f;
|
||||
|
||||
public DTSweepBasin Basin = new DTSweepBasin();
|
||||
public DTSweepEdgeEvent EdgeEvent = new DTSweepEdgeEvent();
|
||||
|
||||
private DTSweepPointComparator _comparator = new DTSweepPointComparator();
|
||||
public AdvancingFront aFront;
|
||||
|
||||
public DTSweepContext()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
public TriangulationPoint Head { get; set; }
|
||||
public TriangulationPoint Tail { get; set; }
|
||||
|
||||
public void RemoveFromList(DelaunayTriangle triangle)
|
||||
{
|
||||
Triangles.Remove(triangle);
|
||||
// TODO: remove all neighbor pointers to this triangle
|
||||
// for( int i=0; i<3; i++ )
|
||||
// {
|
||||
// if( triangle.neighbors[i] != null )
|
||||
// {
|
||||
// triangle.neighbors[i].clearNeighbor( triangle );
|
||||
// }
|
||||
// }
|
||||
// triangle.clearNeighbors();
|
||||
}
|
||||
|
||||
public void MeshClean(DelaunayTriangle triangle)
|
||||
{
|
||||
MeshCleanReq(triangle);
|
||||
}
|
||||
|
||||
private void MeshCleanReq(DelaunayTriangle triangle)
|
||||
{
|
||||
if (triangle != null && !triangle.IsInterior)
|
||||
{
|
||||
triangle.IsInterior = true;
|
||||
Triangulatable.AddTriangle(triangle);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (!triangle.EdgeIsConstrained[i])
|
||||
{
|
||||
MeshCleanReq(triangle.Neighbors[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
base.Clear();
|
||||
Triangles.Clear();
|
||||
}
|
||||
|
||||
public void AddNode(AdvancingFrontNode node)
|
||||
{
|
||||
// Console.WriteLine( "add:" + node.key + ":" + System.identityHashCode(node.key));
|
||||
// m_nodeTree.put( node.getKey(), node );
|
||||
aFront.AddNode(node);
|
||||
}
|
||||
|
||||
public void RemoveNode(AdvancingFrontNode node)
|
||||
{
|
||||
// Console.WriteLine( "remove:" + node.key + ":" + System.identityHashCode(node.key));
|
||||
// m_nodeTree.delete( node.getKey() );
|
||||
aFront.RemoveNode(node);
|
||||
}
|
||||
|
||||
public AdvancingFrontNode LocateNode(TriangulationPoint point)
|
||||
{
|
||||
return aFront.LocateNode(point);
|
||||
}
|
||||
|
||||
public void CreateAdvancingFront()
|
||||
{
|
||||
AdvancingFrontNode head, tail, middle;
|
||||
// Initial triangle
|
||||
DelaunayTriangle iTriangle = new DelaunayTriangle(Points[0], Tail, Head);
|
||||
Triangles.Add(iTriangle);
|
||||
|
||||
head = new AdvancingFrontNode(iTriangle.Points[1]);
|
||||
head.Triangle = iTriangle;
|
||||
middle = new AdvancingFrontNode(iTriangle.Points[0]);
|
||||
middle.Triangle = iTriangle;
|
||||
tail = new AdvancingFrontNode(iTriangle.Points[2]);
|
||||
|
||||
aFront = new AdvancingFront(head, tail);
|
||||
aFront.AddNode(middle);
|
||||
|
||||
// TODO: I think it would be more intuitive if head is middles next and not previous
|
||||
// so swap head and tail
|
||||
aFront.Head.Next = middle;
|
||||
middle.Next = aFront.Tail;
|
||||
middle.Prev = aFront.Head;
|
||||
aFront.Tail.Prev = middle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to map a node to all sides of this triangle that don't have
|
||||
/// a neighbor.
|
||||
/// </summary>
|
||||
public void MapTriangleToNodes(DelaunayTriangle t)
|
||||
{
|
||||
AdvancingFrontNode n;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (t.Neighbors[i] == null)
|
||||
{
|
||||
n = aFront.LocatePoint(t.PointCW(t.Points[i]));
|
||||
if (n != null)
|
||||
{
|
||||
n.Triangle = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PrepareTriangulation(Triangulatable t)
|
||||
{
|
||||
base.PrepareTriangulation(t);
|
||||
|
||||
double xmax, xmin;
|
||||
double ymax, ymin;
|
||||
|
||||
xmax = xmin = Points[0].X;
|
||||
ymax = ymin = Points[0].Y;
|
||||
|
||||
// Calculate bounds. Should be combined with the sorting
|
||||
foreach (TriangulationPoint p in Points)
|
||||
{
|
||||
if (p.X > xmax)
|
||||
xmax = p.X;
|
||||
if (p.X < xmin)
|
||||
xmin = p.X;
|
||||
if (p.Y > ymax)
|
||||
ymax = p.Y;
|
||||
if (p.Y < ymin)
|
||||
ymin = p.Y;
|
||||
}
|
||||
|
||||
double deltaX = ALPHA*(xmax - xmin);
|
||||
double deltaY = ALPHA*(ymax - ymin);
|
||||
TriangulationPoint p1 = new TriangulationPoint(xmax + deltaX, ymin - deltaY);
|
||||
TriangulationPoint p2 = new TriangulationPoint(xmin - deltaX, ymin - deltaY);
|
||||
|
||||
Head = p1;
|
||||
Tail = p2;
|
||||
|
||||
// long time = System.nanoTime();
|
||||
// Sort the points along y-axis
|
||||
Points.Sort(_comparator);
|
||||
// logger.info( "Triangulation setup [{}ms]", ( System.nanoTime() - time ) / 1e6 );
|
||||
}
|
||||
|
||||
|
||||
public void FinalizeTriangulation()
|
||||
{
|
||||
Triangulatable.AddTriangles(Triangles);
|
||||
Triangles.Clear();
|
||||
}
|
||||
|
||||
public override TriangulationConstraint NewConstraint(TriangulationPoint a, TriangulationPoint b)
|
||||
{
|
||||
return new DTSweepConstraint(a, b);
|
||||
}
|
||||
|
||||
#region Nested type: DTSweepBasin
|
||||
|
||||
public class DTSweepBasin
|
||||
{
|
||||
public AdvancingFrontNode bottomNode;
|
||||
public bool leftHighest;
|
||||
public AdvancingFrontNode leftNode;
|
||||
public AdvancingFrontNode rightNode;
|
||||
public double width;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: DTSweepEdgeEvent
|
||||
|
||||
public class DTSweepEdgeEvent
|
||||
{
|
||||
public DTSweepConstraint ConstrainedEdge;
|
||||
public bool Right;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Delaunay.Sweep
|
||||
{
|
||||
internal class DTSweepPointComparator : IComparer<TriangulationPoint>
|
||||
{
|
||||
#region IComparer<TriangulationPoint> Members
|
||||
|
||||
public int Compare(TriangulationPoint p1, TriangulationPoint p2)
|
||||
{
|
||||
if (p1.Y < p2.Y)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (p1.Y > p2.Y)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p1.X < p2.X)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (p1.X > p2.X)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Delaunay.Sweep
|
||||
{
|
||||
internal class PointOnEdgeException : NotImplementedException
|
||||
{
|
||||
public PointOnEdgeException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using FarseerPhysics.Common.Decomposition.CDT.Delaunay;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT
|
||||
{
|
||||
internal interface Triangulatable
|
||||
{
|
||||
IList<TriangulationPoint> Points { get; } // MM: Neither of these are used via interface (yet?)
|
||||
IList<DelaunayTriangle> Triangles { get; }
|
||||
TriangulationMode TriangulationMode { get; }
|
||||
void PrepareTriangulation(TriangulationContext tcx);
|
||||
|
||||
void AddTriangle(DelaunayTriangle t);
|
||||
void AddTriangles(IEnumerable<DelaunayTriangle> list);
|
||||
void ClearTriangles();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT
|
||||
{
|
||||
internal enum Orientation
|
||||
{
|
||||
CW,
|
||||
CCW,
|
||||
Collinear
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Changes from the Java version
|
||||
// Polygon constructors sprused up, checks for 3+ polys
|
||||
// Naming of everything
|
||||
// getTriangulationMode() -> TriangulationMode { get; }
|
||||
// Exceptions replaced
|
||||
// Future possibilities
|
||||
// We have a lot of Add/Clear methods -- we may prefer to just expose the container
|
||||
// Some self-explanitory methods may deserve commenting anyways
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FarseerPhysics.Common.Decomposition.CDT.Delaunay;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Polygon
|
||||
{
|
||||
internal class Polygon : Triangulatable
|
||||
{
|
||||
protected List<Polygon> _holes;
|
||||
protected PolygonPoint _last;
|
||||
protected List<TriangulationPoint> _points = new List<TriangulationPoint>();
|
||||
protected List<TriangulationPoint> _steinerPoints;
|
||||
protected List<DelaunayTriangle> _triangles;
|
||||
|
||||
/// <summary>
|
||||
/// Create a polygon from a list of at least 3 points with no duplicates.
|
||||
/// </summary>
|
||||
/// <param name="points">A list of unique points</param>
|
||||
public Polygon(IList<PolygonPoint> points)
|
||||
{
|
||||
if (points.Count < 3) throw new ArgumentException("List has fewer than 3 points", "points");
|
||||
|
||||
// Lets do one sanity check that first and last point hasn't got same position
|
||||
// Its something that often happen when importing polygon data from other formats
|
||||
if (points[0].Equals(points[points.Count - 1])) points.RemoveAt(points.Count - 1);
|
||||
|
||||
_points.AddRange(points.Cast<TriangulationPoint>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a polygon from a list of at least 3 points with no duplicates.
|
||||
/// </summary>
|
||||
/// <param name="points">A list of unique points.</param>
|
||||
public Polygon(IEnumerable<PolygonPoint> points) : this((points as IList<PolygonPoint>) ?? points.ToArray())
|
||||
{
|
||||
}
|
||||
|
||||
public Polygon()
|
||||
{
|
||||
}
|
||||
|
||||
public IList<Polygon> Holes
|
||||
{
|
||||
get { return _holes; }
|
||||
}
|
||||
|
||||
#region Triangulatable Members
|
||||
|
||||
public TriangulationMode TriangulationMode
|
||||
{
|
||||
get { return TriangulationMode.Polygon; }
|
||||
}
|
||||
|
||||
public IList<TriangulationPoint> Points
|
||||
{
|
||||
get { return _points; }
|
||||
}
|
||||
|
||||
public IList<DelaunayTriangle> Triangles
|
||||
{
|
||||
get { return _triangles; }
|
||||
}
|
||||
|
||||
public void AddTriangle(DelaunayTriangle t)
|
||||
{
|
||||
_triangles.Add(t);
|
||||
}
|
||||
|
||||
public void AddTriangles(IEnumerable<DelaunayTriangle> list)
|
||||
{
|
||||
_triangles.AddRange(list);
|
||||
}
|
||||
|
||||
public void ClearTriangles()
|
||||
{
|
||||
if (_triangles != null) _triangles.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates constraints and populates the context with points
|
||||
/// </summary>
|
||||
/// <param name="tcx">The context</param>
|
||||
public void PrepareTriangulation(TriangulationContext tcx)
|
||||
{
|
||||
if (_triangles == null)
|
||||
{
|
||||
_triangles = new List<DelaunayTriangle>(_points.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
_triangles.Clear();
|
||||
}
|
||||
|
||||
// Outer constraints
|
||||
for (int i = 0; i < _points.Count - 1; i++)
|
||||
{
|
||||
tcx.NewConstraint(_points[i], _points[i + 1]);
|
||||
}
|
||||
tcx.NewConstraint(_points[0], _points[_points.Count - 1]);
|
||||
tcx.Points.AddRange(_points);
|
||||
|
||||
// Hole constraints
|
||||
if (_holes != null)
|
||||
{
|
||||
foreach (Polygon p in _holes)
|
||||
{
|
||||
for (int i = 0; i < p._points.Count - 1; i++)
|
||||
{
|
||||
tcx.NewConstraint(p._points[i], p._points[i + 1]);
|
||||
}
|
||||
tcx.NewConstraint(p._points[0], p._points[p._points.Count - 1]);
|
||||
tcx.Points.AddRange(p._points);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steinerPoints != null)
|
||||
{
|
||||
tcx.Points.AddRange(_steinerPoints);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void AddSteinerPoint(TriangulationPoint point)
|
||||
{
|
||||
if (_steinerPoints == null)
|
||||
{
|
||||
_steinerPoints = new List<TriangulationPoint>();
|
||||
}
|
||||
_steinerPoints.Add(point);
|
||||
}
|
||||
|
||||
public void AddSteinerPoints(List<TriangulationPoint> points)
|
||||
{
|
||||
if (_steinerPoints == null)
|
||||
{
|
||||
_steinerPoints = new List<TriangulationPoint>();
|
||||
}
|
||||
_steinerPoints.AddRange(points);
|
||||
}
|
||||
|
||||
public void ClearSteinerPoints()
|
||||
{
|
||||
if (_steinerPoints != null)
|
||||
{
|
||||
_steinerPoints.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a hole to the polygon.
|
||||
/// </summary>
|
||||
/// <param name="poly">A subtraction polygon fully contained inside this polygon.</param>
|
||||
public void AddHole(Polygon poly)
|
||||
{
|
||||
if (_holes == null) _holes = new List<Polygon>();
|
||||
_holes.Add(poly);
|
||||
// XXX: tests could be made here to be sure it is fully inside
|
||||
// addSubtraction( poly.getPoints() );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts newPoint after point.
|
||||
/// </summary>
|
||||
/// <param name="point">The point to insert after in the polygon</param>
|
||||
/// <param name="newPoint">The point to insert into the polygon</param>
|
||||
public void InsertPointAfter(PolygonPoint point, PolygonPoint newPoint)
|
||||
{
|
||||
// Validate that
|
||||
int index = _points.IndexOf(point);
|
||||
if (index == -1)
|
||||
throw new ArgumentException(
|
||||
"Tried to insert a point into a Polygon after a point not belonging to the Polygon", "point");
|
||||
newPoint.Next = point.Next;
|
||||
newPoint.Previous = point;
|
||||
point.Next.Previous = newPoint;
|
||||
point.Next = newPoint;
|
||||
_points.Insert(index + 1, newPoint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts list (after last point in polygon?)
|
||||
/// </summary>
|
||||
/// <param name="list"></param>
|
||||
public void AddPoints(IEnumerable<PolygonPoint> list)
|
||||
{
|
||||
PolygonPoint first;
|
||||
foreach (PolygonPoint p in list)
|
||||
{
|
||||
p.Previous = _last;
|
||||
if (_last != null)
|
||||
{
|
||||
p.Next = _last.Next;
|
||||
_last.Next = p;
|
||||
}
|
||||
_last = p;
|
||||
_points.Add(p);
|
||||
}
|
||||
first = (PolygonPoint) _points[0];
|
||||
_last.Next = first;
|
||||
first.Previous = _last;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a point after the last in the polygon.
|
||||
/// </summary>
|
||||
/// <param name="p">The point to add</param>
|
||||
public void AddPoint(PolygonPoint p)
|
||||
{
|
||||
p.Previous = _last;
|
||||
p.Next = _last.Next;
|
||||
_last.Next = p;
|
||||
_points.Add(p);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a point from the polygon.
|
||||
/// </summary>
|
||||
/// <param name="p"></param>
|
||||
public void RemovePoint(PolygonPoint p)
|
||||
{
|
||||
PolygonPoint next, prev;
|
||||
|
||||
next = p.Next;
|
||||
prev = p.Previous;
|
||||
prev.Next = next;
|
||||
next.Previous = prev;
|
||||
_points.Remove(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Changes from the Java version
|
||||
// Replaced get/set Next/Previous with attributes
|
||||
// Future possibilities
|
||||
// Documentation!
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Polygon
|
||||
{
|
||||
internal class PolygonPoint : TriangulationPoint
|
||||
{
|
||||
public PolygonPoint(double x, double y) : base(x, y)
|
||||
{
|
||||
}
|
||||
|
||||
public PolygonPoint Next { get; set; }
|
||||
public PolygonPoint Previous { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Changes from the Java version
|
||||
// Replaced getPolygons with attribute
|
||||
// Future possibilities
|
||||
// Replace Add(Polygon) with exposed container?
|
||||
// Replace entire class with HashSet<Polygon> ?
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Polygon
|
||||
{
|
||||
internal class PolygonSet
|
||||
{
|
||||
protected List<Polygon> _polygons = new List<Polygon>();
|
||||
|
||||
public PolygonSet()
|
||||
{
|
||||
}
|
||||
|
||||
public PolygonSet(Polygon poly)
|
||||
{
|
||||
_polygons.Add(poly);
|
||||
}
|
||||
|
||||
public IEnumerable<Polygon> Polygons
|
||||
{
|
||||
get { return _polygons; }
|
||||
}
|
||||
|
||||
public void Add(Polygon p)
|
||||
{
|
||||
_polygons.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Sets
|
||||
{
|
||||
/*
|
||||
* Extends the PointSet by adding some Constraints on how it will be triangulated<br>
|
||||
* A constraint defines an edge between two points in the set, these edges can not
|
||||
* be crossed. They will be enforced triangle edges after a triangulation.
|
||||
* <p>
|
||||
*
|
||||
*
|
||||
* @author Thomas Åhlén, thahlen@gmail.com
|
||||
*/
|
||||
|
||||
internal class ConstrainedPointSet : PointSet
|
||||
{
|
||||
private List<TriangulationPoint> _constrainedPointList;
|
||||
|
||||
public ConstrainedPointSet(List<TriangulationPoint> points, int[] index)
|
||||
: base(points)
|
||||
{
|
||||
EdgeIndex = index;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param points - A list of all points in PointSet
|
||||
* @param constraints - Pairs of two points defining a constraint, all points <b>must</b> be part of given PointSet!
|
||||
*/
|
||||
|
||||
public ConstrainedPointSet(List<TriangulationPoint> points, IEnumerable<TriangulationPoint> constraints)
|
||||
: base(points)
|
||||
{
|
||||
_constrainedPointList = new List<TriangulationPoint>();
|
||||
_constrainedPointList.AddRange(constraints);
|
||||
}
|
||||
|
||||
public int[] EdgeIndex { get; private set; }
|
||||
|
||||
public override TriangulationMode TriangulationMode
|
||||
{
|
||||
get { return TriangulationMode.Constrained; }
|
||||
}
|
||||
|
||||
public override void PrepareTriangulation(TriangulationContext tcx)
|
||||
{
|
||||
base.PrepareTriangulation(tcx);
|
||||
if (_constrainedPointList != null)
|
||||
{
|
||||
TriangulationPoint p1, p2;
|
||||
List<TriangulationPoint>.Enumerator iterator = _constrainedPointList.GetEnumerator();
|
||||
while (iterator.MoveNext())
|
||||
{
|
||||
p1 = iterator.Current;
|
||||
iterator.MoveNext();
|
||||
p2 = iterator.Current;
|
||||
tcx.NewConstraint(p1, p2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < EdgeIndex.Length; i += 2)
|
||||
{
|
||||
// XXX: must change!!
|
||||
tcx.NewConstraint(Points[EdgeIndex[i]], Points[EdgeIndex[i + 1]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: TO BE IMPLEMENTED!
|
||||
* Peforms a validation on given input<br>
|
||||
* 1. Check's if there any constraint edges are crossing or collinear<br>
|
||||
* 2.
|
||||
* @return
|
||||
*/
|
||||
|
||||
public bool isValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using FarseerPhysics.Common.Decomposition.CDT.Delaunay;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Sets
|
||||
{
|
||||
internal class PointSet : Triangulatable
|
||||
{
|
||||
public PointSet(List<TriangulationPoint> points)
|
||||
{
|
||||
Points = new List<TriangulationPoint>(points);
|
||||
}
|
||||
|
||||
#region Triangulatable Members
|
||||
|
||||
public IList<TriangulationPoint> Points { get; private set; }
|
||||
public IList<DelaunayTriangle> Triangles { get; private set; }
|
||||
|
||||
public virtual TriangulationMode TriangulationMode
|
||||
{
|
||||
get { return TriangulationMode.Unconstrained; }
|
||||
}
|
||||
|
||||
public void AddTriangle(DelaunayTriangle t)
|
||||
{
|
||||
Triangles.Add(t);
|
||||
}
|
||||
|
||||
public void AddTriangles(IEnumerable<DelaunayTriangle> list)
|
||||
{
|
||||
foreach (DelaunayTriangle tri in list) Triangles.Add(tri);
|
||||
}
|
||||
|
||||
public void ClearTriangles()
|
||||
{
|
||||
Triangles.Clear();
|
||||
}
|
||||
|
||||
public virtual void PrepareTriangulation(TriangulationContext tcx)
|
||||
{
|
||||
if (Triangles == null)
|
||||
{
|
||||
Triangles = new List<DelaunayTriangle>(Points.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
Triangles.Clear();
|
||||
}
|
||||
tcx.Points.AddRange(Points);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Forces a triangle edge between two points p and q
|
||||
* when triangulating. For example used to enforce
|
||||
* Polygon Edges during a polygon triangulation.
|
||||
*
|
||||
* @author Thomas Åhlén, thahlen@gmail.com
|
||||
*/
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT
|
||||
{
|
||||
internal class TriangulationConstraint
|
||||
{
|
||||
public TriangulationPoint P;
|
||||
public TriangulationPoint Q;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using FarseerPhysics.Common.Decomposition.CDT.Delaunay;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT
|
||||
{
|
||||
internal abstract class TriangulationContext
|
||||
{
|
||||
public readonly List<TriangulationPoint> Points = new List<TriangulationPoint>(200);
|
||||
public readonly List<DelaunayTriangle> Triangles = new List<DelaunayTriangle>();
|
||||
private int _stepTime = -1;
|
||||
|
||||
public TriangulationContext()
|
||||
{
|
||||
Terminated = false;
|
||||
}
|
||||
|
||||
public TriangulationMode TriangulationMode { get; protected set; }
|
||||
public Triangulatable Triangulatable { get; private set; }
|
||||
|
||||
public bool WaitUntilNotified { get; private set; }
|
||||
public bool Terminated { get; set; }
|
||||
|
||||
public int StepCount { get; private set; }
|
||||
public virtual bool IsDebugEnabled { get; protected set; }
|
||||
|
||||
public void Done()
|
||||
{
|
||||
StepCount++;
|
||||
}
|
||||
|
||||
public virtual void PrepareTriangulation(Triangulatable t)
|
||||
{
|
||||
Triangulatable = t;
|
||||
TriangulationMode = t.TriangulationMode;
|
||||
t.PrepareTriangulation(this);
|
||||
}
|
||||
|
||||
public abstract TriangulationConstraint NewConstraint(TriangulationPoint a, TriangulationPoint b);
|
||||
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
public void Update(string message)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Clear()
|
||||
{
|
||||
Points.Clear();
|
||||
Terminated = false;
|
||||
StepCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT
|
||||
{
|
||||
internal enum TriangulationMode
|
||||
{
|
||||
Unconstrained,
|
||||
Constrained,
|
||||
Polygon
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using FarseerPhysics.Common.Decomposition.CDT.Delaunay.Sweep;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT
|
||||
{
|
||||
internal class TriangulationPoint
|
||||
{
|
||||
// List of edges this point constitutes an upper ending point (CDT)
|
||||
|
||||
public double X, Y;
|
||||
|
||||
public TriangulationPoint(double x, double y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
public List<DTSweepConstraint> Edges { get; private set; }
|
||||
|
||||
public float Xf
|
||||
{
|
||||
get { return (float) X; }
|
||||
set { X = value; }
|
||||
}
|
||||
|
||||
public float Yf
|
||||
{
|
||||
get { return (float) Y; }
|
||||
set { Y = value; }
|
||||
}
|
||||
|
||||
public bool HasEdges
|
||||
{
|
||||
get { return Edges != null; }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "[" + X + "," + Y + "]";
|
||||
}
|
||||
|
||||
public void AddEdge(DTSweepConstraint e)
|
||||
{
|
||||
if (Edges == null)
|
||||
{
|
||||
Edges = new List<DTSweepConstraint>();
|
||||
}
|
||||
Edges.Add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT
|
||||
{
|
||||
/**
|
||||
* @author Thomas Åhlén, thahlen@gmail.com
|
||||
*/
|
||||
|
||||
internal class TriangulationUtil
|
||||
{
|
||||
public static double EPSILON = 1e-12;
|
||||
|
||||
/// <summary>
|
||||
/// Requirements:
|
||||
/// 1. a,b and c form a triangle.
|
||||
/// 2. a and d is know to be on opposite side of bc
|
||||
/// <code>
|
||||
/// a
|
||||
/// +
|
||||
/// / \
|
||||
/// / \
|
||||
/// b/ \c
|
||||
/// +-------+
|
||||
/// / B \
|
||||
/// / \
|
||||
/// </code>
|
||||
/// Facts:
|
||||
/// d has to be in area B to have a chance to be inside the circle formed by a,b and c
|
||||
/// d is outside B if orient2d(a,b,d) or orient2d(c,a,d) is CW
|
||||
/// This preknowledge gives us a way to optimize the incircle test
|
||||
/// </summary>
|
||||
/// <param name="pa">triangle point, opposite d</param>
|
||||
/// <param name="pb">triangle point</param>
|
||||
/// <param name="pc">triangle point</param>
|
||||
/// <param name="pd">point opposite a</param>
|
||||
/// <returns>true if d is inside circle, false if on circle edge</returns>
|
||||
public static bool SmartIncircle(TriangulationPoint pa, TriangulationPoint pb, TriangulationPoint pc,
|
||||
TriangulationPoint pd)
|
||||
{
|
||||
double pdx = pd.X;
|
||||
double pdy = pd.Y;
|
||||
double adx = pa.X - pdx;
|
||||
double ady = pa.Y - pdy;
|
||||
double bdx = pb.X - pdx;
|
||||
double bdy = pb.Y - pdy;
|
||||
|
||||
double adxbdy = adx * bdy;
|
||||
double bdxady = bdx * ady;
|
||||
double oabd = adxbdy - bdxady;
|
||||
// oabd = orient2d(pa,pb,pd);
|
||||
if (oabd <= 0) return false;
|
||||
|
||||
double cdx = pc.X - pdx;
|
||||
double cdy = pc.Y - pdy;
|
||||
|
||||
double cdxady = cdx * ady;
|
||||
double adxcdy = adx * cdy;
|
||||
double ocad = cdxady - adxcdy;
|
||||
// ocad = orient2d(pc,pa,pd);
|
||||
if (ocad <= 0) return false;
|
||||
|
||||
double bdxcdy = bdx * cdy;
|
||||
double cdxbdy = cdx * bdy;
|
||||
|
||||
double alift = adx * adx + ady * ady;
|
||||
double blift = bdx * bdx + bdy * bdy;
|
||||
double clift = cdx * cdx + cdy * cdy;
|
||||
|
||||
double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd;
|
||||
|
||||
return det > 0;
|
||||
}
|
||||
/*
|
||||
public static bool InScanArea(TriangulationPoint pa, TriangulationPoint pb, TriangulationPoint pc,
|
||||
TriangulationPoint pd)
|
||||
{
|
||||
double pdx = pd.X;
|
||||
double pdy = pd.Y;
|
||||
double adx = pa.X - pdx;
|
||||
double ady = pa.Y - pdy;
|
||||
double bdx = pb.X - pdx;
|
||||
double bdy = pb.Y - pdy;
|
||||
|
||||
double adxbdy = adx*bdy;
|
||||
double bdxady = bdx*ady;
|
||||
double oabd = adxbdy - bdxady;
|
||||
// oabd = orient2d(pa,pb,pd);
|
||||
if (oabd <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
double cdx = pc.X - pdx;
|
||||
double cdy = pc.Y - pdy;
|
||||
|
||||
double cdxady = cdx*ady;
|
||||
double adxcdy = adx*cdy;
|
||||
double ocad = cdxady - adxcdy;
|
||||
// ocad = orient2d(pc,pa,pd);
|
||||
if (ocad <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
public static bool InScanArea(TriangulationPoint pa, TriangulationPoint pb, TriangulationPoint pc, TriangulationPoint pd)
|
||||
{
|
||||
double oadb = (pa.X - pb.X) * (pd.Y - pb.Y) - (pd.X - pb.X) * (pa.Y - pb.Y);
|
||||
if (oadb >= -EPSILON)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
double oadc = (pa.X - pc.X) * (pd.Y - pc.Y) - (pd.X - pc.X) * (pa.Y - pc.Y);
|
||||
if (oadc <= EPSILON)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Forumla to calculate signed area
|
||||
/// Positive if CCW
|
||||
/// Negative if CW
|
||||
/// 0 if collinear
|
||||
/// A[P1,P2,P3] = (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1)
|
||||
/// = (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
|
||||
public static Orientation Orient2d(TriangulationPoint pa, TriangulationPoint pb, TriangulationPoint pc)
|
||||
{
|
||||
double detleft = (pa.X - pc.X) * (pb.Y - pc.Y);
|
||||
double detright = (pa.Y - pc.Y) * (pb.X - pc.X);
|
||||
double val = detleft - detright;
|
||||
if (val > -EPSILON && val < EPSILON)
|
||||
{
|
||||
return Orientation.Collinear;
|
||||
}
|
||||
else if (val > 0)
|
||||
{
|
||||
return Orientation.CCW;
|
||||
}
|
||||
return Orientation.CW;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Util
|
||||
{
|
||||
internal struct FixedArray3<T> : IEnumerable<T> where T : class
|
||||
{
|
||||
public T _0, _1, _2;
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return _0;
|
||||
case 1:
|
||||
return _1;
|
||||
case 2:
|
||||
return _2;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
_0 = value;
|
||||
break;
|
||||
case 1:
|
||||
_1 = value;
|
||||
break;
|
||||
case 2:
|
||||
_2 = value;
|
||||
break;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region IEnumerable<T> Members
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return Enumerate().GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public bool Contains(T value)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) if (this[i] == value) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public int IndexOf(T value)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) if (this[i] == value) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_0 = _1 = _2 = null;
|
||||
}
|
||||
|
||||
public void Clear(T value)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) if (this[i] == value) this[i] = null;
|
||||
}
|
||||
|
||||
private IEnumerable<T> Enumerate()
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) yield return this[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Util
|
||||
{
|
||||
internal struct FixedBitArray3 : IEnumerable<bool>
|
||||
{
|
||||
public bool _0, _1, _2;
|
||||
|
||||
public bool this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return _0;
|
||||
case 1:
|
||||
return _1;
|
||||
case 2:
|
||||
return _2;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
_0 = value;
|
||||
break;
|
||||
case 1:
|
||||
_1 = value;
|
||||
break;
|
||||
case 2:
|
||||
_2 = value;
|
||||
break;
|
||||
default:
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region IEnumerable<bool> Members
|
||||
|
||||
public IEnumerator<bool> GetEnumerator()
|
||||
{
|
||||
return Enumerate().GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public bool Contains(bool value)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) if (this[i] == value) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public int IndexOf(bool value)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) if (this[i] == value) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_0 = _1 = _2 = false;
|
||||
}
|
||||
|
||||
public void Clear(bool value)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) if (this[i] == value) this[i] = false;
|
||||
}
|
||||
|
||||
private IEnumerable<bool> Enumerate()
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) yield return this[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Util
|
||||
{
|
||||
internal class PointGenerator
|
||||
{
|
||||
private static readonly Random RNG = new Random();
|
||||
|
||||
public static List<TriangulationPoint> UniformDistribution(int n, double scale)
|
||||
{
|
||||
List<TriangulationPoint> points = new List<TriangulationPoint>();
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
points.Add(new TriangulationPoint(scale*(0.5 - RNG.NextDouble()), scale*(0.5 - RNG.NextDouble())));
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
public static List<TriangulationPoint> UniformGrid(int n, double scale)
|
||||
{
|
||||
double x = 0;
|
||||
double size = scale/n;
|
||||
double halfScale = 0.5*scale;
|
||||
|
||||
List<TriangulationPoint> points = new List<TriangulationPoint>();
|
||||
for (int i = 0; i < n + 1; i++)
|
||||
{
|
||||
x = halfScale - i*size;
|
||||
for (int j = 0; j < n + 1; j++)
|
||||
{
|
||||
points.Add(new TriangulationPoint(x, halfScale - j*size));
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using FarseerPhysics.Common.Decomposition.CDT.Polygon;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.CDT.Util
|
||||
{
|
||||
internal class PolygonGenerator
|
||||
{
|
||||
private static readonly Random RNG = new Random();
|
||||
|
||||
private static double PI_2 = 2.0*Math.PI;
|
||||
|
||||
public static Polygon.Polygon RandomCircleSweep(double scale, int vertexCount)
|
||||
{
|
||||
PolygonPoint point;
|
||||
PolygonPoint[] points;
|
||||
double radius = scale/4;
|
||||
|
||||
points = new PolygonPoint[vertexCount];
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (i%250 == 0)
|
||||
{
|
||||
radius += scale/2*(0.5 - RNG.NextDouble());
|
||||
}
|
||||
else if (i%50 == 0)
|
||||
{
|
||||
radius += scale/5*(0.5 - RNG.NextDouble());
|
||||
}
|
||||
else
|
||||
{
|
||||
radius += 25*scale/vertexCount*(0.5 - RNG.NextDouble());
|
||||
}
|
||||
radius = radius > scale/2 ? scale/2 : radius;
|
||||
radius = radius < scale/10 ? scale/10 : radius;
|
||||
} while (radius < scale/10 || radius > scale/2);
|
||||
point = new PolygonPoint(radius*Math.Cos((PI_2*i)/vertexCount),
|
||||
radius*Math.Sin((PI_2*i)/vertexCount));
|
||||
points[i] = point;
|
||||
}
|
||||
return new Polygon.Polygon(points);
|
||||
}
|
||||
|
||||
public static Polygon.Polygon RandomCircleSweep2(double scale, int vertexCount)
|
||||
{
|
||||
PolygonPoint point;
|
||||
PolygonPoint[] points;
|
||||
double radius = scale/4;
|
||||
|
||||
points = new PolygonPoint[vertexCount];
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
do
|
||||
{
|
||||
radius += scale/5*(0.5 - RNG.NextDouble());
|
||||
radius = radius > scale/2 ? scale/2 : radius;
|
||||
radius = radius < scale/10 ? scale/10 : radius;
|
||||
} while (radius < scale/10 || radius > scale/2);
|
||||
point = new PolygonPoint(radius*Math.Cos((PI_2*i)/vertexCount),
|
||||
radius*Math.Sin((PI_2*i)/vertexCount));
|
||||
points[i] = point;
|
||||
}
|
||||
return new Polygon.Polygon(points);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Farseer Physics Engine:
|
||||
* Copyright (c) 2012 Ian Qvist
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using FarseerPhysics.Common.Decomposition.CDT;
|
||||
using FarseerPhysics.Common.Decomposition.CDT.Delaunay;
|
||||
using FarseerPhysics.Common.Decomposition.CDT.Delaunay.Sweep;
|
||||
using FarseerPhysics.Common.Decomposition.CDT.Polygon;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition
|
||||
{
|
||||
/// <summary>
|
||||
/// 2D constrained Delaunay triangulation algorithm.
|
||||
/// Based on the paper "Sweep-line algorithm for constrained Delaunay triangulation" by V. Domiter and and B. Zalik
|
||||
///
|
||||
/// Properties:
|
||||
/// - Creates triangles with a large interior angle.
|
||||
/// - Supports holes
|
||||
/// - Generate a lot of garbage due to incapsulation of the Poly2Tri library.
|
||||
/// - Running time is O(n^2), n = number of vertices.
|
||||
/// - Does not care about winding order.
|
||||
///
|
||||
/// Source: http://code.google.com/p/poly2tri/
|
||||
/// </summary>
|
||||
internal static class CDTDecomposer
|
||||
{
|
||||
/// <summary>
|
||||
/// Decompose the polygon into several smaller non-concave polygon.
|
||||
/// </summary>
|
||||
public static List<Vertices> ConvexPartition(Vertices vertices)
|
||||
{
|
||||
Debug.Assert(vertices.Count > 3);
|
||||
|
||||
Polygon poly = new Polygon();
|
||||
|
||||
foreach (Vector2 vertex in vertices)
|
||||
poly.Points.Add(new TriangulationPoint(vertex.X, vertex.Y));
|
||||
|
||||
if (vertices.Holes != null)
|
||||
{
|
||||
foreach (Vertices holeVertices in vertices.Holes)
|
||||
{
|
||||
Polygon hole = new Polygon();
|
||||
|
||||
foreach (Vector2 vertex in holeVertices)
|
||||
hole.Points.Add(new TriangulationPoint(vertex.X, vertex.Y));
|
||||
|
||||
poly.AddHole(hole);
|
||||
}
|
||||
}
|
||||
|
||||
DTSweepContext tcx = new DTSweepContext();
|
||||
tcx.PrepareTriangulation(poly);
|
||||
DTSweep.Triangulate(tcx);
|
||||
|
||||
List<Vertices> results = new List<Vertices>();
|
||||
|
||||
foreach (DelaunayTriangle triangle in poly.Triangles)
|
||||
{
|
||||
Vertices v = new Vertices();
|
||||
foreach (TriangulationPoint p in triangle.Points)
|
||||
{
|
||||
v.Add(new Vector2((float)p.X, (float)p.Y));
|
||||
}
|
||||
results.Add(v);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* C# Version Ported by Matt Bettcher and Ian Qvist 2009-2010
|
||||
*
|
||||
* Original C++ Version Copyright (c) 2007 Eric Jordan
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition
|
||||
{
|
||||
/// <summary>
|
||||
/// Convex decomposition algorithm using ear clipping
|
||||
///
|
||||
/// Properties:
|
||||
/// - Only works on simple polygons.
|
||||
/// - Does not support holes.
|
||||
/// - Running time is O(n^2), n = number of vertices.
|
||||
///
|
||||
/// Source: http://www.ewjordan.com/earClip/
|
||||
/// </summary>
|
||||
internal static class EarclipDecomposer
|
||||
{
|
||||
//box2D rev 32 - for details, see http://www.box2d.org/forum/viewtopic.php?f=4&t=83&start=50
|
||||
|
||||
/// <summary>
|
||||
/// Decompose the polygon into several smaller non-concave polygon.
|
||||
/// Each resulting polygon will have no more than Settings.MaxPolygonVertices vertices.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The vertices.</param>
|
||||
/// <param name="tolerance">The tolerance.</param>
|
||||
public static List<Vertices> ConvexPartition(Vertices vertices, float tolerance = 0.001f)
|
||||
{
|
||||
Debug.Assert(vertices.Count > 3);
|
||||
Debug.Assert(!vertices.IsCounterClockWise());
|
||||
|
||||
return TriangulatePolygon(vertices, tolerance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triangulates a polygon using simple ear-clipping algorithm. Returns
|
||||
/// size of Triangle array unless the polygon can't be triangulated.
|
||||
/// This should only happen if the polygon self-intersects,
|
||||
/// though it will not _always_ return null for a bad polygon - it is the
|
||||
/// caller's responsibility to check for self-intersection, and if it
|
||||
/// doesn't, it should at least check that the return value is non-null
|
||||
/// before using. You're warned!
|
||||
///
|
||||
/// Triangles may be degenerate, especially if you have identical points
|
||||
/// in the input to the algorithm. Check this before you use them.
|
||||
///
|
||||
/// This is totally unoptimized, so for large polygons it should not be part
|
||||
/// of the simulation loop.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only works on simple polygons.
|
||||
/// </remarks>
|
||||
private static List<Vertices> TriangulatePolygon(Vertices vertices, float tolerance)
|
||||
{
|
||||
//FPE note: Check is needed as invalid triangles can be returned in recursive calls.
|
||||
if (vertices.Count < 3)
|
||||
return new List<Vertices>();
|
||||
|
||||
List<Vertices> results = new List<Vertices>();
|
||||
|
||||
//Recurse and split on pinch points
|
||||
Vertices pA, pB;
|
||||
Vertices pin = new Vertices(vertices);
|
||||
if (ResolvePinchPoint(pin, out pA, out pB, tolerance))
|
||||
{
|
||||
List<Vertices> mergeA = TriangulatePolygon(pA, tolerance);
|
||||
List<Vertices> mergeB = TriangulatePolygon(pB, tolerance);
|
||||
|
||||
if (mergeA.Count == -1 || mergeB.Count == -1)
|
||||
throw new Exception("Can't triangulate your polygon.");
|
||||
|
||||
for (int i = 0; i < mergeA.Count; ++i)
|
||||
{
|
||||
results.Add(new Vertices(mergeA[i]));
|
||||
}
|
||||
for (int i = 0; i < mergeB.Count; ++i)
|
||||
{
|
||||
results.Add(new Vertices(mergeB[i]));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
Vertices[] buffer = new Vertices[vertices.Count - 2];
|
||||
int bufferSize = 0;
|
||||
float[] xrem = new float[vertices.Count];
|
||||
float[] yrem = new float[vertices.Count];
|
||||
for (int i = 0; i < vertices.Count; ++i)
|
||||
{
|
||||
xrem[i] = vertices[i].X;
|
||||
yrem[i] = vertices[i].Y;
|
||||
}
|
||||
|
||||
int vNum = vertices.Count;
|
||||
|
||||
while (vNum > 3)
|
||||
{
|
||||
// Find an ear
|
||||
int earIndex = -1;
|
||||
float earMaxMinCross = -10.0f;
|
||||
for (int i = 0; i < vNum; ++i)
|
||||
{
|
||||
if (IsEar(i, xrem, yrem, vNum))
|
||||
{
|
||||
int lower = Remainder(i - 1, vNum);
|
||||
int upper = Remainder(i + 1, vNum);
|
||||
Vector2 d1 = new Vector2(xrem[upper] - xrem[i], yrem[upper] - yrem[i]);
|
||||
Vector2 d2 = new Vector2(xrem[i] - xrem[lower], yrem[i] - yrem[lower]);
|
||||
Vector2 d3 = new Vector2(xrem[lower] - xrem[upper], yrem[lower] - yrem[upper]);
|
||||
|
||||
d1.Normalize();
|
||||
d2.Normalize();
|
||||
d3.Normalize();
|
||||
float cross12;
|
||||
MathUtils.Cross(ref d1, ref d2, out cross12);
|
||||
cross12 = Math.Abs(cross12);
|
||||
|
||||
float cross23;
|
||||
MathUtils.Cross(ref d2, ref d3, out cross23);
|
||||
cross23 = Math.Abs(cross23);
|
||||
|
||||
float cross31;
|
||||
MathUtils.Cross(ref d3, ref d1, out cross31);
|
||||
cross31 = Math.Abs(cross31);
|
||||
|
||||
//Find the maximum minimum angle
|
||||
float minCross = Math.Min(cross12, Math.Min(cross23, cross31));
|
||||
if (minCross > earMaxMinCross)
|
||||
{
|
||||
earIndex = i;
|
||||
earMaxMinCross = minCross;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we still haven't found an ear, we're screwed.
|
||||
// Note: sometimes this is happening because the
|
||||
// remaining points are collinear. Really these
|
||||
// should just be thrown out without halting triangulation.
|
||||
if (earIndex == -1)
|
||||
{
|
||||
for (int i = 0; i < bufferSize; i++)
|
||||
{
|
||||
results.Add(buffer[i]);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// Clip off the ear:
|
||||
// - remove the ear tip from the list
|
||||
|
||||
--vNum;
|
||||
float[] newx = new float[vNum];
|
||||
float[] newy = new float[vNum];
|
||||
int currDest = 0;
|
||||
for (int i = 0; i < vNum; ++i)
|
||||
{
|
||||
if (currDest == earIndex) ++currDest;
|
||||
newx[i] = xrem[currDest];
|
||||
newy[i] = yrem[currDest];
|
||||
++currDest;
|
||||
}
|
||||
|
||||
// - add the clipped triangle to the triangle list
|
||||
int under = (earIndex == 0) ? (vNum) : (earIndex - 1);
|
||||
int over = (earIndex == vNum) ? 0 : (earIndex + 1);
|
||||
Triangle toAdd = new Triangle(xrem[earIndex], yrem[earIndex], xrem[over], yrem[over], xrem[under],
|
||||
yrem[under]);
|
||||
buffer[bufferSize] = toAdd;
|
||||
++bufferSize;
|
||||
|
||||
// - replace the old list with the new one
|
||||
xrem = newx;
|
||||
yrem = newy;
|
||||
}
|
||||
|
||||
Triangle tooAdd = new Triangle(xrem[1], yrem[1], xrem[2], yrem[2], xrem[0], yrem[0]);
|
||||
buffer[bufferSize] = tooAdd;
|
||||
++bufferSize;
|
||||
|
||||
for (int i = 0; i < bufferSize; i++)
|
||||
{
|
||||
results.Add(new Vertices(buffer[i]));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds and fixes "pinch points," points where two polygon
|
||||
/// vertices are at the same point.
|
||||
///
|
||||
/// If a pinch point is found, pin is broken up into poutA and poutB
|
||||
/// and true is returned; otherwise, returns false.
|
||||
///
|
||||
/// Mostly for internal use.
|
||||
///
|
||||
/// O(N^2) time, which sucks...
|
||||
/// </summary>
|
||||
/// <param name="pin">The pin.</param>
|
||||
/// <param name="poutA">The pout A.</param>
|
||||
/// <param name="poutB">The pout B.</param>
|
||||
/// <param name="tolerance"></param>
|
||||
private static bool ResolvePinchPoint(Vertices pin, out Vertices poutA, out Vertices poutB, float tolerance)
|
||||
{
|
||||
poutA = new Vertices();
|
||||
poutB = new Vertices();
|
||||
|
||||
if (pin.Count < 3)
|
||||
return false;
|
||||
|
||||
bool hasPinchPoint = false;
|
||||
int pinchIndexA = -1;
|
||||
int pinchIndexB = -1;
|
||||
for (int i = 0; i < pin.Count; ++i)
|
||||
{
|
||||
for (int j = i + 1; j < pin.Count; ++j)
|
||||
{
|
||||
//Don't worry about pinch points where the points
|
||||
//are actually just dupe neighbors
|
||||
if (Math.Abs(pin[i].X - pin[j].X) < tolerance && Math.Abs(pin[i].Y - pin[j].Y) < tolerance && j != i + 1)
|
||||
{
|
||||
pinchIndexA = i;
|
||||
pinchIndexB = j;
|
||||
hasPinchPoint = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasPinchPoint) break;
|
||||
}
|
||||
if (hasPinchPoint)
|
||||
{
|
||||
int sizeA = pinchIndexB - pinchIndexA;
|
||||
if (sizeA == pin.Count) return false; //has dupe points at wraparound, not a problem here
|
||||
for (int i = 0; i < sizeA; ++i)
|
||||
{
|
||||
int ind = Remainder(pinchIndexA + i, pin.Count); // is this right
|
||||
poutA.Add(pin[ind]);
|
||||
}
|
||||
|
||||
int sizeB = pin.Count - sizeA;
|
||||
for (int i = 0; i < sizeB; ++i)
|
||||
{
|
||||
int ind = Remainder(pinchIndexB + i, pin.Count); // is this right
|
||||
poutB.Add(pin[ind]);
|
||||
}
|
||||
}
|
||||
return hasPinchPoint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fix for obnoxious behavior for the % operator for negative numbers...
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="modulus">The modulus.</param>
|
||||
/// <returns></returns>
|
||||
private static int Remainder(int x, int modulus)
|
||||
{
|
||||
int rem = x % modulus;
|
||||
while (rem < 0)
|
||||
{
|
||||
rem += modulus;
|
||||
}
|
||||
return rem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if vertex i is the tip of an ear in polygon defined by xv[] and yv[].
|
||||
/// </summary>
|
||||
/// <param name="i">The i.</param>
|
||||
/// <param name="xv">The xv.</param>
|
||||
/// <param name="yv">The yv.</param>
|
||||
/// <param name="xvLength">Length of the xv.</param>
|
||||
/// <remarks>
|
||||
/// Assumes clockwise orientation of polygon.
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified i is ear; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
private static bool IsEar(int i, float[] xv, float[] yv, int xvLength)
|
||||
{
|
||||
float dx0, dy0, dx1, dy1;
|
||||
if (i >= xvLength || i < 0 || xvLength < 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int upper = i + 1;
|
||||
int lower = i - 1;
|
||||
if (i == 0)
|
||||
{
|
||||
dx0 = xv[0] - xv[xvLength - 1];
|
||||
dy0 = yv[0] - yv[xvLength - 1];
|
||||
dx1 = xv[1] - xv[0];
|
||||
dy1 = yv[1] - yv[0];
|
||||
lower = xvLength - 1;
|
||||
}
|
||||
else if (i == xvLength - 1)
|
||||
{
|
||||
dx0 = xv[i] - xv[i - 1];
|
||||
dy0 = yv[i] - yv[i - 1];
|
||||
dx1 = xv[0] - xv[i];
|
||||
dy1 = yv[0] - yv[i];
|
||||
upper = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
dx0 = xv[i] - xv[i - 1];
|
||||
dy0 = yv[i] - yv[i - 1];
|
||||
dx1 = xv[i + 1] - xv[i];
|
||||
dy1 = yv[i + 1] - yv[i];
|
||||
}
|
||||
|
||||
float cross = dx0 * dy1 - dx1 * dy0;
|
||||
|
||||
if (cross > 0)
|
||||
return false;
|
||||
|
||||
Triangle myTri = new Triangle(xv[i], yv[i], xv[upper], yv[upper], xv[lower], yv[lower]);
|
||||
|
||||
for (int j = 0; j < xvLength; ++j)
|
||||
{
|
||||
if (j == i || j == lower || j == upper)
|
||||
continue;
|
||||
if (myTri.IsInside(xv[j], yv[j]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private class Triangle : Vertices
|
||||
{
|
||||
//Constructor automatically fixes orientation to ccw
|
||||
public Triangle(float x1, float y1, float x2, float y2, float x3, float y3)
|
||||
{
|
||||
float cross = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
|
||||
if (cross > 0)
|
||||
{
|
||||
Add(new Vector2(x1, y1));
|
||||
Add(new Vector2(x2, y2));
|
||||
Add(new Vector2(x3, y3));
|
||||
}
|
||||
else
|
||||
{
|
||||
Add(new Vector2(x1, y1));
|
||||
Add(new Vector2(x3, y3));
|
||||
Add(new Vector2(x2, y2));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsInside(float x, float y)
|
||||
{
|
||||
Vector2 a = this[0];
|
||||
Vector2 b = this[1];
|
||||
Vector2 c = this[2];
|
||||
|
||||
if (x < a.X && x < b.X && x < c.X) return false;
|
||||
if (x > a.X && x > b.X && x > c.X) return false;
|
||||
if (y < a.Y && y < b.Y && y < c.Y) return false;
|
||||
if (y > a.Y && y > b.Y && y > c.Y) return false;
|
||||
|
||||
float vx2 = x - a.X;
|
||||
float vy2 = y - a.Y;
|
||||
float vx1 = b.X - a.X;
|
||||
float vy1 = b.Y - a.Y;
|
||||
float vx0 = c.X - a.X;
|
||||
float vy0 = c.Y - a.Y;
|
||||
|
||||
float dot00 = vx0 * vx0 + vy0 * vy0;
|
||||
float dot01 = vx0 * vx1 + vy0 * vy1;
|
||||
float dot02 = vx0 * vx2 + vy0 * vy2;
|
||||
float dot11 = vx1 * vx1 + vy1 * vy1;
|
||||
float dot12 = vx1 * vx2 + vy1 * vy2;
|
||||
float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
|
||||
float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
|
||||
float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
|
||||
|
||||
return ((u > 0) && (v > 0) && (u + v < 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition
|
||||
{
|
||||
/// <summary>
|
||||
/// Convex decomposition algorithm created by unknown
|
||||
///
|
||||
/// Properties:
|
||||
/// - No support for holes
|
||||
/// - Very fast
|
||||
/// - Only works on simple polygons
|
||||
/// - Only works on counter clockwise polygons
|
||||
///
|
||||
/// More information: http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
|
||||
/// </summary>
|
||||
internal static class FlipcodeDecomposer
|
||||
{
|
||||
private static Vector2 _tmpA;
|
||||
private static Vector2 _tmpB;
|
||||
private static Vector2 _tmpC;
|
||||
|
||||
/// <summary>
|
||||
/// Decompose the polygon into triangles.
|
||||
///
|
||||
/// Properties:
|
||||
/// - Only works on counter clockwise polygons
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="vertices">The list of points describing the polygon</param>
|
||||
public static List<Vertices> ConvexPartition(Vertices vertices)
|
||||
{
|
||||
Debug.Assert(vertices.Count > 3);
|
||||
Debug.Assert(vertices.IsCounterClockWise());
|
||||
|
||||
int[] polygon = new int[vertices.Count];
|
||||
|
||||
for (int v = 0; v < vertices.Count; v++)
|
||||
polygon[v] = v;
|
||||
|
||||
int nv = vertices.Count;
|
||||
|
||||
// Remove nv-2 Vertices, creating 1 triangle every time
|
||||
int count = 2 * nv; /* error detection */
|
||||
|
||||
List<Vertices> result = new List<Vertices>();
|
||||
|
||||
for (int v = nv - 1; nv > 2; )
|
||||
{
|
||||
// If we loop, it is probably a non-simple polygon
|
||||
if (0 >= (count--))
|
||||
{
|
||||
// Triangulate: ERROR - probable bad polygon!
|
||||
return new List<Vertices>();
|
||||
}
|
||||
|
||||
// Three consecutive vertices in current polygon, <u,v,w>
|
||||
int u = v;
|
||||
if (nv <= u)
|
||||
u = 0; // Previous
|
||||
v = u + 1;
|
||||
if (nv <= v)
|
||||
v = 0; // New v
|
||||
int w = v + 1;
|
||||
if (nv <= w)
|
||||
w = 0; // Next
|
||||
|
||||
_tmpA = vertices[polygon[u]];
|
||||
_tmpB = vertices[polygon[v]];
|
||||
_tmpC = vertices[polygon[w]];
|
||||
|
||||
if (Snip(vertices, u, v, w, nv, polygon))
|
||||
{
|
||||
int s, t;
|
||||
|
||||
// Output Triangle
|
||||
Vertices triangle = new Vertices(3);
|
||||
triangle.Add(_tmpA);
|
||||
triangle.Add(_tmpB);
|
||||
triangle.Add(_tmpC);
|
||||
result.Add(triangle);
|
||||
|
||||
// Remove v from remaining polygon
|
||||
for (s = v, t = v + 1; t < nv; s++, t++)
|
||||
{
|
||||
polygon[s] = polygon[t];
|
||||
}
|
||||
nv--;
|
||||
|
||||
// Reset error detection counter
|
||||
count = 2 * nv;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the point P is inside the triangle defined by
|
||||
/// the points A, B, C
|
||||
/// </summary>
|
||||
/// <param name="a">The A point.</param>
|
||||
/// <param name="b">The B point.</param>
|
||||
/// <param name="c">The C point.</param>
|
||||
/// <param name="p">The point to be tested.</param>
|
||||
/// <returns>True if the point is inside the triangle</returns>
|
||||
private static bool InsideTriangle(ref Vector2 a, ref Vector2 b, ref Vector2 c, ref Vector2 p)
|
||||
{
|
||||
//A cross bp
|
||||
float abp = (c.X - b.X) * (p.Y - b.Y) - (c.Y - b.Y) * (p.X - b.X);
|
||||
|
||||
//A cross ap
|
||||
float aap = (b.X - a.X) * (p.Y - a.Y) - (b.Y - a.Y) * (p.X - a.X);
|
||||
|
||||
//b cross cp
|
||||
float bcp = (a.X - c.X) * (p.Y - c.Y) - (a.Y - c.Y) * (p.X - c.X);
|
||||
|
||||
return ((abp >= 0.0f) && (bcp >= 0.0f) && (aap >= 0.0f));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cut a the contour and add a triangle into V to describe the
|
||||
/// location of the cut
|
||||
/// </summary>
|
||||
/// <param name="contour">The list of points defining the polygon</param>
|
||||
/// <param name="u">The index of the first point</param>
|
||||
/// <param name="v">The index of the second point</param>
|
||||
/// <param name="w">The index of the third point</param>
|
||||
/// <param name="n">The number of elements in the array.</param>
|
||||
/// <param name="V">The array to populate with indicies of triangles.</param>
|
||||
/// <returns>True if a triangle was found</returns>
|
||||
private static bool Snip(Vertices contour, int u, int v, int w, int n, int[] V)
|
||||
{
|
||||
if (Settings.Epsilon > MathUtils.Area(ref _tmpA, ref _tmpB, ref _tmpC))
|
||||
return false;
|
||||
|
||||
for (int p = 0; p < n; p++)
|
||||
{
|
||||
if ((p == u) || (p == v) || (p == w))
|
||||
continue;
|
||||
|
||||
Vector2 point = contour[V[p]];
|
||||
|
||||
if (InsideTriangle(ref _tmpA, ref _tmpB, ref _tmpC, ref point))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.Seidel
|
||||
{
|
||||
internal class Edge
|
||||
{
|
||||
// Pointers used for building trapezoidal map
|
||||
public Trapezoid Above;
|
||||
public float B;
|
||||
public Trapezoid Below;
|
||||
|
||||
// Montone mountain points
|
||||
public HashSet<Point> MPoints;
|
||||
public Point P;
|
||||
public Point Q;
|
||||
|
||||
// Slope of the line (m)
|
||||
public float Slope;
|
||||
|
||||
|
||||
public Edge(Point p, Point q)
|
||||
{
|
||||
P = p;
|
||||
Q = q;
|
||||
|
||||
if (q.X - p.X != 0)
|
||||
Slope = (q.Y - p.Y) / (q.X - p.X);
|
||||
else
|
||||
Slope = 0;
|
||||
|
||||
B = p.Y - (p.X * Slope);
|
||||
Above = null;
|
||||
Below = null;
|
||||
MPoints = new HashSet<Point>();
|
||||
MPoints.Add(p);
|
||||
MPoints.Add(q);
|
||||
}
|
||||
|
||||
public bool IsAbove(Point point)
|
||||
{
|
||||
return P.Orient2D(Q, point) < 0;
|
||||
}
|
||||
|
||||
public bool IsBelow(Point point)
|
||||
{
|
||||
return P.Orient2D(Q, point) > 0;
|
||||
}
|
||||
|
||||
public void AddMpoint(Point point)
|
||||
{
|
||||
foreach (Point mp in MPoints)
|
||||
{
|
||||
if (!mp.Neq(point))
|
||||
return;
|
||||
}
|
||||
|
||||
MPoints.Add(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.Seidel
|
||||
{
|
||||
internal class MonotoneMountain
|
||||
{
|
||||
// Almost Pi!
|
||||
private const float PiSlop = 3.1f;
|
||||
|
||||
// Triangles that constitute the mountain
|
||||
public List<List<Point>> Triangles;
|
||||
private HashSet<Point> _convexPoints;
|
||||
private Point _head;
|
||||
|
||||
// Monotone mountain points
|
||||
private List<Point> _monoPoly;
|
||||
|
||||
// Used to track which side of the line we are on
|
||||
private bool _positive;
|
||||
private int _size;
|
||||
private Point _tail;
|
||||
|
||||
public MonotoneMountain()
|
||||
{
|
||||
_size = 0;
|
||||
_tail = null;
|
||||
_head = null;
|
||||
_positive = false;
|
||||
_convexPoints = new HashSet<Point>();
|
||||
_monoPoly = new List<Point>();
|
||||
Triangles = new List<List<Point>>();
|
||||
}
|
||||
|
||||
// Append a point to the list
|
||||
public void Add(Point point)
|
||||
{
|
||||
if (_size == 0)
|
||||
{
|
||||
_head = point;
|
||||
_size = 1;
|
||||
}
|
||||
else if (_size == 1)
|
||||
{
|
||||
// Keep repeat points out of the list
|
||||
_tail = point;
|
||||
_tail.Prev = _head;
|
||||
_head.Next = _tail;
|
||||
_size = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep repeat points out of the list
|
||||
_tail.Next = point;
|
||||
point.Prev = _tail;
|
||||
_tail = point;
|
||||
_size += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove a point from the list
|
||||
public void Remove(Point point)
|
||||
{
|
||||
Point next = point.Next;
|
||||
Point prev = point.Prev;
|
||||
point.Prev.Next = next;
|
||||
point.Next.Prev = prev;
|
||||
_size -= 1;
|
||||
}
|
||||
|
||||
// Partition a x-monotone mountain into triangles O(n)
|
||||
// See "Computational Geometry in C", 2nd edition, by Joseph O'Rourke, page 52
|
||||
public void Process()
|
||||
{
|
||||
// Establish the proper sign
|
||||
_positive = AngleSign();
|
||||
// create monotone polygon - for dubug purposes
|
||||
GenMonoPoly();
|
||||
|
||||
// Initialize internal angles at each nonbase vertex
|
||||
// Link strictly convex vertices into a list, ignore reflex vertices
|
||||
Point p = _head.Next;
|
||||
while (p.Neq(_tail))
|
||||
{
|
||||
float a = Angle(p);
|
||||
// If the point is almost colinear with it's neighbor, remove it!
|
||||
if (a >= PiSlop || a <= -PiSlop || a == 0.0f)
|
||||
Remove(p);
|
||||
else if (IsConvex(p))
|
||||
_convexPoints.Add(p);
|
||||
p = p.Next;
|
||||
}
|
||||
|
||||
Triangulate();
|
||||
}
|
||||
|
||||
private void Triangulate()
|
||||
{
|
||||
while (_convexPoints.Count != 0)
|
||||
{
|
||||
IEnumerator<Point> e = _convexPoints.GetEnumerator();
|
||||
e.MoveNext();
|
||||
Point ear = e.Current;
|
||||
|
||||
_convexPoints.Remove(ear);
|
||||
Point a = ear.Prev;
|
||||
Point b = ear;
|
||||
Point c = ear.Next;
|
||||
List<Point> triangle = new List<Point>(3);
|
||||
triangle.Add(a);
|
||||
triangle.Add(b);
|
||||
triangle.Add(c);
|
||||
|
||||
Triangles.Add(triangle);
|
||||
|
||||
// Remove ear, update angles and convex list
|
||||
Remove(ear);
|
||||
if (Valid(a))
|
||||
_convexPoints.Add(a);
|
||||
if (Valid(c))
|
||||
_convexPoints.Add(c);
|
||||
}
|
||||
|
||||
Debug.Assert(_size <= 3, "Triangulation bug, please report");
|
||||
}
|
||||
|
||||
private bool Valid(Point p)
|
||||
{
|
||||
return p.Neq(_head) && p.Neq(_tail) && IsConvex(p);
|
||||
}
|
||||
|
||||
// Create the monotone polygon
|
||||
private void GenMonoPoly()
|
||||
{
|
||||
Point p = _head;
|
||||
while (p != null)
|
||||
{
|
||||
_monoPoly.Add(p);
|
||||
p = p.Next;
|
||||
}
|
||||
}
|
||||
|
||||
private float Angle(Point p)
|
||||
{
|
||||
Point a = (p.Next - p);
|
||||
Point b = (p.Prev - p);
|
||||
return (float)Math.Atan2(a.Cross(b), a.Dot(b));
|
||||
}
|
||||
|
||||
private bool AngleSign()
|
||||
{
|
||||
Point a = (_head.Next - _head);
|
||||
Point b = (_tail - _head);
|
||||
return Math.Atan2(a.Cross(b), a.Dot(b)) >= 0;
|
||||
}
|
||||
|
||||
// Determines if the inslide angle is convex or reflex
|
||||
private bool IsConvex(Point p)
|
||||
{
|
||||
if (_positive != (Angle(p) >= 0))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.Seidel
|
||||
{
|
||||
// Node for a Directed Acyclic graph (DAG)
|
||||
internal abstract class Node
|
||||
{
|
||||
protected Node LeftChild;
|
||||
public List<Node> ParentList;
|
||||
protected Node RightChild;
|
||||
|
||||
protected Node(Node left, Node right)
|
||||
{
|
||||
ParentList = new List<Node>();
|
||||
LeftChild = left;
|
||||
RightChild = right;
|
||||
|
||||
if (left != null)
|
||||
left.ParentList.Add(this);
|
||||
if (right != null)
|
||||
right.ParentList.Add(this);
|
||||
}
|
||||
|
||||
public abstract Sink Locate(Edge s);
|
||||
|
||||
// Replace a node in the graph with this node
|
||||
// Make sure parent pointers are updated
|
||||
public void Replace(Node node)
|
||||
{
|
||||
foreach (Node parent in node.ParentList)
|
||||
{
|
||||
// Select the correct node to replace (left or right child)
|
||||
if (parent.LeftChild == node)
|
||||
parent.LeftChild = this;
|
||||
else
|
||||
parent.RightChild = this;
|
||||
}
|
||||
ParentList.AddRange(node.ParentList);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
namespace FarseerPhysics.Common.Decomposition.Seidel
|
||||
{
|
||||
internal class Point
|
||||
{
|
||||
// Pointers to next and previous points in Monontone Mountain
|
||||
public Point Next, Prev;
|
||||
public float X, Y;
|
||||
|
||||
public Point(float x, float y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Next = null;
|
||||
Prev = null;
|
||||
}
|
||||
|
||||
public static Point operator -(Point p1, Point p2)
|
||||
{
|
||||
return new Point(p1.X - p2.X, p1.Y - p2.Y);
|
||||
}
|
||||
|
||||
public static Point operator +(Point p1, Point p2)
|
||||
{
|
||||
return new Point(p1.X + p2.X, p1.Y + p2.Y);
|
||||
}
|
||||
|
||||
public static Point operator -(Point p1, float f)
|
||||
{
|
||||
return new Point(p1.X - f, p1.Y - f);
|
||||
}
|
||||
|
||||
public static Point operator +(Point p1, float f)
|
||||
{
|
||||
return new Point(p1.X + f, p1.Y + f);
|
||||
}
|
||||
|
||||
public float Cross(Point p)
|
||||
{
|
||||
return X * p.Y - Y * p.X;
|
||||
}
|
||||
|
||||
public float Dot(Point p)
|
||||
{
|
||||
return X * p.X + Y * p.Y;
|
||||
}
|
||||
|
||||
public bool Neq(Point p)
|
||||
{
|
||||
return p.X != X || p.Y != Y;
|
||||
}
|
||||
|
||||
public float Orient2D(Point pb, Point pc)
|
||||
{
|
||||
float acx = X - pc.X;
|
||||
float bcx = pb.X - pc.X;
|
||||
float acy = Y - pc.Y;
|
||||
float bcy = pb.Y - pc.Y;
|
||||
return acx * bcy - acy * bcx;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.Seidel
|
||||
{
|
||||
// Directed Acyclic graph (DAG)
|
||||
// See "Computational Geometry", 3rd edition, by Mark de Berg et al, Chapter 6.2
|
||||
internal class QueryGraph
|
||||
{
|
||||
private Node _head;
|
||||
|
||||
public QueryGraph(Node head)
|
||||
{
|
||||
_head = head;
|
||||
}
|
||||
|
||||
private Trapezoid Locate(Edge edge)
|
||||
{
|
||||
return _head.Locate(edge).Trapezoid;
|
||||
}
|
||||
|
||||
public List<Trapezoid> FollowEdge(Edge edge)
|
||||
{
|
||||
List<Trapezoid> trapezoids = new List<Trapezoid>();
|
||||
trapezoids.Add(Locate(edge));
|
||||
int j = 0;
|
||||
|
||||
while (edge.Q.X > trapezoids[j].RightPoint.X)
|
||||
{
|
||||
if (edge.IsAbove(trapezoids[j].RightPoint))
|
||||
{
|
||||
trapezoids.Add(trapezoids[j].UpperRight);
|
||||
}
|
||||
else
|
||||
{
|
||||
trapezoids.Add(trapezoids[j].LowerRight);
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
return trapezoids;
|
||||
}
|
||||
|
||||
private void Replace(Sink sink, Node node)
|
||||
{
|
||||
if (sink.ParentList.Count == 0)
|
||||
_head = node;
|
||||
else
|
||||
node.Replace(sink);
|
||||
}
|
||||
|
||||
public void Case1(Sink sink, Edge edge, Trapezoid[] tList)
|
||||
{
|
||||
YNode yNode = new YNode(edge, Sink.Isink(tList[1]), Sink.Isink(tList[2]));
|
||||
XNode qNode = new XNode(edge.Q, yNode, Sink.Isink(tList[3]));
|
||||
XNode pNode = new XNode(edge.P, Sink.Isink(tList[0]), qNode);
|
||||
Replace(sink, pNode);
|
||||
}
|
||||
|
||||
public void Case2(Sink sink, Edge edge, Trapezoid[] tList)
|
||||
{
|
||||
YNode yNode = new YNode(edge, Sink.Isink(tList[1]), Sink.Isink(tList[2]));
|
||||
XNode pNode = new XNode(edge.P, Sink.Isink(tList[0]), yNode);
|
||||
Replace(sink, pNode);
|
||||
}
|
||||
|
||||
public void Case3(Sink sink, Edge edge, Trapezoid[] tList)
|
||||
{
|
||||
YNode yNode = new YNode(edge, Sink.Isink(tList[0]), Sink.Isink(tList[1]));
|
||||
Replace(sink, yNode);
|
||||
}
|
||||
|
||||
public void Case4(Sink sink, Edge edge, Trapezoid[] tList)
|
||||
{
|
||||
YNode yNode = new YNode(edge, Sink.Isink(tList[0]), Sink.Isink(tList[1]));
|
||||
XNode qNode = new XNode(edge.Q, yNode, Sink.Isink(tList[2]));
|
||||
Replace(sink, qNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace FarseerPhysics.Common.Decomposition.Seidel
|
||||
{
|
||||
internal class Sink : Node
|
||||
{
|
||||
public Trapezoid Trapezoid;
|
||||
|
||||
private Sink(Trapezoid trapezoid)
|
||||
: base(null, null)
|
||||
{
|
||||
Trapezoid = trapezoid;
|
||||
trapezoid.Sink = this;
|
||||
}
|
||||
|
||||
public static Sink Isink(Trapezoid trapezoid)
|
||||
{
|
||||
if (trapezoid.Sink == null)
|
||||
return new Sink(trapezoid);
|
||||
|
||||
return trapezoid.Sink;
|
||||
}
|
||||
|
||||
public override Sink Locate(Edge edge)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.Seidel
|
||||
{
|
||||
internal class Trapezoid
|
||||
{
|
||||
public Edge Bottom;
|
||||
public bool Inside;
|
||||
public Point LeftPoint;
|
||||
|
||||
// Neighbor pointers
|
||||
public Trapezoid LowerLeft;
|
||||
public Trapezoid LowerRight;
|
||||
|
||||
public Point RightPoint;
|
||||
public Sink Sink;
|
||||
|
||||
public Edge Top;
|
||||
public Trapezoid UpperLeft;
|
||||
public Trapezoid UpperRight;
|
||||
|
||||
public Trapezoid(Point leftPoint, Point rightPoint, Edge top, Edge bottom)
|
||||
{
|
||||
LeftPoint = leftPoint;
|
||||
RightPoint = rightPoint;
|
||||
Top = top;
|
||||
Bottom = bottom;
|
||||
UpperLeft = null;
|
||||
UpperRight = null;
|
||||
LowerLeft = null;
|
||||
LowerRight = null;
|
||||
Inside = true;
|
||||
Sink = null;
|
||||
}
|
||||
|
||||
// Update neighbors to the left
|
||||
public void UpdateLeft(Trapezoid ul, Trapezoid ll)
|
||||
{
|
||||
UpperLeft = ul;
|
||||
if (ul != null) ul.UpperRight = this;
|
||||
LowerLeft = ll;
|
||||
if (ll != null) ll.LowerRight = this;
|
||||
}
|
||||
|
||||
// Update neighbors to the right
|
||||
public void UpdateRight(Trapezoid ur, Trapezoid lr)
|
||||
{
|
||||
UpperRight = ur;
|
||||
if (ur != null) ur.UpperLeft = this;
|
||||
LowerRight = lr;
|
||||
if (lr != null) lr.LowerLeft = this;
|
||||
}
|
||||
|
||||
// Update neighbors on both sides
|
||||
public void UpdateLeftRight(Trapezoid ul, Trapezoid ll, Trapezoid ur, Trapezoid lr)
|
||||
{
|
||||
UpperLeft = ul;
|
||||
if (ul != null) ul.UpperRight = this;
|
||||
LowerLeft = ll;
|
||||
if (ll != null) ll.LowerRight = this;
|
||||
UpperRight = ur;
|
||||
if (ur != null) ur.UpperLeft = this;
|
||||
LowerRight = lr;
|
||||
if (lr != null) lr.LowerLeft = this;
|
||||
}
|
||||
|
||||
// Recursively trim outside neighbors
|
||||
public void TrimNeighbors()
|
||||
{
|
||||
if (Inside)
|
||||
{
|
||||
Inside = false;
|
||||
if (UpperLeft != null) UpperLeft.TrimNeighbors();
|
||||
if (LowerLeft != null) LowerLeft.TrimNeighbors();
|
||||
if (UpperRight != null) UpperRight.TrimNeighbors();
|
||||
if (LowerRight != null) LowerRight.TrimNeighbors();
|
||||
}
|
||||
}
|
||||
|
||||
// Determines if this point lies inside the trapezoid
|
||||
public bool Contains(Point point)
|
||||
{
|
||||
return (point.X > LeftPoint.X && point.X < RightPoint.X && Top.IsAbove(point) && Bottom.IsBelow(point));
|
||||
}
|
||||
|
||||
public List<Point> GetVertices()
|
||||
{
|
||||
List<Point> verts = new List<Point>(4);
|
||||
verts.Add(LineIntersect(Top, LeftPoint.X));
|
||||
verts.Add(LineIntersect(Bottom, LeftPoint.X));
|
||||
verts.Add(LineIntersect(Bottom, RightPoint.X));
|
||||
verts.Add(LineIntersect(Top, RightPoint.X));
|
||||
return verts;
|
||||
}
|
||||
|
||||
private Point LineIntersect(Edge edge, float x)
|
||||
{
|
||||
float y = edge.Slope * x + edge.B;
|
||||
return new Point(x, y);
|
||||
}
|
||||
|
||||
// Add points to monotone mountain
|
||||
public void AddPoints()
|
||||
{
|
||||
if (LeftPoint != Bottom.P)
|
||||
{
|
||||
Bottom.AddMpoint(LeftPoint);
|
||||
}
|
||||
if (RightPoint != Bottom.Q)
|
||||
{
|
||||
Bottom.AddMpoint(RightPoint);
|
||||
}
|
||||
if (LeftPoint != Top.P)
|
||||
{
|
||||
Top.AddMpoint(LeftPoint);
|
||||
}
|
||||
if (RightPoint != Top.Q)
|
||||
{
|
||||
Top.AddMpoint(RightPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.Seidel
|
||||
{
|
||||
internal class TrapezoidalMap
|
||||
{
|
||||
// Trapezoid container
|
||||
public HashSet<Trapezoid> Map;
|
||||
|
||||
// Bottom segment that spans multiple trapezoids
|
||||
private Edge _bCross;
|
||||
|
||||
// Top segment that spans multiple trapezoids
|
||||
private Edge _cross;
|
||||
|
||||
// AABB margin
|
||||
private float _margin;
|
||||
|
||||
public TrapezoidalMap()
|
||||
{
|
||||
Map = new HashSet<Trapezoid>();
|
||||
_margin = 50.0f;
|
||||
_bCross = null;
|
||||
_cross = null;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_bCross = null;
|
||||
_cross = null;
|
||||
}
|
||||
|
||||
// Case 1: segment completely enclosed by trapezoid
|
||||
// break trapezoid into 4 smaller trapezoids
|
||||
public Trapezoid[] Case1(Trapezoid t, Edge e)
|
||||
{
|
||||
Trapezoid[] trapezoids = new Trapezoid[4];
|
||||
trapezoids[0] = new Trapezoid(t.LeftPoint, e.P, t.Top, t.Bottom);
|
||||
trapezoids[1] = new Trapezoid(e.P, e.Q, t.Top, e);
|
||||
trapezoids[2] = new Trapezoid(e.P, e.Q, e, t.Bottom);
|
||||
trapezoids[3] = new Trapezoid(e.Q, t.RightPoint, t.Top, t.Bottom);
|
||||
|
||||
trapezoids[0].UpdateLeft(t.UpperLeft, t.LowerLeft);
|
||||
trapezoids[1].UpdateLeftRight(trapezoids[0], null, trapezoids[3], null);
|
||||
trapezoids[2].UpdateLeftRight(null, trapezoids[0], null, trapezoids[3]);
|
||||
trapezoids[3].UpdateRight(t.UpperRight, t.LowerRight);
|
||||
|
||||
return trapezoids;
|
||||
}
|
||||
|
||||
// Case 2: Trapezoid contains point p, q lies outside
|
||||
// break trapezoid into 3 smaller trapezoids
|
||||
public Trapezoid[] Case2(Trapezoid t, Edge e)
|
||||
{
|
||||
Point rp;
|
||||
if (e.Q.X == t.RightPoint.X)
|
||||
rp = e.Q;
|
||||
else
|
||||
rp = t.RightPoint;
|
||||
|
||||
Trapezoid[] trapezoids = new Trapezoid[3];
|
||||
trapezoids[0] = new Trapezoid(t.LeftPoint, e.P, t.Top, t.Bottom);
|
||||
trapezoids[1] = new Trapezoid(e.P, rp, t.Top, e);
|
||||
trapezoids[2] = new Trapezoid(e.P, rp, e, t.Bottom);
|
||||
|
||||
trapezoids[0].UpdateLeft(t.UpperLeft, t.LowerLeft);
|
||||
trapezoids[1].UpdateLeftRight(trapezoids[0], null, t.UpperRight, null);
|
||||
trapezoids[2].UpdateLeftRight(null, trapezoids[0], null, t.LowerRight);
|
||||
|
||||
_bCross = t.Bottom;
|
||||
_cross = t.Top;
|
||||
|
||||
e.Above = trapezoids[1];
|
||||
e.Below = trapezoids[2];
|
||||
|
||||
return trapezoids;
|
||||
}
|
||||
|
||||
// Case 3: Trapezoid is bisected
|
||||
public Trapezoid[] Case3(Trapezoid t, Edge e)
|
||||
{
|
||||
Point lp;
|
||||
if (e.P.X == t.LeftPoint.X)
|
||||
lp = e.P;
|
||||
else
|
||||
lp = t.LeftPoint;
|
||||
|
||||
Point rp;
|
||||
if (e.Q.X == t.RightPoint.X)
|
||||
rp = e.Q;
|
||||
else
|
||||
rp = t.RightPoint;
|
||||
|
||||
Trapezoid[] trapezoids = new Trapezoid[2];
|
||||
|
||||
if (_cross == t.Top)
|
||||
{
|
||||
trapezoids[0] = t.UpperLeft;
|
||||
trapezoids[0].UpdateRight(t.UpperRight, null);
|
||||
trapezoids[0].RightPoint = rp;
|
||||
}
|
||||
else
|
||||
{
|
||||
trapezoids[0] = new Trapezoid(lp, rp, t.Top, e);
|
||||
trapezoids[0].UpdateLeftRight(t.UpperLeft, e.Above, t.UpperRight, null);
|
||||
}
|
||||
|
||||
if (_bCross == t.Bottom)
|
||||
{
|
||||
trapezoids[1] = t.LowerLeft;
|
||||
trapezoids[1].UpdateRight(null, t.LowerRight);
|
||||
trapezoids[1].RightPoint = rp;
|
||||
}
|
||||
else
|
||||
{
|
||||
trapezoids[1] = new Trapezoid(lp, rp, e, t.Bottom);
|
||||
trapezoids[1].UpdateLeftRight(e.Below, t.LowerLeft, null, t.LowerRight);
|
||||
}
|
||||
|
||||
_bCross = t.Bottom;
|
||||
_cross = t.Top;
|
||||
|
||||
e.Above = trapezoids[0];
|
||||
e.Below = trapezoids[1];
|
||||
|
||||
return trapezoids;
|
||||
}
|
||||
|
||||
// Case 4: Trapezoid contains point q, p lies outside
|
||||
// break trapezoid into 3 smaller trapezoids
|
||||
public Trapezoid[] Case4(Trapezoid t, Edge e)
|
||||
{
|
||||
Point lp;
|
||||
if (e.P.X == t.LeftPoint.X)
|
||||
lp = e.P;
|
||||
else
|
||||
lp = t.LeftPoint;
|
||||
|
||||
Trapezoid[] trapezoids = new Trapezoid[3];
|
||||
|
||||
if (_cross == t.Top)
|
||||
{
|
||||
trapezoids[0] = t.UpperLeft;
|
||||
trapezoids[0].RightPoint = e.Q;
|
||||
}
|
||||
else
|
||||
{
|
||||
trapezoids[0] = new Trapezoid(lp, e.Q, t.Top, e);
|
||||
trapezoids[0].UpdateLeft(t.UpperLeft, e.Above);
|
||||
}
|
||||
|
||||
if (_bCross == t.Bottom)
|
||||
{
|
||||
trapezoids[1] = t.LowerLeft;
|
||||
trapezoids[1].RightPoint = e.Q;
|
||||
}
|
||||
else
|
||||
{
|
||||
trapezoids[1] = new Trapezoid(lp, e.Q, e, t.Bottom);
|
||||
trapezoids[1].UpdateLeft(e.Below, t.LowerLeft);
|
||||
}
|
||||
|
||||
trapezoids[2] = new Trapezoid(e.Q, t.RightPoint, t.Top, t.Bottom);
|
||||
trapezoids[2].UpdateLeftRight(trapezoids[0], trapezoids[1], t.UpperRight, t.LowerRight);
|
||||
|
||||
return trapezoids;
|
||||
}
|
||||
|
||||
// Create an AABB around segments
|
||||
public Trapezoid BoundingBox(List<Edge> edges)
|
||||
{
|
||||
Point max = edges[0].P + _margin;
|
||||
Point min = edges[0].Q - _margin;
|
||||
|
||||
foreach (Edge e in edges)
|
||||
{
|
||||
if (e.P.X > max.X) max = new Point(e.P.X + _margin, max.Y);
|
||||
if (e.P.Y > max.Y) max = new Point(max.X, e.P.Y + _margin);
|
||||
if (e.Q.X > max.X) max = new Point(e.Q.X + _margin, max.Y);
|
||||
if (e.Q.Y > max.Y) max = new Point(max.X, e.Q.Y + _margin);
|
||||
if (e.P.X < min.X) min = new Point(e.P.X - _margin, min.Y);
|
||||
if (e.P.Y < min.Y) min = new Point(min.X, e.P.Y - _margin);
|
||||
if (e.Q.X < min.X) min = new Point(e.Q.X - _margin, min.Y);
|
||||
if (e.Q.Y < min.Y) min = new Point(min.X, e.Q.Y - _margin);
|
||||
}
|
||||
|
||||
Edge top = new Edge(new Point(min.X, max.Y), new Point(max.X, max.Y));
|
||||
Edge bottom = new Edge(new Point(min.X, min.Y), new Point(max.X, min.Y));
|
||||
Point left = bottom.P;
|
||||
Point right = top.Q;
|
||||
|
||||
return new Trapezoid(left, right, top, bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition.Seidel
|
||||
{
|
||||
internal class Triangulator
|
||||
{
|
||||
// Trapezoid decomposition list
|
||||
public List<Trapezoid> Trapezoids;
|
||||
public List<List<Point>> Triangles;
|
||||
|
||||
// Initialize trapezoidal map and query structure
|
||||
private Trapezoid _boundingBox;
|
||||
private List<Edge> _edgeList;
|
||||
private QueryGraph _queryGraph;
|
||||
private float _sheer = 0.001f;
|
||||
private TrapezoidalMap _trapezoidalMap;
|
||||
private List<MonotoneMountain> _xMonoPoly;
|
||||
|
||||
public Triangulator(List<Point> polyLine, float sheer)
|
||||
{
|
||||
_sheer = sheer;
|
||||
Triangles = new List<List<Point>>();
|
||||
Trapezoids = new List<Trapezoid>();
|
||||
_xMonoPoly = new List<MonotoneMountain>();
|
||||
_edgeList = InitEdges(polyLine);
|
||||
_trapezoidalMap = new TrapezoidalMap();
|
||||
_boundingBox = _trapezoidalMap.BoundingBox(_edgeList);
|
||||
_queryGraph = new QueryGraph(Sink.Isink(_boundingBox));
|
||||
|
||||
Process();
|
||||
}
|
||||
|
||||
// Build the trapezoidal map and query graph
|
||||
private void Process()
|
||||
{
|
||||
foreach (Edge edge in _edgeList)
|
||||
{
|
||||
List<Trapezoid> traps = _queryGraph.FollowEdge(edge);
|
||||
|
||||
// Remove trapezoids from trapezoidal Map
|
||||
foreach (Trapezoid t in traps)
|
||||
{
|
||||
_trapezoidalMap.Map.Remove(t);
|
||||
|
||||
bool cp = t.Contains(edge.P);
|
||||
bool cq = t.Contains(edge.Q);
|
||||
Trapezoid[] tList;
|
||||
|
||||
if (cp && cq)
|
||||
{
|
||||
tList = _trapezoidalMap.Case1(t, edge);
|
||||
_queryGraph.Case1(t.Sink, edge, tList);
|
||||
}
|
||||
else if (cp && !cq)
|
||||
{
|
||||
tList = _trapezoidalMap.Case2(t, edge);
|
||||
_queryGraph.Case2(t.Sink, edge, tList);
|
||||
}
|
||||
else if (!cp && !cq)
|
||||
{
|
||||
tList = _trapezoidalMap.Case3(t, edge);
|
||||
_queryGraph.Case3(t.Sink, edge, tList);
|
||||
}
|
||||
else
|
||||
{
|
||||
tList = _trapezoidalMap.Case4(t, edge);
|
||||
_queryGraph.Case4(t.Sink, edge, tList);
|
||||
}
|
||||
// Add new trapezoids to map
|
||||
foreach (Trapezoid y in tList)
|
||||
{
|
||||
_trapezoidalMap.Map.Add(y);
|
||||
}
|
||||
}
|
||||
_trapezoidalMap.Clear();
|
||||
}
|
||||
|
||||
// Mark outside trapezoids
|
||||
foreach (Trapezoid t in _trapezoidalMap.Map)
|
||||
{
|
||||
MarkOutside(t);
|
||||
}
|
||||
|
||||
// Collect interior trapezoids
|
||||
foreach (Trapezoid t in _trapezoidalMap.Map)
|
||||
{
|
||||
if (t.Inside)
|
||||
{
|
||||
Trapezoids.Add(t);
|
||||
t.AddPoints();
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the triangles
|
||||
CreateMountains();
|
||||
}
|
||||
|
||||
// Build a list of x-monotone mountains
|
||||
private void CreateMountains()
|
||||
{
|
||||
foreach (Edge edge in _edgeList)
|
||||
{
|
||||
if (edge.MPoints.Count > 2)
|
||||
{
|
||||
MonotoneMountain mountain = new MonotoneMountain();
|
||||
|
||||
// Sorting is a perfromance hit. Literature says this can be accomplised in
|
||||
// linear time, although I don't see a way around using traditional methods
|
||||
// when using a randomized incremental algorithm
|
||||
|
||||
// Insertion sort is one of the fastest algorithms for sorting arrays containing
|
||||
// fewer than ten elements, or for lists that are already mostly sorted.
|
||||
|
||||
List<Point> points = new List<Point>(edge.MPoints);
|
||||
points.Sort((p1, p2) => p1.X.CompareTo(p2.X));
|
||||
|
||||
foreach (Point p in points)
|
||||
mountain.Add(p);
|
||||
|
||||
// Triangulate monotone mountain
|
||||
mountain.Process();
|
||||
|
||||
// Extract the triangles into a single list
|
||||
foreach (List<Point> t in mountain.Triangles)
|
||||
{
|
||||
Triangles.Add(t);
|
||||
}
|
||||
|
||||
_xMonoPoly.Add(mountain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the outside trapezoids surrounding the polygon
|
||||
private void MarkOutside(Trapezoid t)
|
||||
{
|
||||
if (t.Top == _boundingBox.Top || t.Bottom == _boundingBox.Bottom)
|
||||
t.TrimNeighbors();
|
||||
}
|
||||
|
||||
// Create segments and connect end points; update edge event pointer
|
||||
private List<Edge> InitEdges(List<Point> points)
|
||||
{
|
||||
List<Edge> edges = new List<Edge>();
|
||||
|
||||
for (int i = 0; i < points.Count - 1; i++)
|
||||
{
|
||||
edges.Add(new Edge(points[i], points[i + 1]));
|
||||
}
|
||||
edges.Add(new Edge(points[0], points[points.Count - 1]));
|
||||
return OrderSegments(edges);
|
||||
}
|
||||
|
||||
private List<Edge> OrderSegments(List<Edge> edgeInput)
|
||||
{
|
||||
// Ignore vertical segments!
|
||||
List<Edge> edges = new List<Edge>();
|
||||
|
||||
foreach (Edge e in edgeInput)
|
||||
{
|
||||
Point p = ShearTransform(e.P);
|
||||
Point q = ShearTransform(e.Q);
|
||||
|
||||
// Point p must be to the left of point q
|
||||
if (p.X > q.X)
|
||||
{
|
||||
edges.Add(new Edge(q, p));
|
||||
}
|
||||
else if (p.X < q.X)
|
||||
{
|
||||
edges.Add(new Edge(p, q));
|
||||
}
|
||||
}
|
||||
|
||||
// Randomized triangulation improves performance
|
||||
// See Seidel's paper, or O'Rourke's book, p. 57
|
||||
Shuffle(edges);
|
||||
return edges;
|
||||
}
|
||||
|
||||
private static void Shuffle<T>(IList<T> list)
|
||||
{
|
||||
Random rng = new Random();
|
||||
int n = list.Count;
|
||||
while (n > 1)
|
||||
{
|
||||
n--;
|
||||
int k = rng.Next(n + 1);
|
||||
T value = list[k];
|
||||
list[k] = list[n];
|
||||
list[n] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevents any two distinct endpoints from lying on a common vertical line, and avoiding
|
||||
// the degenerate case. See Mark de Berg et al, Chapter 6.3
|
||||
private Point ShearTransform(Point point)
|
||||
{
|
||||
return new Point(point.X + _sheer * point.Y, point.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace FarseerPhysics.Common.Decomposition.Seidel
|
||||
{
|
||||
internal class XNode : Node
|
||||
{
|
||||
private Point _point;
|
||||
|
||||
public XNode(Point point, Node lChild, Node rChild)
|
||||
: base(lChild, rChild)
|
||||
{
|
||||
_point = point;
|
||||
}
|
||||
|
||||
public override Sink Locate(Edge edge)
|
||||
{
|
||||
if (edge.P.X >= _point.X)
|
||||
return RightChild.Locate(edge); // Move to the right in the graph
|
||||
|
||||
return LeftChild.Locate(edge); // Move to the left in the graph
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace FarseerPhysics.Common.Decomposition.Seidel
|
||||
{
|
||||
internal class YNode : Node
|
||||
{
|
||||
private Edge _edge;
|
||||
|
||||
public YNode(Edge edge, Node lChild, Node rChild)
|
||||
: base(lChild, rChild)
|
||||
{
|
||||
_edge = edge;
|
||||
}
|
||||
|
||||
public override Sink Locate(Edge edge)
|
||||
{
|
||||
if (_edge.IsAbove(edge.P))
|
||||
return RightChild.Locate(edge); // Move down the graph
|
||||
|
||||
if (_edge.IsBelow(edge.P))
|
||||
return LeftChild.Locate(edge); // Move up the graph
|
||||
|
||||
// s and segment share the same endpoint, p
|
||||
if (edge.Slope < _edge.Slope)
|
||||
return RightChild.Locate(edge); // Move down the graph
|
||||
|
||||
// Move up the graph
|
||||
return LeftChild.Locate(edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Farseer Physics Engine:
|
||||
* Copyright (c) 2012 Ian Qvist
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using FarseerPhysics.Common.Decomposition.Seidel;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Point = FarseerPhysics.Common.Decomposition.Seidel.Point;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition
|
||||
{
|
||||
/// <summary>
|
||||
/// Convex decomposition algorithm created by Raimund Seidel
|
||||
///
|
||||
/// Properties:
|
||||
/// - Decompose the polygon into trapezoids, then triangulate.
|
||||
/// - To use the trapezoid data, use ConvexPartitionTrapezoid()
|
||||
/// - Generate a lot of garbage due to incapsulation of the Poly2Tri library.
|
||||
/// - Running time is O(n log n), n = number of vertices.
|
||||
/// - Running time is almost linear for most simple polygons.
|
||||
/// - Does not care about winding order.
|
||||
///
|
||||
/// For more information, see Raimund Seidel's paper "A simple and fast incremental randomized
|
||||
/// algorithm for computing trapezoidal decompositions and for triangulating polygons"
|
||||
///
|
||||
/// See also: "Computational Geometry", 3rd edition, by Mark de Berg et al, Chapter 6.2
|
||||
/// "Computational Geometry in C", 2nd edition, by Joseph O'Rourke
|
||||
///
|
||||
/// Original code from the Poly2Tri project by Mason Green.
|
||||
/// http://code.google.com/p/poly2tri/source/browse?repo=archive#hg/scala/src/org/poly2tri/seidel
|
||||
///
|
||||
/// This implementation is from Dec 14, 2010
|
||||
/// </summary>
|
||||
internal static class SeidelDecomposer
|
||||
{
|
||||
/// <summary>
|
||||
/// Decompose the polygon into several smaller non-concave polygons.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The polygon to decompose.</param>
|
||||
/// <param name="sheer">The sheer to use if you get bad results, try using a higher value.</param>
|
||||
/// <returns>A list of triangles</returns>
|
||||
public static List<Vertices> ConvexPartition(Vertices vertices, float sheer = 0.001f)
|
||||
{
|
||||
Debug.Assert(vertices.Count > 3);
|
||||
|
||||
List<Point> compatList = new List<Point>(vertices.Count);
|
||||
|
||||
foreach (Vector2 vertex in vertices)
|
||||
{
|
||||
compatList.Add(new Point(vertex.X, vertex.Y));
|
||||
}
|
||||
|
||||
Triangulator t = new Triangulator(compatList, sheer);
|
||||
|
||||
List<Vertices> list = new List<Vertices>();
|
||||
|
||||
foreach (List<Point> triangle in t.Triangles)
|
||||
{
|
||||
Vertices outTriangles = new Vertices(triangle.Count);
|
||||
|
||||
foreach (Point outTriangle in triangle)
|
||||
{
|
||||
outTriangles.Add(new Vector2(outTriangle.X, outTriangle.Y));
|
||||
}
|
||||
|
||||
list.Add(outTriangles);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompose the polygon into several smaller non-concave polygons.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The polygon to decompose.</param>
|
||||
/// <param name="sheer">The sheer to use if you get bad results, try using a higher value.</param>
|
||||
/// <returns>A list of trapezoids</returns>
|
||||
public static List<Vertices> ConvexPartitionTrapezoid(Vertices vertices, float sheer = 0.001f)
|
||||
{
|
||||
List<Point> compatList = new List<Point>(vertices.Count);
|
||||
|
||||
foreach (Vector2 vertex in vertices)
|
||||
{
|
||||
compatList.Add(new Point(vertex.X, vertex.Y));
|
||||
}
|
||||
|
||||
Triangulator t = new Triangulator(compatList, sheer);
|
||||
|
||||
List<Vertices> list = new List<Vertices>();
|
||||
|
||||
foreach (Trapezoid trapezoid in t.Trapezoids)
|
||||
{
|
||||
Vertices verts = new Vertices();
|
||||
|
||||
List<Point> points = trapezoid.GetVertices();
|
||||
foreach (Point point in points)
|
||||
{
|
||||
verts.Add(new Vector2(point.X, point.Y));
|
||||
}
|
||||
|
||||
list.Add(verts);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using FarseerPhysics.Common.ConvexHull;
|
||||
|
||||
namespace FarseerPhysics.Common.Decomposition
|
||||
{
|
||||
public enum TriangulationAlgorithm
|
||||
{
|
||||
/// <summary>
|
||||
/// Convex decomposition algorithm using ear clipping
|
||||
///
|
||||
/// Properties:
|
||||
/// - Only works on simple polygons.
|
||||
/// - Does not support holes.
|
||||
/// - Running time is O(n^2), n = number of vertices.
|
||||
/// </summary>
|
||||
Earclip,
|
||||
|
||||
/// <summary>
|
||||
/// Convex decomposition algorithm created by Mark Bayazit (http://mnbayazit.com/)
|
||||
///
|
||||
/// Properties:
|
||||
/// - Tries to decompose using polygons instead of triangles.
|
||||
/// - Tends to produce optimal results with low processing time.
|
||||
/// - Running time is O(nr), n = number of vertices, r = reflex vertices.
|
||||
/// - Does not support holes.
|
||||
/// </summary>
|
||||
Bayazit,
|
||||
|
||||
/// <summary>
|
||||
/// Convex decomposition algorithm created by unknown
|
||||
///
|
||||
/// Properties:
|
||||
/// - No support for holes
|
||||
/// - Very fast
|
||||
/// - Only works on simple polygons
|
||||
/// - Only works on counter clockwise polygons
|
||||
/// </summary>
|
||||
Flipcode,
|
||||
|
||||
/// <summary>
|
||||
/// Convex decomposition algorithm created by Raimund Seidel
|
||||
///
|
||||
/// Properties:
|
||||
/// - Decompose the polygon into trapezoids, then triangulate.
|
||||
/// - To use the trapezoid data, use ConvexPartitionTrapezoid()
|
||||
/// - Generate a lot of garbage due to incapsulation of the Poly2Tri library.
|
||||
/// - Running time is O(n log n), n = number of vertices.
|
||||
/// - Running time is almost linear for most simple polygons.
|
||||
/// - Does not care about winding order.
|
||||
/// </summary>
|
||||
Seidel,
|
||||
SeidelTrapezoids,
|
||||
|
||||
/// <summary>
|
||||
/// 2D constrained Delaunay triangulation algorithm.
|
||||
/// Based on the paper "Sweep-line algorithm for constrained Delaunay triangulation" by V. Domiter and and B. Zalik
|
||||
///
|
||||
/// Properties:
|
||||
/// - Creates triangles with a large interior angle.
|
||||
/// - Supports holes
|
||||
/// - Generate a lot of garbage due to incapsulation of the Poly2Tri library.
|
||||
/// - Running time is O(n^2), n = number of vertices.
|
||||
/// - Does not care about winding order.
|
||||
/// </summary>
|
||||
Delauny
|
||||
}
|
||||
|
||||
public static class Triangulate
|
||||
{
|
||||
public static List<Vertices> ConvexPartition(Vertices vertices, TriangulationAlgorithm algorithm, bool discardAndFixInvalid = true, float tolerance = 0.001f)
|
||||
{
|
||||
if (vertices.Count <= 3)
|
||||
return new List<Vertices> { vertices };
|
||||
|
||||
List<Vertices> results;
|
||||
|
||||
switch (algorithm)
|
||||
{
|
||||
case TriangulationAlgorithm.Earclip:
|
||||
if (Settings.SkipSanityChecks)
|
||||
Debug.Assert(!vertices.IsCounterClockWise(), "The Earclip algorithm expects the polygon to be clockwise.");
|
||||
else
|
||||
{
|
||||
if (vertices.IsCounterClockWise())
|
||||
{
|
||||
Vertices temp = new Vertices(vertices);
|
||||
temp.Reverse();
|
||||
results = EarclipDecomposer.ConvexPartition(temp, tolerance);
|
||||
}
|
||||
else
|
||||
results = EarclipDecomposer.ConvexPartition(vertices, tolerance);
|
||||
}
|
||||
break;
|
||||
case TriangulationAlgorithm.Bayazit:
|
||||
if (Settings.SkipSanityChecks)
|
||||
Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly.");
|
||||
else
|
||||
{
|
||||
if (!vertices.IsCounterClockWise())
|
||||
{
|
||||
Vertices temp = new Vertices(vertices);
|
||||
temp.Reverse();
|
||||
results = BayazitDecomposer.ConvexPartition(temp);
|
||||
}
|
||||
else
|
||||
results = BayazitDecomposer.ConvexPartition(vertices);
|
||||
}
|
||||
break;
|
||||
case TriangulationAlgorithm.Flipcode:
|
||||
if (Settings.SkipSanityChecks)
|
||||
Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly.");
|
||||
else
|
||||
{
|
||||
if (!vertices.IsCounterClockWise())
|
||||
{
|
||||
Vertices temp = new Vertices(vertices);
|
||||
temp.Reverse();
|
||||
results = FlipcodeDecomposer.ConvexPartition(temp);
|
||||
}
|
||||
else
|
||||
results = FlipcodeDecomposer.ConvexPartition(vertices);
|
||||
}
|
||||
break;
|
||||
case TriangulationAlgorithm.Seidel:
|
||||
results = SeidelDecomposer.ConvexPartition(vertices, tolerance);
|
||||
break;
|
||||
case TriangulationAlgorithm.SeidelTrapezoids:
|
||||
results = SeidelDecomposer.ConvexPartitionTrapezoid(vertices, tolerance);
|
||||
break;
|
||||
case TriangulationAlgorithm.Delauny:
|
||||
results = CDTDecomposer.ConvexPartition(vertices);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("algorithm");
|
||||
}
|
||||
|
||||
if (discardAndFixInvalid)
|
||||
{
|
||||
for (int i = results.Count - 1; i >= 0; i--)
|
||||
{
|
||||
Vertices polygon = results[i];
|
||||
|
||||
if (!ValidatePolygon(polygon))
|
||||
results.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private static bool ValidatePolygon(Vertices polygon)
|
||||
{
|
||||
PolygonError errorCode = polygon.CheckPolygon();
|
||||
|
||||
if (errorCode == PolygonError.InvalidAmountOfVertices || errorCode == PolygonError.AreaTooSmall || errorCode == PolygonError.SideTooSmall || errorCode == PolygonError.NotSimple)
|
||||
return false;
|
||||
|
||||
if (errorCode == PolygonError.NotCounterClockWise) //NotCounterCloseWise is the last check in CheckPolygon(), thus we don't need to call ValidatePolygon again.
|
||||
polygon.Reverse();
|
||||
|
||||
if (errorCode == PolygonError.NotConvex)
|
||||
{
|
||||
polygon = GiftWrap.GetConvexHull(polygon);
|
||||
return ValidatePolygon(polygon);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user