org.ams.core.Util.java Source code

Java tutorial

Introduction

Here is the source code for org.ams.core.Util.java

Source

/*
 *
 *  The MIT License (MIT)
 *
 *  Copyright (c) <2015> <Andreas Modahl>
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *  THE SOFTWARE.
 *
 */

package org.ams.core;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Intersector;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import org.ams.core.clipper.Path;
import org.ams.core.clipper.Paths;
import org.ams.core.clipper.Point;
import org.ams.core.clipper.Simplify;
import org.ams.core.poly2tri.geometry.polygon.Polygon;
import org.ams.core.poly2tri.geometry.polygon.PolygonPoint;
import org.ams.core.poly2tri.triangulation.delaunay.DelaunayTriangle;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

// TODO Comment
public class Util {

    public static final double scale = 100000;

    public static boolean intersectEdges(Array<Vector2> a, Array<Vector2> b) {
        Vector2 q = new Vector2();
        Vector2 q1 = new Vector2();

        Vector2 v = new Vector2();
        Vector2 v1 = new Vector2();

        Vector2 w = new Vector2();

        for (int i = 0; i < a.size; i++) {
            Util.getEdge(a, i, q, q1);
            for (int j = 0; j < b.size; j++) {
                Util.getEdge(b, j, v, v1);
                if (Intersector.intersectSegments(q, q1, v, v1, w))
                    return true;

            }
        }

        return false;
    }

    /**
     * Puts the coordinates of the endpoints of the edge with index i into
     * v1 and v2.
     */
    public static void getEdge(Array<Vector2> vertices, int i, Vector2 v1, Vector2 v2) {
        v1.set(vertices.get(i % vertices.size));
        v2.set(vertices.get((i + 1) % vertices.size));
    }

    public static boolean clockwisePolygon(Array<Vector2> vertices) {
        float sum = 0;
        Vector2 a, b;
        for (int i = 0; i < vertices.size; i++) {
            a = vertices.get(i);
            b = vertices.get((i + 1) % vertices.size);
            float edge = (b.x - a.x) * (b.y + a.y);
            sum += edge;
        }
        return sum > 0;
    }

    public static Path convertToPath(Array<Vector2> vertices) {
        Path path = new Path();
        for (Vector2 v : vertices) {
            path.add(convertToLongPoint(v));
        }
        return path;
    }

    public static Point.LongPoint convertToLongPoint(Vector2 v) {
        return new Point.LongPoint((long) (v.x * scale), (long) (v.y * scale));
    }

    public static Point.LongPoint convertToLongPoint(float x, float y) {
        return new Point.LongPoint((long) (x * scale), (long) (y * scale));
    }

    public static Vector2 convertToVector(Point.LongPoint lp) {
        return new Vector2((float) (lp.getX() / scale), (float) (lp.getY() / scale));
    }

    public static Array<Array<Vector2>> convertToVectors(Paths paths) {
        Array<Array<Vector2>> converted = new Array<Array<Vector2>>(true, paths.size(), Array.class);
        for (Path p : paths) {
            converted.add(convertToVectors(p));
        }
        return converted;
    }

    public static float getTouchRadius(float zoom) {
        float f = 0.5f * (float) Math.sqrt(zoom);
        f *= (float) Math.pow(Gdx.graphics.getDensity(), 0.25);
        return f;
    }

    public static Array<Triangle> makeTriangles(Array<Vector2> polygon, Array<Array<Vector2>> holes) {

        Array<Triangle> triangles = new Array<Triangle>();

        List<PolygonPoint> asdf = new ArrayList<PolygonPoint>();
        for (Vector2 p : polygon) {
            asdf.add(new PolygonPoint(p.x, p.y));
        }
        Polygon p = new Polygon(asdf);

        if (holes != null) {
            for (Array<Vector2> hole : holes) {
                List<PolygonPoint> qwer = new ArrayList<PolygonPoint>();
                for (Vector2 q : hole) {
                    qwer.add(new PolygonPoint(q.x, q.y));
                }

                p.addHole(new Polygon(qwer));
            }
        }

        org.ams.core.poly2tri.Poly2Tri.triangulate(p);
        List<DelaunayTriangle> ll = p.getTriangles();

        for (DelaunayTriangle dl : ll) {

            Vector2 a = new Vector2((float) dl.points[0].getX(), (float) dl.points[0].getY());
            Vector2 b = new Vector2((float) dl.points[1].getX(), (float) dl.points[1].getY());
            Vector2 c = new Vector2((float) dl.points[2].getX(), (float) dl.points[2].getY());

            triangles.add(new Triangle(a, b, c));

        }

        return triangles;

    }

    public static float[] simplifyAndMakeTriangles(Array<Vector2> vertices) {
        Array<Array<Vector2>> vertices_simplified = Simplify.simplify(vertices);
        Array<float[]> triangles = new Array<float[]>();

        int size = 0;
        for (Array<Vector2> _vertices : vertices_simplified) {
            float[] _triangles;
            _triangles = makeTrianglesAsArray(_vertices);
            triangles.add(_triangles);
            size += _triangles.length;
        }
        float[] simplified = new float[size];

        int k = 0;
        for (int i = 0; i < triangles.size; i++) {
            float[] tri = triangles.get(i);

            for (int j = 0; j < tri.length; j++) {
                simplified[k++] = tri[j];
            }
        }
        return simplified;

    }

