analogous method

List<Hct> analogous({
  1. int count = 5,
  2. int divisions = 12,
})

A set of colors with differing hues, equidistant in temperature.

In art, this is usually described as a set of 5 colors on a color wheel divided into 12 sections. This method allows provision of either of those values.

Behavior is undefined when count or divisions is 0. When divisions < count, colors repeat.

count The number of colors to return, includes the input color. divisions The number of divisions on the color wheel.

Implementation

List<Hct> analogous({int count = 5, int divisions = 12}) {
  final startHue = input.hue.round();
  final startHct = hctsByHue[startHue];
  var lastTemp = relativeTemperature(startHct);
  List<Hct> allColors = [startHct];

  var absoluteTotalTempDelta = 0.0;
  for (int i = 0; i < 360; i++) {
    final hue = MathUtils.sanitizeDegreesInt(startHue + i);
    final hct = hctsByHue[hue];
    final temp = relativeTemperature(hct);
    final tempDelta = (temp - lastTemp).abs();
    lastTemp = temp;
    absoluteTotalTempDelta += tempDelta;
  }
  var hueAddend = 1;
  final tempStep = absoluteTotalTempDelta / divisions;
  var totalTempDelta = 0.0;
  lastTemp = relativeTemperature(startHct);
  while (allColors.length < divisions) {
    final hue = MathUtils.sanitizeDegreesInt(startHue + hueAddend);
    final hct = hctsByHue[hue];
    final temp = relativeTemperature(hct);
    final tempDelta = (temp - lastTemp).abs();
    totalTempDelta += tempDelta;

    final desiredTotalTempDeltaForIndex = allColors.length * tempStep;
    var indexSatisfied = totalTempDelta >= desiredTotalTempDeltaForIndex;
    var indexAddend = 1;
    // Keep adding this hue to the answers until its temperature is
    // insufficient. This ensures consistent behavior when there aren't
    // [divisions] discrete steps between 0 and 360 in hue with [tempStep]
    // delta in temperature between them.
    //
    // For example, white and black have no analogues: there are no other
    // colors at T100/T0. Therefore, they should just be added to the array
    // as answers.
    while (indexSatisfied && allColors.length < divisions) {
      allColors.add(hct);
      final desiredTotalTempDeltaForIndex =
          ((allColors.length + indexAddend) * tempStep);
      indexSatisfied = totalTempDelta >= desiredTotalTempDeltaForIndex;
      indexAddend++;
    }
    lastTemp = temp;
    hueAddend++;
    if (hueAddend > 360) {
      while (allColors.length < divisions) {
        allColors.add(hct);
      }
      break;
    }
  }

  final answers = <Hct>[input];

  // First, generate analogues from rotating counter-clockwise.
  final increaseHueCount = ((count - 1) / 2.0).floor();
  for (int i = 1; i < (increaseHueCount + 1); i++) {
    var index = 0 - i;
    while (index < 0) {
      index = allColors.length + index;
    }
    if (index >= allColors.length) {
      index = index % allColors.length;
    }
    answers.insert(0, allColors[index]);
  }

  // Second, generate analogues from rotating clockwise.
  final decreaseHueCount = count - increaseHueCount - 1;
  for (int i = 1; i < (decreaseHueCount + 1); i++) {
    var index = i;
    while (index < 0) {
      index = allColors.length + index;
    }
    if (index >= allColors.length) {
      index = index % allColors.length;
    }
    answers.add(allColors[index]);
  }

  return answers;
}