module: colors
colors is a module which contains class definitions for Color and Pixel as well as helper functions for converting colors between formats
I appologise to all british programmers who spell color as colour, but within the programming world we spell it color. This will be the cause of 90% of your bugs if you're not use to programming with the color spelling
class: Color
A data class representing a color
from colors import Color
@staticmethodColor(r: int, g: int, b: int) -> Color
initiate a color instance, values between 0 and 255 for R, G, and B
red = Color(255, 0, 0)
@staticmethodfrom_hex(s: str) -> Color
get a color from a string hex code
red = Color.from_hex("FF0000")
@staticmethodfrom_hsl(hue: float, sat: float, lig: float) -> Color
get a color from hsl format
red = Color.from_hsl(0, 1, 0.5)
@staticmethodrandom(saturation: float = 1, lightness: float = 0.6) -> Color
Generate a random color (generate random hue for hsl), saturation and lightness can be specified
my_random_color = Color.random()
my_dark_random_color = Color.random(lightness=0.2)
@staticmethoddifferent_from(color: Color) -> Color
Generate a random color which is different from the passed color maintaining the same hue and saturation
red = Color.red()
not_red = Color.different_from(red)
set_rgb(r: int, g: int, b: int)
set the red green blue values of the color, all bound between 0 and 255
light = tree.get_light(200)
light.set_rgb(255, 0, 0) # the light is now red
set_color(color: Color)
change the color to another color
light = tree.get_light(200)
light.set_color(Color.red()) # the light is now red
fade(n: float = 1.1)
fade the color slightly, greater values of n will fade quicker, whereas values less than 0 will brighten to a max of white
light = tree.get_light(200)
light.fade() # the light is now slightly darker
to_tuple() -> tuple[int, int, int]
Returns a tuple of the R, G, and B values between 0 and 255
light = tree.get_light(200)
light.set_color(Color.red()) # the light is now red
to_hex() -> string
Returns the hex value of the RGB color
red = Color.red()
print(red.to_hex()) # prints out "FF0000"
lerp(target: tuple[int, int, int], frames: int, override: boolean = False, fn: Callable[[float], float] = util.linear)
Linearly interpolate the color from its current color to the target color (a tuple of red green and blue 0 - 255) over the amount of frames. This was initially based on the lerp found in the Unity Game Engine. set override to true to force a reset of the interpolation, it will take the current value and start interpolation from there
Each successive call to lerp will step the color toward the target color. After frame amount of calls, it will be the target color. any change to the target or the frames between calls will restart the lerp from the current color, and interpolate to the new target over frames
you can pass in any interpolation function which maps a float (0 - 1) to another float (0 - 1). Util provides lots based on the css timing functions
1
2
3
4
5
6
7
8
my_color = Color.red() # (255, 0, 0)
my_color.lerp((0, 0, 0), 5) # (205, 0, 0)
my_color.lerp((0, 0, 0), 5) # (153, 0, 0)
my_color.lerp((0, 0, 0), 5) # (102, 0, 0)
my_color.lerp((0, 0, 0), 5) # (51, 0, 0)
my_color.lerp((0, 0, 0), 5) # (0, 0, 0)
# once reacing the target, lerp has no effect
my_color.lerp((0, 0, 0), 5) # (0, 0, 0)
typically apply lerp to each pixel once a frame in the main loop
1
2
3
4
5
6
7
8
9
10
11
def main(): # a little tracer program,
i = 0
while True:
# turn on each light in a row each frame
i = (i + 1) % tree.num_pixels
tree.get_light(i).set_color(Color.white())
# tell each pixel to go to interpolate to black
for pixel in tree.pixels:
pixel.lerp((0, 0, 0), 30)
tree.update()
and optionally you can provide a timing function to override the linear default
1
2
3
4
5
6
7
8
9
10
11
12
import util
def main(): # a little tracer program,
i = 0
while True:
# turn on each light in a row each frame
i = (i + 1) % tree.num_pixels
tree.get_light(i).set_color(Color.white())
# tell each pixel to go to interpolate to black
for pixel in tree.pixels:
pixel.lerp((0, 0, 0), 30, fn=util.ease_in_out_sine)
tree.update()
set_lerp(target: tuple[int, int, int], time: int, override: boolean = False, fn: Callable[[float], float] = util.linear)
this will reset the lerp and start interpolation to target from current value. sucessive calls will not change the target unless override is set to True. use with cont_lerp to have the same effect as lerp()
cont_lerp()
this will advance the linear interpolation one step
class: Pixel extends Color
the pixel class extends the Color class by adding 3D coordinates to a color. All the same methods and attributes exist on a pixel so they act the same way
coordintates are in the GIFT format so range between -1 and 1 on X and Y axis, and 0 and tree.height on the Z axis
x: float
the X coordinate of the pixel
1
2
3
4
5
6
# set one half of the tree to red the other to green
for pixel in tree.pixels:
if pixel.x > 0:
pixel.set_rgb(255, 0, 0)
else:
pixel.set_rgb(0, 255, 0)
y: float
the Y coordinate of the pixel
1
2
3
4
5
6
# set one half of the tree to red the other to green
for pixel in tree.pixels:
if pixel.y > 0:
pixel.set_rgb(255, 0, 0)
else:
pixel.set_rgb(0, 255, 0)
z: float
the Z coordinate of the pixel
1
2
3
4
5
6
# set one half of the tree to red the other to green
for pixel in tree.pixels:
if pixel.z > tree.height / 2:
pixel.set_rgb(255, 0, 0)
else:
pixel.set_rgb(0, 255, 0)
polar coordinates
polar coordinates can be used to locate a pixel with the height pixel.z
, angle from x+ pixel.a
, and distance from z axis pixel.d
its 3D position is defined
a: float
the polar angle in radians from the x axis going clockwise when looking downward on the tree
1
2
3
4
5
6
# set one half of the tree to red the other to green
for pixel in tree.pixels:
if pixel.a > math.pi:
pixel.set_rgb(255, 0, 0)
else:
pixel.set_rgb(0, 255, 0)
d: float
the polar distance from the Z axis (trunk)
1
2
3
4
5
6
# set an inner cylinder to red and outer to green, it is assumed the base radius is 1
for pixel in tree.pixels:
if pixel.d > 0.5:
pixel.set_rgb(255, 0, 0)
else:
pixel.set_rgb(0, 255, 0)
Utility Functions
just some helper function which might be useful
# import them like this
from colors import tuple2hex
int2tuple(c: int) -> tuple[int, int, int]
conver the 24bit encoded int to tuple of R, G, and B.
int bitmap encoded as GGGGGGGGRRRRRRRRBBBBBBBB
tuple2hex(t: tuple[int, int, int]) -> str
conver an RGB tuple to hex string
1
print(tuple2hex((0, 0, 0))) # prints "000000"
hex2tuple(h: str) -> tuple[int, int, int]
conver a hex string to an RGB tuple
1
print(hex2tuple("ffffff")) # prints "(255, 255, 255)"