|
import math |
|
from color import Color |
|
|
|
class ColorWheel: |
|
@property |
|
def base_color(self): |
|
return self._base_color |
|
|
|
@property |
|
def hue(self): |
|
return [ |
|
self.base_color, self.add_h(1.0 / 12), self.add_h(2.0 / 12), self.add_h(3.0 / 12), self.add_h(4.0 / 12), self.add_h(5.0 / 12), |
|
self.add_h(-6.0 / 12), self.add_h(-5.0 / 12), self.add_h(-4.0 / 12), self.add_h(-3.0 / 12), self.add_h(-2.0 / 12), self.add_h(-1.0 / 12) |
|
] |
|
|
|
@property |
|
def tone(self): |
|
return [self.add_white(-2.0 / 16), self.add_white(-1.0 / 16), self.base_color, self.add_white(1.0 / 16), self.add_white(2.0 / 16)] |
|
|
|
@property |
|
def tone15(self): |
|
return [self.add_white(-7.0 / 16), self.add_white(-6.0 / 16), self.add_white(-5.0 / 16), self.add_white(-4.0 / 16), self.add_white(-3.0 / 16), |
|
self.add_white(-2.0 / 16), self.add_white(-1.0 / 16), self.base_color, self.add_white(1.0 / 16), self.add_white(2.0 / 16), |
|
self.add_white(3.0 / 16), self.add_white(4.0 / 16), self.add_white(5.0 / 16), self.add_white(6.0 / 16), self.add_white(7.0 / 16)] |
|
|
|
@property |
|
def complementary_colors(self): |
|
return [self.base_color, self.add_h(0.5)] |
|
|
|
@property |
|
def triadic_colors(self): |
|
return [self.add_h(-4.0 / 12), self.base_color, self.add_h(4.0 / 12)] |
|
|
|
@property |
|
def split_complementary_colors(self): |
|
return [self.add_h(-5.0 / 12), self.base_color, self.add_h(5.0 / 12)] |
|
|
|
@property |
|
def analogous_colors(self): |
|
return [self.add_h(-2.0 / 12), self.add_h(-1.0 / 12), self.base_color, self.add_h(1.0 / 12), self.add_h(2.0 / 12)] |
|
|
|
def __init__(self, c): |
|
self._base_color = c |
|
self._r = c.r / 255.0 |
|
self._g = c.g / 255.0 |
|
self._b = c.b / 255.0 |
|
|
|
@staticmethod |
|
def from_hsv(h, s, v): |
|
r, g, b = ColorWheel.hsv_to_rgb(h, s, v) |
|
c = Color.from_rgb(round(r * 255), round(g * 255), round(b * 255)) |
|
return ColorWheel(c) |
|
|
|
def add_white(self, value): |
|
r, g, b = (self._r + value, self._g + value, self._b + value) |
|
r = min(max(r, 0.0), 1.0) |
|
g = min(max(g, 0.0), 1.0) |
|
b = min(max(b, 0.0), 1.0) |
|
return self._from_rgb(r, g, b) |
|
|
|
def add_h(self, value): |
|
h, s, v = ColorWheel.rgb_to_hsv(self._r, self._g, self._b) |
|
h = (h + value) % 1.0 |
|
if h < 0.0: |
|
h += 1.0 |
|
r, g, b = ColorWheel.hsv_to_rgb(h, s, v) |
|
return self._from_rgb(r, g, b) |
|
|
|
def add_s(self, value): |
|
h, s, v = ColorWheel.rgb_to_hsv(self._r, self._g, self._b) |
|
s += value |
|
s = min(max(s, 0.0), 1.0) |
|
r, g, b = ColorWheel.hsv_to_rgb(h, s, v) |
|
return self._from_rgb(r, g, b) |
|
|
|
def add_v(self, value): |
|
h, s, v = ColorWheel.rgb_to_hsv(self._r, self._g, self._b) |
|
v += value |
|
v = min(max(v, 0.0), 1.0) |
|
r, g, b = ColorWheel.hsv_to_rgb(h, s, v) |
|
return self._from_rgb(r, g, b) |
|
|
|
@staticmethod |
|
def rgb_to_hsv(r, g, b): |
|
if r < 0.0 or r > 1.0: |
|
raise ValueError() |
|
if g < 0.0 or g > 1.0: |
|
raise ValueError() |
|
if b < 0.0 or b > 1.0: |
|
raise ValueError() |
|
cmax = max(r, g, b) |
|
cmin = min(r, g, b) |
|
h = cmax - cmin |
|
if h > 0.0: |
|
if cmax == r: |
|
h = (g - b) / h |
|
if h < 0.0: |
|
h += 6.0 |
|
elif cmax == g: |
|
h = 2.0 + (b - r) / h |
|
else: |
|
h = 4.0 + (r - g) / h |
|
h /= 6.0 |
|
s = cmax - cmin |
|
if cmax != 0.0: |
|
s /= cmax |
|
v = cmax |
|
return h, s, v |
|
|
|
@staticmethod |
|
def hsv_to_rgb(h, s, v): |
|
if h < 0.0 or h > 1.0: |
|
raise ValueError() |
|
if s < 0.0 or s > 1.0: |
|
raise ValueError() |
|
if v < 0.0 or v > 1.0: |
|
raise ValueError() |
|
r = v |
|
g = v |
|
b = v |
|
if s > 0.0: |
|
h *= 6.0 |
|
i = math.floor(h) |
|
f = h - i |
|
if i == 1: |
|
r *= 1 - s * f |
|
b *= 1 - s |
|
elif i == 2: |
|
r *= 1 - s |
|
b *= 1 - s * (1 - f) |
|
elif i == 3: |
|
r *= 1 - s |
|
g *= 1 - s * f |
|
elif i == 4: |
|
r *= 1 - s * (1 - f) |
|
g *= 1 - s |
|
elif i == 5: |
|
g *= 1 - s |
|
b *= 1 - s * f |
|
else: |
|
g *= 1 - s * (1 - f) |
|
b *= 1 - s |
|
return r, g, b |
|
|
|
def _from_rgb(self, r, g, b): |
|
return Color.from_argb(self.base_color.a, round(r * 255), round(g * 255), round(b * 255)) |
|
|