How does polyline simplification in Adobe Illustrator work?

I've played with bezier simplification extensively in attempt to replicate Illustrator's path > simplify. What works best and most like Illustrator is Philip J. Schneider's Graphic's Gems simplification but with an additional step. That step being excluding sharp/angled points on the path.

With a bezier path:

Split the path at each sharp bezier segment. So any segment where its bezier handles are not smooth/collinear or where it creates a 'sharp point' in relation to the segment's two adjacent curves. You can set a threshold of your own defining when a segment is considered 'sharp'. 180 degrees being smooth, and anything from 179.99 or 170 degrees or less being the threshold of what is considered a sharp segment.

With each of these paths that have been split from the original at its sharp segments, apply the curve fitting algorithm to each of the paths, then rejoin them.

This retains sharp edges but smooths out redundant segments, fitting the curve along the rest of the path.

My implementation is in paper.js but the same technique could be leveraged using the fitcurve algorithm:

C: https://github.com/erich666/GraphicsGems/blob/2bab77250b8d45b4dfcb9cf58cf68f19f8268e56/gems/FitCurves.c

JS: https://github.com/soswow/fit-curve


I came across the question Smoothing a hand-drawn curve (which this question might actually be a dupe of), which has an answer that proposes using Ramer-Douglas-Peucker and then applying curve fitting according to Philip J. Schneiders approach.

A quick adaptation of the provided sample code to my drawing methods results in the following curve:

enter image description here

The input data from the question has been reduced to 28 points (which are being drawn using Bezier splines).

I'm not sure which approach exactly Adobe is using, but this one serves me extremely well so far.

Adaptation

So, the code provided by Kris is written for WPF and makes some assumptions in that regard. To work for my case (and because I didn't want to adjust his code), I wrote the following snippet:

private List<Point> OptimizeCurve( List<Point> curve ) {
  const float tolerance = 1.5f;
  const double error    = 100.0;

  // Remember the first point in the series.
  Point startPoint = curve.First();
  // Simplify the input curve.
  List<Point> simplified = Douglas.DouglasPeuckerReduction( curve, tolerance ).ToList();
  // Create a new curve from the simplified one.
  List<System.Windows.Point> fitted = FitCurves.FitCurve( simplified.Select( p => new System.Windows.Point( p.X, p.Y ) ).ToArray(), error );
  // Convert the points back to our desired type.
  List<Point> fittedPoints = fitted.Select( p => new Point( (int)p.X, (int)p.Y ) ).ToList();
  // Add back our first point.
  fittedPoints.Insert( 0, startPoint );
  return fittedPoints;
}

The resulting list will be in the format Start Point, Control Point 1, Control Point 2, End Point.