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 JarvisMarch.jarvisMarch(pVertices, pVertexCount, pVertexOffsetX, pVertexOffsetY, pVertexStride); } // =========================================================== // Methods // =========================================================== private static 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 // =========================================================== }