    public static Array<Triangle> makeTriangles(Array<Vector2> vertices, boolean safe) {
        return makeTriangles(vertices, null, safe);
    }

    private static Array<Vector2> reverse(Array<Vector2> vertices) {

        Array<Vector2> reverse = new Array<Vector2>(vertices.size);
        for (int i = vertices.size - 1; i >= 0; i--) {
            reverse.add(vertices.get(i));
        }
        return reverse;
    }

    private static boolean checkFixtureArea(Array<Triangle> triangles) {
        float[] triangle = new float[6];
        com.badlogic.gdx.math.Polygon mathPolygon = new com.badlogic.gdx.math.Polygon();

        for (Triangle t : triangles) {
            triangle[0] = t.a.x;
            triangle[1] = t.a.y;
            triangle[2] = t.b.x;
            triangle[3] = t.b.y;
            triangle[4] = t.c.x;
            triangle[5] = t.c.y;
            mathPolygon.setVertices(triangle);

            if (Math.abs(mathPolygon.area()) < 0.005) {
                return false;
            }
        }
        return true;
    }

    public static Array<Triangle> makeTriangles(Array<Vector2> vertices, Array<Array<Vector2>> holes,
            boolean safe) {

        Array<Triangle> triangles = makeTriangles(vertices, holes);
        boolean ok = checkFixtureArea(triangles);
        if (!ok) {
            triangles = makeTriangles(reverse(vertices), holes);
            ok = checkFixtureArea(triangles);
        }

        if (!ok && safe) {
            throw new RuntimeException("Could not create polygon with large enough fixtures");
        }
        return triangles;
    }

    public static float[] makeTrianglesAsArray(Array<Vector2> vertices) {
        Array<Triangle> triangles = makeTriangles(vertices, false);
        float[] trianglesAsFloat = new float[triangles.size * 6];

        int j = 0;
        for (int i = 0; i < triangles.size; i++) {
            Triangle t = triangles.get(i);
            trianglesAsFloat[j++] = t.a.x;
            trianglesAsFloat[j++] = t.a.y;
            trianglesAsFloat[j++] = t.b.x;
            trianglesAsFloat[j++] = t.b.y;
            trianglesAsFloat[j++] = t.c.x;
            trianglesAsFloat[j++] = t.c.y;

        }
        return trianglesAsFloat;
    }

    public static Array<Vector2> convertToVectors(Path path) {
        Array<Vector2> vectors = new Array<Vector2>(true, path.size(), Vector2.class);
        for (Point.LongPoint lp : path) {
            vectors.add(convertToVector(lp));
        }
        return vectors;
    }

    public static float[] makeTriangles(Array<Vector2> vertices) {

        List<PolygonPoint> converted = new ArrayList<PolygonPoint>();
        for (Vector2 p : vertices) {
            converted.add(new PolygonPoint(p.x, p.y));
        }
        Polygon p = new Polygon(converted);

        org.ams.core.poly2tri.Poly2Tri.triangulate(p);
        List<DelaunayTriangle> product = p.getTriangles();

        float[] triangles = new float[product.size() * 6];

        int i = 0;
        for (DelaunayTriangle dl : product) {

            triangles[i++] = (float) dl.points[0].getX();
            triangles[i++] = (float) dl.points[0].getY();

            triangles[i++] = (float) dl.points[1].getX();
            triangles[i++] = (float) dl.points[1].getY();

            triangles[i++] = (float) dl.points[2].getX();
            triangles[i++] = (float) dl.points[2].getY();

        }

        return triangles;

    }

    /**
     * Makes pizza slices from a circle.
     */
    public static float[] makePizzaTriangles(Array<Vector2> vertices, Vector2 origin) {

        float[] triangles = new float[vertices.size * 6];

        Vector2 v1 = new Vector2();
        Vector2 v2 = new Vector2();

        int j = 0;
        for (int i = 0; i < vertices.size; i++) {
            getEdge(vertices, i, v1, v2);

            triangles[j++] = origin.x;
            triangles[j++] = origin.y;

            triangles[j++] = v1.x;
            triangles[j++] = v1.y;

            triangles[j++] = v2.x;
            triangles[j++] = v2.y;

        }
        return triangles;
    }

