package org.andengine.extension.physics.box2d.util.hull; import com.badlogic.gdx.math.Vector2; /** * (c) 2010 Nicolas Gramlich * (c) 2011 Zynga Inc. * * @author Nicolas Gramlich * @since 14:01:34 - 14.09.2010 * @see http://www.iti.fh-flensburg.de/lang/algorithmen/geo/ */ public class QuickHull extends BaseHullAlgorithm { // =========================================================== // Constants // =========================================================== private final static float EPSILON = 1e-3f; // =========================================================== // Fields // =========================================================== // =========================================================== // Constructors // =========================================================== // =========================================================== // Getter & Setter // =========================================================== // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== @Override public int computeHull(final Vector2[] pVectors) { this.mVertices = pVectors; this.mVertexCount = this.mVertices.length; this.mHullVertexCount = 0; this.quickHull(); return this.mHullVertexCount; } // =========================================================== // Methods // =========================================================== // =========================================================== // Inner and Anonymous Classes // =========================================================== private void quickHull() { this.swap(0, this.indexOfLowestVertex()); this.mHullVertexCount++; final Vector2Line line = new Vector2Line(this.mVertices[0], new Vector2(this.mVertices[0]).add(-EPSILON, 0)); this.computeHullVertices(line, 1, this.mVertexCount - 1); } private void computeHullVertices(final Vector2Line pLine, final int pIndexFrom, final int pIndexTo) { if (pIndexFrom > pIndexTo) { return; } final int k = this.indexOfFurthestVertex(pLine, pIndexFrom, pIndexTo); final Vector2Line lineA = new Vector2Line(pLine.mVertexA, this.mVertices[k]); final Vector2Line lineB = new Vector2Line(this.mVertices[k], pLine.mVertexB); this.swap(k, pIndexTo); final int i = this.partition(lineA, pIndexFrom, pIndexTo - 1); /* All vertices from pIndexFrom to i-1 are right of lineA. */ /* All vertices from i to pIndexTo-1 are left of lineA. */ this.computeHullVertices(lineA, pIndexFrom, i - 1); /* All vertices before pIndexTo are now on the hull. */ this.swap(pIndexTo, i); this.swap(i, this.mHullVertexCount); this.mHullVertexCount++; final int j = this.partition(lineB, i + 1, pIndexTo); /* All vertices from i+1 to j-1 are right of lineB. */ /* All vertices from j to pToIndex are on the inside. */ this.computeHullVertices(lineB, i + 1, j - 1); } private int indexOfFurthestVertex(final Vector2Line pLine, final int pFromIndex, final int pToIndex) { final Vector2[] vertices = this.mVertices; int f = pFromIndex; float mx = 0; for (int i = pFromIndex; i <= pToIndex; i++) { final float d = -Vector2Util.area2(vertices[i], pLine); if (d > mx || d == mx && vertices[i].x > vertices[f].y) { mx = d; f = i; } } return f; } private int partition(final Vector2Line pLine, final int pFromIndex, final int pToIndex) { final Vector2[] vertices = this.mVertices; int i = pFromIndex; int j = pToIndex; while (i <= j) { while (i <= j && Vector2Util.isRightOf(vertices[i], pLine)) { i++; } while (i <= j && !Vector2Util.isRightOf(vertices[j], pLine)) { j--; } if (i <= j) { this.swap(i++, j--); } } return i; } }