// QuickHull seemed like a neat algorithm, and efficient-ish for large input sets.
// My implementation performs an in place reduction using the result array as scratch space.
int
cpConvexHull(int count, cpVect *verts, cpVect *result, int *first, cpFloat tol)
{
	if(result){
		// Copy the line vertexes into the empty part of the result polyline to use as a scratch buffer.
		memcpy(result, verts, count*sizeof(cpVect));
	} else {
		// If a result array was not specified, reduce the input instead.
		result = verts;
	}
	
	// Degenerate case, all poins are the same.
	int start, end;
	cpLoopIndexes(verts, count, &start, &end);
	if(start == end){
		if(first) (*first) = 0;
		return 1;
	}
	
	SWAP(result[0], result[start]);
	SWAP(result[1], result[end == 0 ? start : end]);
	
	cpVect a = result[0];
	cpVect b = result[1];
	
	if(first) (*first) = start;
	int resultCount = QHullReduce(tol, result + 2, count - 2, a, b, a, result + 1) + 1;
	cpAssertSoft(cpPolyValidate(result, resultCount),
		"Internal error: cpConvexHull() and cpPolyValidate() did not agree."
		"Please report this error with as much info as you can.");
	return resultCount;
}
static void
setUpVerts(cpPolyShape *poly, int numVerts, const cpVect *verts, cpVect offset)
{
	// Fail if the user attempts to pass a concave poly, or a bad winding.
	cpAssertHard(cpPolyValidate(verts, numVerts), "Polygon is concave or has a reversed winding. Consider using cpConvexHull() or CP_CONVEX_HULL().");
	
	poly->numVerts = numVerts;
	poly->verts = (cpVect *)cpcalloc(2*numVerts, sizeof(cpVect));
	poly->planes = (cpSplittingPlane *)cpcalloc(2*numVerts, sizeof(cpSplittingPlane));
	poly->tVerts = poly->verts + numVerts;
	poly->tPlanes = poly->planes + numVerts;
	
	for(int i=0; i<numVerts; i++){
		cpVect a = cpvadd(offset, verts[i]);
		cpVect b = cpvadd(offset, verts[(i+1)%numVerts]);
		cpVect n = cpvnormalize(cpvperp(cpvsub(b, a)));

		poly->verts[i] = a;
		poly->planes[i].n = n;
		poly->planes[i].d = cpvdot(n, a);
	}
	
	// TODO: Why did I add this? It duplicates work from above.
	for(int i=0; i<numVerts; i++){
		poly->planes[i] = cpSplittingPlaneNew(poly->verts[(i - 1 + numVerts)%numVerts], poly->verts[i]);
	}
}
Example #3
0
cpPolyShape *
cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset)
{
	// Fail if the user attempts to pass a concave poly, or a bad winding.
	assert(cpPolyValidate(verts, numVerts));
	
	setUpVerts(poly, numVerts, verts, offset);
	cpShapeInit((cpShape *)poly, &polyClass, body);

	return poly;
}
Example #4
0
/**	@name	areaForCircle
	@text	Returns the area for a polygon.
	
	@in		table vertices Array containg vertex coordinate components ( t[1] = x0, t[2] = y0, t[3] = x1, t[4] = y1... )
	@out	number area
*/ 
int MOAICpShape::_areaForPolygon ( lua_State* L ) {
	USLuaState state ( L );
	if ( !state.CheckParams ( 1, "T" )) return 0;

	cpVect verts [ MAX_POLY_VERTS ];
	int numVerts = MOAICpShape::LoadVerts ( state, 1, verts, MAX_POLY_VERTS );
			
	if ( numVerts && cpPolyValidate ( verts, numVerts )) {
		cpFloat area = cpAreaForPoly ( numVerts, verts );
		area = area < 0 ? -area : area;
		lua_pushnumber ( L, area );
		return 1;
	}
	return 0;
}