I’ve been working with this example code over on the old forum, which reduces the number of points in a polygon using the Ramer-Douglas-Peucker algorithm. It works great for my purposes, but for one weird thing: it creates duplicates of all the points 
Here’s my demo code; simplification functions below with a few notes:
int numPoints = 12;     // reduce to this many points
float[][] pointsArray = { 
  { 1687, 1667 }, { 1684, 1708 }, { 1663, 1948 }, { 1662, 1955 }, { 1642, 2030 }, { 1640, 2037 }, { 1639, 2040 }, { 1572, 2225 }, { 1570, 2230 }, { 1457, 2472 }, { 1456, 2474 }, { 1444, 2497 }, { 1378, 2623 }, { 1359, 2656 }, { 1355, 2662 }, { 1332, 2694 }, { 1307, 2717 }, { 1297, 2725 }, { 1283, 2736 }, { 1280, 2738 }, { 1265, 2747 }, { 1261, 2749 }, { 1235, 2756 }, { 1172, 2759 }, { 1110, 2759 }, { 1104, 2756 }, { 1096, 2751 }, { 1095, 2750 }, { 796, 2213 }, { 772, 2164 }, { 753, 2118 }, { 749, 2108 }, { 695, 1960 }, { 674, 1899 }, { 672, 1891 }, { 622, 1631 }, { 610, 1567 }, { 588, 1414 }, { 588, 1350 }, { 591, 1292 }, { 595, 1224 }, { 603, 1134 }, { 628, 964 }, { 643, 911 }, { 660, 863 }, { 664, 854 }, { 768, 670 }, { 1039, 207 }, { 1099, 207 }, { 1101, 209 }, { 1386, 634 }, { 1431, 711 }, { 1522, 870 }, { 1597, 1055 }, { 1600, 1063 }, { 1602, 1069 }, { 1648, 1217 }, { 1650, 1224 }, { 1651, 1228 }, { 1669, 1302 }, { 1670, 1312 }, { 1687, 1495 } 
};
void setup() {
  size(800, 600);
  background(255);
  // scale points to fit screen
  ArrayList<PVector> points = new ArrayList<PVector>();
  for (int i=0; i<pointsArray.length; i++) {
    float x = pointsArray[i][0] * 0.2;
    float y = pointsArray[i][1] * 0.2;
    points.add( new PVector(x,y) );
  }
  println("original pts:\t\t" + points.size());
  // draw original polygon
  noFill();
  stroke(0, 150, 255);
  strokeWeight(2);
  beginShape();
  for (PVector point : points) {
    vertex(point.x, point.y);
  }
  endShape(CLOSE);
  fill(0, 100);
  noStroke();
  for (PVector point : points) {
    ellipse(point.x, point.y, 15, 15);
  }
  
  // reduce the number of points in the polygon until it reaches the desired number
  int epsilon = 0;
  ArrayList<PVector> smoothedPoints = douglasPeucker(points, epsilon);
  while (true) {
    epsilon += 1;
    smoothedPoints = douglasPeucker(points, epsilon);
    println("- epsilon " + epsilon + ":\t\t" + smoothedPoints.size());
    if (smoothedPoints.size() <= numPoints) {
      break;
    }
  }
  
  // draw the result
  translate(width/2, 0);
  noFill();
  stroke(0, 150, 255);
  strokeWeight(2);
  beginShape();
  for (PVector point : smoothedPoints) {
    vertex(point.x, point.y);
  }
  endShape(CLOSE);
  fill(0, 100);
  noStroke();
  for (PVector point : smoothedPoints) {
    ellipse(point.x, point.y, 15, 15);
  }
}
And here’s the reduction code – my messy solution is noted about halfway down, where basically I just return the first half of the array list.
ArrayList<PVector> douglasPeucker(ArrayList<PVector> points, float epsilon) {
  return douglasPeucker(points, 0, points.size()-1, epsilon);
}
ArrayList<PVector> douglasPeucker(ArrayList<PVector> points, int startIndex, int endIndexInc, float epsilon) {
  
  // find point with max dist
  float dMax = 0;
  int index = -1;
  for (int i = startIndex+1; i <= endIndexInc; i++) {
    PVector current = points.get(i);
    PVector start =   points.get(startIndex);
    PVector end =     points.get(endIndexInc);
    float d = distToSegmentSquared(current.x, current.y, start.x, start.y, end.x, end.y);
    if (d > dMax) {
      index = i;
      dMax = d;
    }
  }
  dMax = sqrt(dMax);
  // if it's greater we simplify
  if (dMax > epsilon) {
    ArrayList<PVector> resultFront = douglasPeucker(points, startIndex, index, epsilon);
    ArrayList<PVector> resultBack =  douglasPeucker(points, index, endIndexInc, epsilon);
    // combine
    ArrayList<PVector> result = new ArrayList<PVector>(resultFront);
    result.addAll(resultBack);
    return result;
  } 
  else {
    ArrayList<PVector> result = new ArrayList<PVector>();
    result.add( points.get(startIndex) );
    result.add( points.get(endIndexInc) );
    // ***** PROBLEM HERE!!!! ******
    // for some reason gives us duplicates of all the points,
    // so we only return every other one
    ArrayList<PVector> out = new ArrayList<PVector>();
    for (int i=0; i<result.size()/2; i++) {
      out.add(result.get(i));
    }
    return out;
  }
}
float dist2(float x1, float y1, float x2, float y2) { 
  return sq(x1 - x2) + sq(y1 - y2);
}
float distToSegment(float px, float  py, float lx1, float  ly1, float lx2, float ly2) { 
  return sqrt(distToSegmentSquared(px, py, lx1, ly1, lx2, ly2));
}
// inspired by stackoverflow.com/a/1501725/1022707
float distToSegmentSquared(float px, float py, float lx1, float ly1, float lx2, float ly2) {
  float lineDist = dist2(lx1, ly1, lx2, ly2);
  if (lineDist == 0) return dist2(px, py, lx1, ly1);
  float t = ((px - lx1) * (lx2 - lx1) + (py - ly1) * (ly2 - ly1)) / lineDist;
  if (t < 0) return dist2(px, py, lx1, ly1);
  if (t > 1) return dist2(px, py, lx2, ly2);
  return dist2(px, py, lx1 + t * (lx2 - lx1), ly1 + t * (ly2 - ly1));
}
I’m pretty lost as to how this is working, so any help would be much appreciated!


