augment method Null safety

List<ColorModel> augment(
  1. int newLength,
  2. {List<double>? stops,
  3. ColorSpace? colorSpace,
  4. bool invert = false}
)

Returns a new color palette derived from this one; containing the number of colors defined by newLength.

If colorSpace is null, the colors will be interpolated in the color space of the starting color within any pair of colors.

stops can be provided to map the positions of the colors in the palette within the abstract gradient the augmented palette is derived from. If provided, there must be as many stops as there are colors in the palette. (stops.length == length)

If invert is true and colorSpace is null, colors will be interpolated in the color space of the ending color within any pair of colors. invert has no effect if a colorSpace is provided.

Implementation

List<ColorModel> augment(
  int newLength, {
  List<double>? stops,
  ColorSpace? colorSpace,
  bool invert = false,
}) {
  assert(stops == null || stops.length == length);

  late List<ColorModel> baseColors;
  if (stops != null && !stops.isIncremental) {
    // If the [stops] aren't sorted incrementally, reorder the
    // colors and their respective stops to be in correct order.
    final newStops = <double>[stops.first];
    baseColors = <ColorModel>[first];
    for (var i = 1; i < length; i++) {
      for (var j = 0; j <= newStops.length; j++) {
        if (j == newStops.length || stops[i] < newStops[j]) {
          newStops.insert(j, stops[i]);
          baseColors.insert(j, elementAt(i));
          break;
        }
      }
    }
    stops = newStops;
  } else {
    baseColors = toList();
  }

  final colors = <ColorModel>[];
  final slice = 1 / (newLength - 1);

  if (stops == null) {
    final stopSlice = 1 / (length - 1);
    stops = List<double>.generate(length, (index) => index * stopSlice);
  }

  for (var i = 0; i < newLength; i++) {
    // Calculate the position of the color within the palette.
    final step = i * slice;

    // If the step is before the first stop, or after the last stop,
    // set the color to the first or last color in the palette.
    if (step <= stops.first) {
      var color = baseColors.first;
      if (colorSpace != null) color = colorSpace.from(color);
      colors.add(color);
      continue;
    }
    if (step >= stops.last) {
      var color = baseColors.last;
      if (colorSpace != null) color = colorSpace.from(color);
      colors.add(color);
      continue;
    }

    // If the position is equal to one of the stops, the color
    // at that stop should remain in the palette.
    if (stops.contains(step)) {
      colors.add(baseColors[stops.indexOf(step)]);
      continue;
    }

    // Otherwise, calculate the new color by interpolating
    // between the colors around its position.
    late ColorModel colorA, colorB;
    late double stopA, stopB;
    for (var j = 0; j < length - 1; j++) {
      if (step >= stops[j] && step < stops[j + 1]) {
        if (invert) {
          colorA = baseColors[j + 1];
          colorB = baseColors[j];
          stopA = stops[j + 1];
          stopB = stops[j];
        } else {
          colorA = baseColors[j];
          colorB = baseColors[j + 1];
          stopA = stops[j];
          stopB = stops[j + 1];
        }
        break;
      }
    }

    // If [colorSpace] is defined, convert both colors to that space.
    if (colorSpace != null) {
      colorA = colorSpace.from(colorA);
      colorB = colorSpace.from(colorB);
    }

    // Calculate the new color and add it to the list.
    final substep = (step - stopA) / (stopB - stopA);
    colors.add(colorA.interpolate(colorB, substep));
  }
  return colors;
}