evershade/Packages/super-tiled2unity.v2.2.0/Editor/Collision/Geometry/PolygonEdge.cs

135 lines
4.8 KiB
C#

using UnityEngine;
namespace SuperTiled2Unity.Editor.Geometry
{
// A polygon edge that may be shared with another polygon
public class PolygonEdge
{
public bool HasBeenMerged { get; private set; }
public Vector2 P { get; }
public Vector2 Q { get; }
public float Length2 { get; }
// Our Major partner (the edge PQ will be counter-clockwise on this polygon)
// When we merge polygons it is always the Major partner that absorbs
public CompositionPolygon MajorPartner { get; private set; }
public int MajorPartner_pIndex { get; private set; }
public int MajorPartner_qIndex { get; private set; }
// Our Minor partner (the edge PQ will clockwise on this polygon)
public CompositionPolygon MinorPartner { get; private set; }
public int MinorPartner_pIndex { get; private set; }
public int MinorPartner_qIndex { get; private set; }
public PolygonEdge(CompositionPolygon compPolygon, int p)
{
Debug.Assert(compPolygon.Points.Count >= 3);
HasBeenMerged = false;
// P and Q make up our edge
int q = (p + 1) % compPolygon.Points.Count;
P = compPolygon.Points[p];
Q = compPolygon.Points[q];
// Create a compositional polygon with our edge
MajorPartner = compPolygon;
MajorPartner_pIndex = p;
MajorPartner_qIndex = q;
// Calculate the squared length
float x = (P.x - Q.x);
float y = (P.y - Q.y);
Length2 = (x * x) + (y * y);
}
public void AssignMinorPartner(CompositionPolygon polygon)
{
Debug.Assert(MinorPartner == null);
Debug.Assert(MajorPartner != null);
ReplaceMinor(polygon);
}
public void ReplaceMajor(CompositionPolygon polygon)
{
MajorPartner = polygon;
MajorPartner_pIndex = MajorPartner.Points.IndexOf(P);
MajorPartner_qIndex = MajorPartner.Points.IndexOf(Q);
}
public void ReplaceMinor(CompositionPolygon polygon)
{
MinorPartner = polygon;
MinorPartner_pIndex = MinorPartner.Points.IndexOf(P);
MinorPartner_qIndex = MinorPartner.Points.IndexOf(Q);
}
public bool CanMergePolygons()
{
// The two polygon partners can be merged if the two vectors on each point where they would merge don't create a concave polygon
// Concave testing is done through a cross product and assumes CCW winding of the polyon points
// Can merge point P of the Major/CCW partner?
{
// A = CWW[P - 1]
// B = CWW[P]
// C = CW[P + 1]
var A = MajorPartner.PrevPoint(MajorPartner_pIndex);
var B = MajorPartner.Points[MajorPartner_pIndex];
var C = MinorPartner.NextPoint(MinorPartner_pIndex);
float cross = GeoMath.Cross(A, B, C);
if (cross > 0)
return false;
}
// Can merge point Q of Major/CCW partner?
{
// A = CWW[Q + 1]
// B = CWW[Q]
// C = CW[Q-1]
var A = MajorPartner.NextPoint(MajorPartner_qIndex);
var B = MajorPartner.Points[MajorPartner_qIndex];
var C = MinorPartner.PrevPoint(MinorPartner_qIndex);
float cross = GeoMath.Cross(A, B, C);
if (cross < 0)
return false;
}
return true;
}
public void MergePolygons()
{
Debug.Assert(HasBeenMerged == false);
// The major polygon will absorb the minor
MajorPartner.AbsorbPolygon(MajorPartner_qIndex, MinorPartner, MinorPartner_pIndex);
// All edges that referened the minor will need to reference the major
MinorPartner.ReplaceEdgesWithPolygon(MajorPartner, this);
// All edges that reference the major will need their P/Q indices updated
MajorPartner.UpdateEdgeIndices(this);
// This edge has now been processed and we shouldn't merge on it again
HasBeenMerged = true;
}
public void UpdateIndices(CompositionPolygon polygon)
{
if (polygon == this.MajorPartner)
{
MajorPartner_pIndex = polygon.Points.IndexOf(P);
MajorPartner_qIndex = polygon.Points.IndexOf(Q);
}
else if (polygon == MinorPartner)
{
MinorPartner_pIndex = polygon.Points.IndexOf(P);
MinorPartner_qIndex = polygon.Points.IndexOf(Q);
}
}
}
}