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