package stu.tnt.math;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.IntArray;
public class ePolygon {
private final float[] localVertices;
private float[] worldVertices;
private final IntArray noIndex = new IntArray(3);
private float x, y;
private float originX, originY;
private float rotation;
private float scaleX = 1, scaleY = 1;
private boolean dirty = true;
private Rectangle bounds;
public ePolygon() {
this.localVertices = new float[0];
}
public ePolygon(float[] vertices) {
if (vertices.length < 6 || vertices.length % 2 != 0)
throw new IllegalArgumentException(
"polygons must contain at least 3 points.");
this.localVertices = vertices;
}
/** Returns no index vertices of this polygon */
public int[] getNoIndex() {
noIndex.shrink();
return noIndex.items;
}
public void setNoIndex(int... noindex) {
noIndex.clear();
for (int i : noindex) {
if (i >= 0 && i < localVertices.length / 2)
noIndex.add(i);
}
}
/**
* Returns vertices without scaling or rotation and without being offset by
* the polygon position.
*/
public float[] getVertices() {
return localVertices;
}
/** Returns vertices scaled, rotated, and offset by the polygon position. */
public float[] getTransformedVertices() {
if (!dirty)
return worldVertices;
dirty = false;
final float[] localVertices = this.localVertices;
if (worldVertices == null
|| worldVertices.length < localVertices.length)
worldVertices = new float[localVertices.length];
final float[] worldVertices = this.worldVertices;
final float positionX = x;
final float positionY = y;
final float originX = this.originX;
final float originY = this.originY;
final float scaleX = this.scaleX;
final float scaleY = this.scaleY;
final boolean scale = scaleX != 1 || scaleY != 1;
final float rotation = this.rotation;
final float cos = MathUtils.cosDeg(rotation);
final float sin = MathUtils.sinDeg(rotation);
for (int i = 0, n = localVertices.length; i < n; i += 2) {
float x = localVertices[i] - originX;
float y = localVertices[i + 1] - originY;
// scale if needed
if (scale) {
x *= scaleX;
y *= scaleY;
}
// rotate if needed
if (rotation != 0) {
float oldX = x;
x = cos * x - sin * y;
y = sin * oldX + cos * y;
}
worldVertices[i] = positionX + x + originX;
worldVertices[i + 1] = positionY + y + originY;
}
return worldVertices;
}
public void setOrigin(float originX, float originY) {
this.originX = originX;
this.originY = originY;
dirty = true;
}
public void setPosition(float x, float y) {
this.x = x;
this.y = y;
dirty = true;
}
public void translate(float x, float y) {
this.x += x;
this.y += y;
dirty = true;
}
public void setRotation(float degrees) {
this.rotation = degrees;
dirty = true;
}
public void rotate(float degrees) {
rotation += degrees;
dirty = true;
}
public void setScale(float scaleX, float scaleY) {
this.scaleX = scaleX;
this.scaleY = scaleY;
dirty = true;
}
public void scale(float amount) {
this.scaleX += amount;
this.scaleY += amount;
dirty = true;
}
public void dirty() {
dirty = true;
}
public float area() {
float area = 0;
float[] vertices = getTransformedVertices();
final int numFloats = vertices.length;
int x1, y1, x2, y2;
for (int i = 0; i < numFloats; i += 2) {
x1 = i;
y1 = i + 1;
x2 = (i + 2) % numFloats;
y2 = (i + 3) % numFloats;
area += vertices[x1] * vertices[y2];
area -= vertices[x2] * vertices[y1];
}
area *= 0.5f;
return area;
}
/**
* Returns an axis-aligned bounding box of this polygon.
*
* Note the returned Rectangle is cached in this polygon, and will be reused
* if this Polygon is changed.
*
* @return this polygon's bounding box Rectangle
*/
public Rectangle getBoundingRectangle() {
float[] vertices = getTransformedVertices();
float minX = vertices[0];
float minY = vertices[1];
float maxX = vertices[0];
float maxY = vertices[1];
final int numFloats = vertices.length;
for (int i = 2; i < numFloats; i += 2) {
minX = minX > vertices[i] ? vertices[i] : minX;
minY = minY > vertices[i + 1] ? vertices[i + 1] : minY;
maxX = maxX < vertices[i] ? vertices[i] : maxX;
maxY = maxY < vertices[i + 1] ? vertices[i + 1] : maxY;
}
if (bounds == null)
bounds = new Rectangle();
bounds.x = minX;
bounds.y = minY;
bounds.width = maxX - minX;
bounds.height = maxY - minY;
return bounds;
}
public boolean contains(float x, float y) {
final float[] vertices = getTransformedVertices();
final int numFloats = vertices.length;
int intersects = 0;
for (int i = 0; i < numFloats; i += 2) {
float x1 = vertices[i];
float y1 = vertices[i + 1];
float x2 = vertices[(i + 2) % numFloats];
float y2 = vertices[(i + 3) % numFloats];
if (((y1 <= y && y < y2) || (y2 <= y && y < y1))
&& x < ((x2 - x1) / (y2 - y1) * (y - y1) + x1))
intersects++;
}
return (intersects & 1) == 1;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public float getOriginX() {
return originX;
}
public float getOriginY() {
return originY;
}
public float getRotation() {
return rotation;
}
public float getScaleX() {
return scaleX;
}
public float getScaleY() {
return scaleY;
}
public void draw(ShapeRenderer render) {
final float[] vertices = getTransformedVertices();
for (int i = 0; i < vertices.length; i += 2) {
if (i + 2 >= vertices.length) {
render.line(vertices[i], vertices[i + 1], vertices[0],
vertices[1]);
} else
render.line(vertices[i], vertices[i + 1], vertices[i + 2],
vertices[i + 3]);
}
}
public static void drawPolygon(float[] vertices, ShapeRenderer render) {
for (int i = 0; i < vertices.length; i += 2) {
if (i + 2 >= vertices.length) {
render.line(vertices[i], vertices[i + 1], vertices[0],
vertices[1]);
} else
render.line(vertices[i], vertices[i + 1], vertices[i + 2],
vertices[i + 3]);
}
}
}