Files
LuaCsForBarotraumaEP/Farseer Physics Engine 3.5/Common/Decomposition/Seidel/Triangulator.cs

203 lines
6.7 KiB
C#

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);
}
}
}