summary refs log tree commit diff stats
path: root/palette.cpp
blob: 413575648fecfb6485d6d5632634bcda0a131fd5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include "palette.h"
#include <algorithm>

const std::vector<Magick::ColorRGB> palette::reds = {
  {"#ff4848"}, {"#ff7575"}, {"#ff8a8a"}, {"#ff9797"}, {"#ffa8a8"}, {"#ffbbbb"}
};

const std::vector<Magick::ColorRGB> palette::oranges = {
  {"#ffbf85"}, {"#ffcfa4"}, {"#ffbd82"}, {"#ffc48e"}
};

const std::vector<Magick::ColorRGB> palette::yellows = {
  {"#fdfda5"}, {"#eff0ac"}, {"#fef495"}
};

const std::vector<Magick::ColorRGB> palette::greens = {
  {"#c6fcb4"}, {"#d4ffa2"}, {"#93eeaa"}
};

const std::vector<Magick::ColorRGB> palette::blues = {
  {"#62d0ff"}, {"#62a9ff"}, {"#63e9fc"}, {"#7bcae1"}, {"#92fef9"}
};

const std::vector<Magick::ColorRGB> palette::purples = {
  {"#dfb0fe"}, {"#b0a7f1"}, {"#ff86ff"}, {"#ffacec"}, {"#ff86c2"}, {"#ea8dfe"}
};

palette::palette(std::vector<Magick::Color> foci)
{
  if (foci.size() < 1)
  {
    throw std::invalid_argument("Must have at least one focus");
  }

  if (foci.size() < 2)
  {
    // Degenerate scenario, but deal with it gracefully.
    foci.push_back(foci.front());
  }

  int sections = foci.size() - 1;
  double sectionSize = 256.0 / static_cast<double>(sections);
  for (int i=0; i<256; i++)
  {
    int section = std::floor(static_cast<double>(i) / sectionSize);
    double interpolation = (static_cast<double>(i) / sectionSize) - section;

    Magick::ColorHSL interpLeft = foci[section];
    Magick::ColorHSL interpRight = foci[section+1];

    double newHue;
    double diff = interpRight.hue() - interpLeft.hue();
    if (diff < 0)
    {
      std::swap(interpLeft, interpRight);
      
      diff = -diff;
      interpolation = 1 - interpolation;
    }
    
    if (diff > 0.5)
    {
      newHue = 1.0 + interpLeft.hue()
        * (interpolation * (interpRight.hue() - interpLeft.hue() - 1.0));
      
      if (newHue > 1.0)
      {
        newHue -= 1.0;
      }
    } else {
      newHue = interpLeft.hue() + interpolation * diff;
    }
    
    Magick::ColorHSL interpolated(
      newHue,
      ((1.0 - interpolation) * interpLeft.saturation())
        + (interpolation * interpRight.saturation()),
      ((1.0 - interpolation) * interpLeft.luminosity())
        + (interpolation * interpRight.luminosity()));

    gradient_.push_back(interpolated);
  }
}

palette palette::randomPalette(std::mt19937& rng)
{
  std::vector<Magick::Color> foci;
  foci.push_back(reds[
      std::uniform_int_distribution<int>(0, reds.size()-1)(rng)]);
  foci.push_back(oranges[
      std::uniform_int_distribution<int>(0, oranges.size()-1)(rng)]);
  foci.push_back(yellows[
      std::uniform_int_distribution<int>(0, yellows.size()-1)(rng)]);
  foci.push_back(greens[
      std::uniform_int_distribution<int>(0, greens.size()-1)(rng)]);
  foci.push_back(blues[
      std::uniform_int_distribution<int>(0, blues.size()-1)(rng)]);
  foci.push_back(purples[
      std::uniform_int_distribution<int>(0, purples.size()-1)(rng)]);

  std::shuffle(std::begin(foci), std::end(foci), rng);

  int origNum = foci.size();
  int numOfFoci = std::uniform_int_distribution<int>(4, origNum)(rng);
  for (int i=0; i<(origNum-numOfFoci); i++)
  {
    foci.pop_back();
  }

  foci.push_back(foci[0]);

  return palette(std::move(foci));
}

Magick::Color palette::getColor(double shade) const
{
  int index = std::min((int)floor(shade * 256.0), 255);
  return gradient_[index];
}