Aetheria/Assets/Plugins/MSAGL/Routing/Visibility/Polygon.cs
Reinier Vens dbc522a224 Weapos Rejiggered
Modified weapon scripts to eliminate specialized projectile behavior - allows charged weapons to have projectiles and modify weapon stats when charged
Added machine gun weapon & VFX
Moved third party code to Plugins folder to improve compile times
2021-01-31 03:52:32 +00:00

216 lines
No EOL
7.4 KiB
C#

using System;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using Microsoft.Msagl.Core.Geometry;
using Microsoft.Msagl.Core.Geometry.Curves;
using Microsoft.Msagl.Core.Layout;
using Microsoft.Msagl.DebugHelpers;
#if TEST_MSAGL
#endif
namespace Microsoft.Msagl.Routing.Visibility {
/// <summary>
/// the polygon is going clockwise
/// </summary>
#if TEST_MSAGL
[Serializable]
#endif
internal class Polygon {
Polyline polyline;
internal Polyline Polyline {
get { return polyline; }
#if TEST_MSAGL
set { polyline = value; }
#endif
}
readonly PolylinePoint[] points;
internal Polygon(Polyline polyline) {
this.polyline = polyline;
points = new PolylinePoint[polyline.Count];
int i = 0;
PolylinePoint pp = polyline.StartPoint;
for (; i < polyline.Count; i++, pp = pp.Next)
points[i] = pp;
}
internal int Next(int i) {
return Module(i + 1);
}
internal int Prev(int i) {
return Module(i - 1);
}
internal int Count { get { return Polyline.Count; } }
internal int Module(int i) {
if (i < 0)
return i + Count;
if (i < Count)
return i;
return i - Count;
}
internal PolylinePoint this[int i] {
get {
return points[Module(i)];
}
}
//private LineSegment ls(Point pivot, int p) {
// return new LineSegment(pivot, Pnt(p));
//}
internal Point Pnt(int i) {
return this[i].Point;
}
public override string ToString() {
return polyline.ToString();
}
/// <summary>
/// the median of a chunk going clockwise from p1 to p2
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
internal int Median(int p1, int p2) {
System.Diagnostics.Debug.Assert(p1 != p2);//otherwise we do not know what arc is mean: the whole one or just the point
if (p2 > p1)
return (p2 + p1) / 2;
return Module((p2 + Count + p1) / 2);
}
/// <summary>
/// p1 and p2 represent the closest feature. Two cases are possible p1=p2, or p1 and p2 share an edge going from p1 to p2
/// Remind that the polygons are oriented clockwise
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="bisectorPivot"></param>
/// <param name="bisectorRay"></param>
/// <returns></returns>
internal int FindTheFurthestVertexFromBisector(int p1, int p2, Point bisectorPivot, Point bisectorRay) {
Point directionToTheHill = bisectorRay.Rotate(Math.PI / 2);
if ((polyline.StartPoint.Point - bisectorPivot) * directionToTheHill < 0)
directionToTheHill = -directionToTheHill;
if (p1 == p2)
p2 = Next(p1);
//binary search
do {
int m = Median(p2, p1); //now the chunk goes clockwise from p2 to p1
Point mp = Pnt(m);
if ((Pnt(Next(m)) - mp) * directionToTheHill >= 0)
p2 = Next(m);
else if ((Pnt(Prev(m)) - mp) * directionToTheHill >= 0)
p1 = Prev(m);
else
p1 = p2 = m;
}
while (p1 != p2);
return p1;
}
#if TEST_MSAGL
// ReSharper disable UnusedMember.Local
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
static double TestPolygonDist(Polygon a, Polygon b) {
// ReSharper restore UnusedMember.Local
double ret = double.PositiveInfinity, u, v;
for (int i = 0; i < a.Count; i++)
for (int j = 0; j < b.Count; j++)
ret = Math.Min(ret, LineSegment.MinDistBetweenLineSegments(a.Pnt(i), a.Pnt(i + 1), b.Pnt(j),
b.Pnt(j + 1), out u, out v));
return ret;
}
#endif
/// <summary>
/// Distance between two polygons
/// p and q are the closest points
/// The function doesn't work if the polygons intersect each other
/// </summary>
static public double Distance(Polygon a, Polygon b, out Point p, out Point q) {
var tp = new TangentPair(a, b);
tp.FindClosestPoints(out p, out q);
// #if TEST_MSAGL
// if(!ApproximateComparer.Close((p - q).Length,TestPolygonDist(a,b))) {
// using(var stream = File.Open(@"c:\tmp\polygonBug",FileMode.Create)) {
// var bf = new BinaryFormatter();
// bf.Serialize(stream, a);
// bf.Serialize(stream, b);
// }
//
// LayoutAlgorithmSettings.ShowDebugCurves(
// new DebugCurve(100, 0.1, "red", a.Polyline),
// new DebugCurve(100, 0.1, "blue", b.Polyline),
// new DebugCurve(100, 0.1, "black", new LineSegment(p, q)));
// System.Diagnostics.Debug.Fail("wrong distance between two polygons");
// }
// #endif
return (p - q).Length;
}
/// <summary>
/// Distance between two polygons
/// </summary>
static public double Distance(Polygon a, Polygon b) {
System.Diagnostics.Debug.Assert(PolygonIsLegalDebug(a));
System.Diagnostics.Debug.Assert(PolygonIsLegalDebug(b));
Point p, q;
return Distance(a, b, out p, out q);
}
private static bool PolygonIsLegalDebug(Polygon a)
{
var poly = a.Polyline;
for (var p = poly.StartPoint; p.Next != null && p.Next.Next != null; p = p.Next)
if (Point.GetTriangleOrientation(p.Point, p.Next.Point, p.Next.Next.Point) ==
TriangleOrientation.Collinear)
return false;
return true;
}
/// <summary>
/// Distance between polygon and point
/// </summary>
static public double Distance(Polygon poly, Point b)
{
double res = double.PositiveInfinity;
for (int i = 0; i < poly.Count; i++) {
double par;
double dist = Point.DistToLineSegment(b, poly.points[i].Point, poly.points[(i + 1) % poly.Count].Point, out par);
res = Math.Min(res, dist);
}
return res;
}
internal void GetTangentPoints(out int leftTangentPoint, out int rightTangentPoint, Point point) {
var bimodalSequence = new BimodalSequence(GetSequenceDelegate(point), Count);
leftTangentPoint = bimodalSequence.FindMaximum();
rightTangentPoint = bimodalSequence.FindMinimum();
}
private Func<int, double> GetSequenceDelegate(Point point) {
Point pointOfP = Pnt(0);
return delegate(int i) {
double d = Point.Angle(pointOfP, point, Pnt(i));
return d < Math.PI ? d : d - 2 * Math.PI;
};
}
}
}