public class

JarvisMarch

extends Object
implements IHullAlgorithm
package org.andengine.util.algorithm.hull;

import org.andengine.opengl.util.VertexUtils;
import org.andengine.util.math.MathConstants;
import org.andengine.util.math.MathUtils;



/**
 * The Jarvis March algorithm marches around the hull,
 * like a ribbon wrapping itself around the points,
 * this algorithm also called the <i><b>gift-wrapping</b></i> algorithm.
 * 
 * (c) 2010 Nicolas Gramlich
 * (c) 2011 Zynga Inc.
 * 
 * @author Nicolas Gramlich
 * @since 14:01:18 - 14.09.2010
 * @see http://www.iti.fh-flensburg.de/lang/algorithmen/geo/
 */
public class JarvisMarch implements IHullAlgorithm {
	// ===========================================================
	// Constants
	// ===========================================================

	// ===========================================================
	// Fields
	// ===========================================================

	// ===========================================================
	// Constructors
	// ===========================================================

	// ===========================================================
	// Getter & Setter
	// ===========================================================

	// ===========================================================
	// Methods for/from SuperClass/Interfaces
	// ===========================================================

	@Override
	public int computeHull(final float[] pVertices, final int pVertexCount, final int pVertexOffsetX, final int pVertexOffsetY, final int pVertexStride) {
		return this.jarvisMarch(pVertices, pVertexCount, pVertexOffsetX, pVertexOffsetY, pVertexStride);
	}

	// ===========================================================
	// Methods
	// ===========================================================

	private int jarvisMarch(final float[] pVertices, final int pVertexCount, final int pVertexOffsetX, final int pVertexOffsetY, final int pVertexStride) {
		/* Start at the lowest (y-axis) of all vertices. */
		final int firstHullVertexIndex = HullUtils.indexOfLowestVertex(pVertices, pVertexCount, pVertexOffsetY, pVertexStride);
		final float firstHullVertexX = VertexUtils.getVertex(pVertices, pVertexOffsetX, pVertexStride, firstHullVertexIndex);
		final float firstHullVertexY = VertexUtils.getVertex(pVertices, pVertexOffsetY, pVertexStride, firstHullVertexIndex);

		int hullVertexCount = 0;
		int currentHullVertexIndex = firstHullVertexIndex;
		float currentHullVertexAngle = 0; /* 0 degrees. */
		do {
			HullUtils.swap(pVertices, pVertexStride, hullVertexCount, currentHullVertexIndex);

			final float currentHullPointVertexX = VertexUtils.getVertex(pVertices, pVertexOffsetX, pVertexStride, hullVertexCount);
			final float currentHullPointVertexY = VertexUtils.getVertex(pVertices, pVertexOffsetY, pVertexStride, hullVertexCount);

			hullVertexCount++;

			/* Compute the angle between the current hull vertex and all remaining vertices.
			 * Pick the smallest angle larger then the current angle. */
			int nextHullVertexIndex = 0;
			float nextHullVertexAngle = MathConstants.PI_TWICE; /* 360 degrees. */

			/* Start searching one behind the already found hull vertices. */
			for(int j = hullVertexCount; j < pVertexCount; j++) {
				final float possibleNextHullVertexX = VertexUtils.getVertex(pVertices, pVertexOffsetX, pVertexStride, j);
				final float possibleNextHullVertexY = VertexUtils.getVertex(pVertices, pVertexOffsetY, pVertexStride, j);

				/* Ignore identical vertices. */
				if(currentHullPointVertexX != possibleNextHullVertexX || currentHullPointVertexY != possibleNextHullVertexY) {
					final float dX = possibleNextHullVertexX - currentHullPointVertexX;
					final float dY = possibleNextHullVertexY - currentHullPointVertexY;
	
					float possibleNextHullVertexAngle = MathUtils.atan2(dY, dX);
					if(possibleNextHullVertexAngle < 0) {
						possibleNextHullVertexAngle += MathConstants.PI_TWICE; /* 360 degrees. */
					}
					if((possibleNextHullVertexAngle >= currentHullVertexAngle) && (possibleNextHullVertexAngle <= nextHullVertexAngle)) {
						nextHullVertexIndex = j;
						nextHullVertexAngle = possibleNextHullVertexAngle;
					}
				}
			}

			/* Compare against first hull vertex. */
			if(hullVertexCount > 1) {
				final float dX = firstHullVertexX - currentHullPointVertexX;
				final float dY = firstHullVertexY - currentHullPointVertexY;

				float possibleNextHullVertexAngle = MathUtils.atan2(dY, dX);
				if(possibleNextHullVertexAngle < 0) {
					possibleNextHullVertexAngle += MathConstants.PI_TWICE; /* 360 degrees. */
				}
				if((possibleNextHullVertexAngle >= currentHullVertexAngle) && (possibleNextHullVertexAngle <= nextHullVertexAngle)) {
					break;
				}
			}

			currentHullVertexAngle = nextHullVertexAngle;
			currentHullVertexIndex = nextHullVertexIndex;
		} while(currentHullVertexIndex > 0);

		return hullVertexCount;
	}

	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================
}