    /**
     * create a polygon with the shape of a circle
     */
    public static Array<Vector2> makeCircle(Vector2 origin, float radius) {
        Vector2 v2 = new Vector2();
        Vector2 v3 = new Vector2();
        float verticeCount = (int) (36 + radius * 8);
        v2.set(radius, 0);
        // calculate number of segments and length of each segment
        float radiansPerSegment = 0;
        float segmentLength = 0;
        while (segmentLength < 0.05F && verticeCount > 5) {
            verticeCount--;
            radiansPerSegment = (float) (2 * Math.PI / verticeCount);
            v3.x = radius;
            v3.y = 0;
            v3.rotateRad(radiansPerSegment);
            segmentLength = v2.dst(v3);
        }
        Array<Vector2> vertices = new Array<Vector2>(true, (int) verticeCount, Vector2.class);
        for (int i = 0; i < verticeCount; i++) {
            v2.x = radius;
            v2.y = 0;
            v2.rotateRad(i * radiansPerSegment);
            v2.x += origin.x;
            v2.y += origin.y;
            vertices.add(new Vector2(v2));
        }
        return vertices;
    }

    /**
     * Translates given polygon so its centroid is now at the origin.
     *
     * @param vertices some polygon.
     * @return the previous centroid.
     */
    public static Vector2 translateSoCentroidIsAtOrigin(Array<Vector2> vertices) {
        Vector2 centroid = Util.polygonCentroid(vertices);

        for (Vector2 v : vertices) {
            v.sub(centroid);
        }
        return centroid;
    }

    /**
     * Returns the centroid for the specified non-self-intersecting
     * polygon.
     */
    public static Vector2 polygonCentroid(Array<Vector2> vertices) {
        int count = vertices.size;
        if (count < 3)
            throw new IllegalArgumentException("A polygon must have 3 or more coordinate pairs.");
        float x = 0, y = 0;

        float signedArea = 0;

        int i = 0;
        for (; i < count - 1; i++) {
            float x0 = vertices.get(i).x;
            float y0 = vertices.get(i).y;
            float x1 = vertices.get(i + 1).x;
            float y1 = vertices.get(i + 1).y;
            float a = x0 * y1 - x1 * y0;
            signedArea += a;
            x += (x0 + x1) * a;
            y += (y0 + y1) * a;
        }

        float x0 = vertices.get(i).x;
        float y0 = vertices.get(i).y;
        float x1 = vertices.get(0).x;
        float y1 = vertices.get(0).y;

        float a = x0 * y1 - x1 * y0;
        signedArea += a;
        x += (x0 + x1) * a;
        y += (y0 + y1) * a;

        Vector2 centroid = new Vector2();

        if (signedArea == 0) {
            centroid.x = 0;
            centroid.y = 0;
        } else {
            signedArea *= 0.5f;
            centroid.x = x / (6 * signedArea);
            centroid.y = y / (6 * signedArea);
        }
        return centroid;
    }

    public static float getMaximumTranslationX(TextureRegion region) {
        float regWidth = region.getRegionWidth();
        float texWidth = region.getTexture().getWidth();
        return regWidth / texWidth;
    }

    public static float getMaximumTranslationY(TextureRegion region) {
        float regHeight = region.getRegionHeight();
        float texHeight = region.getTexture().getHeight();
        return regHeight / texHeight;
    }

    public static String safeSubstring(Object o, int n) {
        String s = o.toString();
        int y = s.length();
        return s.substring(0, n < y ? n : y);
    }

    public static String getDecimals(float f, int max) {
        String s = String.valueOf(f);

        String[] split = s.split("\\.");

        if (split.length == 0)
            return "";
        return safeSubstring(split[1], max);
    }

    public static float roundToNearestN(float value, float n) {
        return n * (Math.round(value / n));
    }

    /**
     * Find out if a point is inside a polygon. credit:
     * http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
     *
     * @param vertx x coordinates of a polygons vertices
     * @param verty y coordinates of a polygons vertices
     * @param nvert number of vertices stored in the arrays
     * @param testx point to Testttstststs
     * @param testy point to Testttstststs
     * @return whether point is inside polygon.
     */
    public static boolean isPointInsidePolygon(float[] vertx, float[] verty, int nvert, float testx, float testy) {
        int i;
        int j;
        boolean c = false;
        for (i = 0, j = nvert - 1; i < nvert; j = i++) {
            if (((verty[i] > testy) != (verty[j] > testy))
                    && (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i])) {
                c = !c;
            }
        }
        return c;
    }

    public static boolean isPointInsidePolygon(Array<Vector2> vert, float testx, float testy) {
        int i;
        int j;
        int nvert = vert.size;
        boolean c = false;
        for (i = 0, j = nvert - 1; i < nvert; j = i++) {
            if (((vert.items[i].y > testy) != (vert.items[j].y > testy))
                    && (testx < (vert.items[j].x - vert.items[i].x) * (testy - vert.items[i].y)
                            / (vert.items[j].y - vert.items[i].y) + vert.items[i].x)) {
                c = !c;
            }
        }
        return c;
    }

    /**
     * This is a public class because GWT doesn't want to compile otherwise.
     */
    public static class Triangle {

        // coordinates
        public final Vector2 a;
        public final Vector2 b;
        public final Vector2 c;

        public Triangle(Vector2 a, Vector2 b, Vector2 c) {
            this.a = a;
            this.b = b;
            this.c = c;
        }

    }
}