using System;
namespace Spine {
pub struct SkeletonBounds {
private ExposedList<Polygon> polygonPool = new ExposedList<Polygon>();
private f64 minX, minY, maxX, maxY;
pub ExposedList<BoundingBoxAttachment> BoundingBoxes { get; private set; }
pub ExposedList<Polygon> Polygons { get; private set; }
pub f64 MinX { get { return minX; } set { minX = value; } }
pub f64 MinY { get { return minY; } set { minY = value; } }
pub f64 MaxX { get { return maxX; } set { maxX = value; } }
pub f64 MaxY { get { return maxY; } set { maxY = value; } }
pub f64 Width { get { return maxX - minX; } }
pub f64 Height { get { return maxY - minY; } }
pub SkeletonBounds () {
BoundingBoxes = new ExposedList<BoundingBoxAttachment>();
Polygons = new ExposedList<Polygon>();
}
pub void Update (Skeleton skeleton, bool updateAabb) {
ExposedList<BoundingBoxAttachment> boundingBoxes = BoundingBoxes;
ExposedList<Polygon> polygons = Polygons;
ExposedList<Slot> slots = skeleton.slots;
int slotCount = slots.Count;
boundingBoxes.Clear();
for (int i = 0, n = polygons.Count; i < n; i++)
polygonPool.Add(polygons.Items[i]);
polygons.Clear();
for (int i = 0; i < slotCount; i++) {
Slot slot = slots.Items[i];
BoundingBoxAttachment boundingBox = slot.attachment as BoundingBoxAttachment;
if (boundingBox == null) continue;
boundingBoxes.Add(boundingBox);
Polygon polygon = null;
int poolCount = polygonPool.Count;
if (poolCount > 0) {
polygon = polygonPool.Items[poolCount - 1];
polygonPool.RemoveAt(poolCount - 1);
} else
polygon = new Polygon();
polygons.Add(polygon);
int count = boundingBox.worldVerticesLength;
polygon.Count = count;
if (polygon.Vertices.Length < count) polygon.Vertices = new f64[count];
boundingBox.ComputeWorldVertices(slot, polygon.Vertices);
}
if (updateAabb) {
AabbCompute();
} else {
minX = int.MinValue;
minY = int.MinValue;
maxX = int.MaxValue;
maxY = int.MaxValue;
}
}
private void AabbCompute () {
f64 minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue;
ExposedList<Polygon> polygons = Polygons;
for (int i = 0, n = polygons.Count; i < n; i++) {
Polygon polygon = polygons.Items[i];
f64[] vertices = polygon.Vertices;
for (int ii = 0, nn = polygon.Count; ii < nn; ii += 2) {
f64 x = vertices[ii];
f64 y = vertices[ii + 1];
minX = Math.Min(minX, x);
minY = Math.Min(minY, y);
maxX = Math.Max(maxX, x);
maxY = Math.Max(maxY, y);
}
}
this.minX = minX;
this.minY = minY;
this.maxX = maxX;
this.maxY = maxY;
}
pub bool AabbContainsPoint (f64 x, f64 y) {
return x >= minX && x <= maxX && y >= minY && y <= maxY;
}
pub bool AabbIntersectsSegment (f64 x1, f64 y1, f64 x2, f64 y2) {
f64 minX = this.minX;
f64 minY = this.minY;
f64 maxX = this.maxX;
f64 maxY = this.maxY;
if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY))
return false;
f64 m = (y2 - y1) / (x2 - x1);
f64 y = m * (minX - x1) + y1;
if (y > minY && y < maxY) return true;
y = m * (maxX - x1) + y1;
if (y > minY && y < maxY) return true;
f64 x = (minY - y1) / m + x1;
if (x > minX && x < maxX) return true;
x = (maxY - y1) / m + x1;
if (x > minX && x < maxX) return true;
return false;
}
pub bool AabbIntersectsSkeleton (SkeletonBounds bounds) {
return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY;
}
pub bool ContainsPoint (Polygon polygon, f64 x, f64 y) {
f64[] vertices = polygon.Vertices;
int nn = polygon.Count;
int prevIndex = nn - 2;
bool inside = false;
for (int ii = 0; ii < nn; ii += 2) {
f64 vertexY = vertices[ii + 1];
f64 prevY = vertices[prevIndex + 1];
if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) {
f64 vertexX = vertices[ii];
if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside;
}
prevIndex = ii;
}
return inside;
}
pub BoundingBoxAttachment ContainsPoint (f64 x, f64 y) {
ExposedList<Polygon> polygons = Polygons;
for (int i = 0, n = polygons.Count; i < n; i++)
if (ContainsPoint(polygons.Items[i], x, y)) return BoundingBoxes.Items[i];
return null;
}
pub BoundingBoxAttachment IntersectsSegment (f64 x1, f64 y1, f64 x2, f64 y2) {
ExposedList<Polygon> polygons = Polygons;
for (int i = 0, n = polygons.Count; i < n; i++)
if (IntersectsSegment(polygons.Items[i], x1, y1, x2, y2)) return BoundingBoxes.Items[i];
return null;
}
pub bool IntersectsSegment (Polygon polygon, f64 x1, f64 y1, f64 x2, f64 y2) {
f64[] vertices = polygon.Vertices;
int nn = polygon.Count;
f64 width12 = x1 - x2, height12 = y1 - y2;
f64 det1 = x1 * y2 - y1 * x2;
f64 x3 = vertices[nn - 2], y3 = vertices[nn - 1];
for (int ii = 0; ii < nn; ii += 2) {
f64 x4 = vertices[ii], y4 = vertices[ii + 1];
f64 det2 = x3 * y4 - y3 * x4;
f64 width34 = x3 - x4, height34 = y3 - y4;
f64 det3 = width12 * height34 - height12 * width34;
f64 x = (det1 * width34 - width12 * det2) / det3;
if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) {
f64 y = (det1 * height34 - height12 * det2) / det3;
if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true;
}
x3 = x4;
y3 = y4;
}
return false;
}
pub Polygon GetPolygon (BoundingBoxAttachment attachment) {
int index = BoundingBoxes.IndexOf(attachment);
return index == -1 ? null : Polygons.Items[index];
}
}
pub struct Polygon {
pub f64[] Vertices { get; set; }
pub int Count { get; set; }
pub Polygon () {
Vertices = new f64[16];
}
}
}