douglasPeucker function

List<MapEntry<DateTime, double>> douglasPeucker(
  1. List<MapEntry<DateTime, double>> points,
  2. int targetCount
)

Ramer-Douglas-Peucker algorithm implementation. Reduces number of points while preserving the overall shape.

Implementation

List<MapEntry<DateTime, double>> douglasPeucker(
  List<MapEntry<DateTime, double>> points,
  int targetCount,
) {
  if (points.length <= targetCount) return points;

  // Calculate appropriate epsilon (tolerance) based on data range.
  final values = points.map((e) => e.value).toList();
  final minVal = values.reduce((a, b) => a < b ? a : b);
  final maxVal = values.reduce((a, b) => a > b ? a : b);
  final range = maxVal - minVal;

  // Start with a small epsilon and increase until we reach target count.
  var epsilon = range * 0.01;
  var result = rdpRecursive(points, epsilon);

  // Adjust epsilon to get closer to target count.
  var iterations = 0;
  while (result.length > targetCount && iterations < 10) {
    epsilon *= 1.5;
    result = rdpRecursive(points, epsilon);
    iterations++;
  }

  // If still too many points, fall back to uniform sampling.

  if (result.length > targetCount) {
    final step = result.length / targetCount;
    final uniformSampled = <MapEntry<DateTime, double>>[];
    for (var i = 0; i < targetCount; i++) {
      final index = (i * step).round();
      if (index < result.length) {
        uniformSampled.add(result[index]);
      }
    }
    return uniformSampled;
  }

  return result;
}