// 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; }
// 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, const cpVect *verts, cpVect *result, int *first, cpFloat tol) { if(verts != 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)); } // Degenerate case, all points 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; return QHullReduce(tol, result + 2, count - 2, a, b, a, result + 1) + 1; }
// Recursively reduce the vertex count on a polyline. Works best for smooth shapes. // 'tol' is the maximum error for the reduction. // The reduced polyline will never be farther than this distance from the original polyline. cpPolyline * cpPolylineSimplifyCurves(cpPolyline *line, cpFloat tol) { cpPolyline *reduced = cpPolylineMake(line->count); cpFloat min = tol/2.0f; if(cpPolylineIsClosed(line)){ int start, end; cpLoopIndexes(line->verts, line->count - 1, &start, &end); reduced = cpPolylinePush(reduced, line->verts[start]); reduced = DouglasPeucker(line->verts, reduced, line->count - 1, start, end, min, tol); reduced = cpPolylinePush(reduced, line->verts[end]); reduced = DouglasPeucker(line->verts, reduced, line->count - 1, end, start, min, tol); reduced = cpPolylinePush(reduced, line->verts[start]); } else { reduced = cpPolylinePush(reduced, line->verts[0]); reduced = DouglasPeucker(line->verts, reduced, line->count, 0, line->count - 1, min, tol); reduced = cpPolylinePush(reduced, line->verts[line->count - 1]); } return cpPolylineShrink(reduced); }