2022-01-15 01:31:24 +00:00
//////////////////////////////////////////////////////////////////////
// LibFile: color.scad
2022-04-22 06:34:15 +00:00
// HSV and HSL conversion, rainbow() module for coloring multiple objects.
2022-04-21 04:26:20 +00:00
// The recolor() and color_this() modules allow you to change the color
// of previously colored attachable objects.
2022-01-15 01:31:24 +00:00
// Includes:
// include <BOSL2/std.scad>
// FileGroup: Basic Modeling
2022-04-21 04:26:20 +00:00
// FileSummary: HSV and HSL conversion, color multiple objects, change color of objects
2022-01-15 01:31:24 +00:00
// FileFootnotes: STD=Included in std.scad
//////////////////////////////////////////////////////////////////////
2022-01-19 05:29:23 +00:00
use < builtins.scad >
2022-01-15 01:31:24 +00:00
// Section: Coloring Objects
2022-03-27 23:23:47 +00:00
// Module: recolor()
2023-03-26 00:49:32 +00:00
// Synopsis: Sets the color for attachable children and all their descendants.
// Topics: Attachments
// See Also: color_this(), hsl(), hsv()
2022-03-27 23:23:47 +00:00
// Usage:
2022-03-31 22:12:23 +00:00
// recolor([c]) CHILDREN;
2022-03-27 23:23:47 +00:00
// Description:
// Sets the color for attachable children and all their descendants. This only works with attachables and you cannot
// have any color() modules above it in any parents, only other recolor() or color_this() modules.
// This works by setting the special `$color` variable, which attachable objects make use of to set the color.
// Arguments:
// c = Color name or RGBA vector. Default: The default color in your color scheme.
// Example:
// cuboid([10,10,5])
// recolor("green")attach(TOP,BOT) cuboid([9,9,4.5])
// attach(TOP,BOT) cuboid([8,8,4])
// recolor("purple") attach(TOP,BOT) cuboid([7,7,3.5])
// attach(TOP,BOT) cuboid([6,6,3])
// recolor("cyan")attach(TOP,BOT) cuboid([5,5,2.5])
// attach(TOP,BOT) cuboid([4,4,2]);
module recolor ( c = "default" )
{
2022-03-31 00:08:15 +00:00
req_children ( $children ) ;
2022-03-27 23:23:47 +00:00
$ color = c ;
children ( ) ;
}
// Module: color_this()
2023-03-26 00:49:32 +00:00
// Synopsis: Sets the color for children at the current level only.
// Topics: Attachments
// See Also: recolor(), hsl(), hsv()
2022-03-27 23:23:47 +00:00
// Usage:
2022-03-31 22:12:23 +00:00
// color_this([c]) CHILDREN;
2022-03-27 23:23:47 +00:00
// Description:
// Sets the color for children at one level, reverting to the previous color for further descendants.
// This works only with attachables and you cannot have any color() modules above it in any parents,
// only recolor() or other color_this() modules. This works using the `$color` and `$save_color` variables,
// which attachable objects make use of to set the color.
// Arguments:
// c = Color name or RGBA vector. Default: the default color in your color scheme
// Example:
// cuboid([10,10,5])
// color_this("green")attach(TOP,BOT) cuboid([9,9,4.5])
// attach(TOP,BOT) cuboid([8,8,4])
// color_this("purple") attach(TOP,BOT) cuboid([7,7,3.5])
// attach(TOP,BOT) cuboid([6,6,3])
// color_this("cyan")attach(TOP,BOT) cuboid([5,5,2.5])
// attach(TOP,BOT) cuboid([4,4,2]);
module color_this ( c = "default" )
{
2022-03-31 00:08:15 +00:00
req_children ( $children ) ;
2022-03-27 23:23:47 +00:00
$ save_color = default ( $ color , "default" ) ;
$ color = c ;
children ( ) ;
}
2022-01-15 01:31:24 +00:00
// Module: rainbow()
2023-03-26 00:49:32 +00:00
// Synopsis: Iterates through a list, displaying children in different colors.
// Topics: List Handling
// See Also: hsl(), hsv()
2022-01-15 01:31:24 +00:00
// Usage:
2022-03-31 22:12:23 +00:00
// rainbow(list,[stride],[maxhues],[shuffle],[seed]) CHILDREN;
2022-01-15 01:31:24 +00:00
// Description:
2022-03-27 23:23:47 +00:00
// Iterates the list, displaying children in different colors for each list item. The color
// is set using the color() module, so this module is not compatible with {{recolor()}} or
2022-03-28 00:09:50 +00:00
// {{color_this()}}. This is useful for debugging regions or lists of paths.
2022-01-15 01:31:24 +00:00
// Arguments:
// list = The list of items to iterate through.
// stride = Consecutive colors stride around the color wheel divided into this many parts.
// maxhues = max number of hues to use (to prevent lots of indistinguishable hues)
// shuffle = if true then shuffle the hues in a random order. Default: false
// seed = seed to use for shuffle
// Side Effects:
// Sets the color to progressive values along the ROYGBIV spectrum for each item.
// Sets `$idx` to the index of the current item in `list` that we want to show.
// Sets `$item` to the current item in `list` that we want to show.
// Example(2D):
// rainbow(["Foo","Bar","Baz"]) fwd($idx*10) text(text=$item,size=8,halign="center",valign="center");
// Example(2D):
// rgn = [circle(d=45,$fn=3), circle(d=75,$fn=4), circle(d=50)];
// rainbow(rgn) stroke($item, closed=true);
module rainbow ( list , stride = 1 , maxhues , shuffle = false , seed )
{
2022-03-31 00:08:15 +00:00
req_children ( $children ) ;
2022-01-15 01:31:24 +00:00
ll = len ( list ) ;
maxhues = first_defined ( [ maxhues , ll ] ) ;
huestep = 360 / maxhues ;
huelist = [ for ( i = [ 0 : 1 : ll - 1 ] ) posmod ( i * huestep + i * 360 / stride , 360 ) ] ;
hues = shuffle ? shuffle ( huelist , seed = seed ) : huelist ;
for ( $ idx = idx ( list ) ) {
$ item = list [ $ idx ] ;
2022-03-28 03:06:42 +00:00
hsv ( h = hues [ $ idx ] ) children ( ) ;
2022-01-15 01:31:24 +00:00
}
}
// Section: Colorspace Conversion
2022-03-28 03:06:42 +00:00
// Function&Module: hsl()
2023-03-26 00:49:32 +00:00
// Synopsis: Sets the color of children to a specified hue, saturation, lightness and optional alpha channel value.
// See Also: hsv(), recolor(), color_this()
2022-01-15 01:31:24 +00:00
// Usage:
2022-03-31 22:12:23 +00:00
// hsl(h,[s],[l],[a]) CHILDREN;
2022-03-28 03:06:42 +00:00
// rgb = hsl(h,[s],[l],[a]);
2022-01-15 01:31:24 +00:00
// Description:
2022-03-27 23:23:47 +00:00
// When called as a function, returns the [R,G,B] color for the given hue `h`, saturation `s`, and lightness `l` from the HSL colorspace. If you supply
// the `a` value then you'll get a length 4 list [R,G,B,A].
// When called as a module, sets the color using the color() module to the given hue `h`, saturation `s`, and lightness `l` from the HSL colorspace.
2022-01-15 01:31:24 +00:00
// Arguments:
// h = The hue, given as a value between 0 and 360. 0=red, 60=yellow, 120=green, 180=cyan, 240=blue, 300=magenta.
// s = The saturation, given as a value between 0 and 1. 0 = grayscale, 1 = vivid colors. Default: 1
// l = The lightness, between 0 and 1. 0 = black, 0.5 = bright colors, 1 = white. Default: 0.5
2022-03-27 23:23:47 +00:00
// a = Specifies the alpha channel as a value between 0 and 1. 0 = fully transparent, 1=opaque. Default: 1
2022-01-15 01:31:24 +00:00
// Example:
2022-03-28 03:06:42 +00:00
// hsl(h=120,s=1,l=0.5) sphere(d=60);
2022-01-15 01:31:24 +00:00
// Example:
2022-03-28 03:06:42 +00:00
// rgb = hsl(h=270,s=0.75,l=0.6);
2022-01-15 01:31:24 +00:00
// color(rgb) cube(60, center=true);
2022-03-28 03:06:42 +00:00
function hsl ( h , s = 1 , l = 0.5 , a ) =
2022-01-15 01:31:24 +00:00
let (
h = posmod ( h , 360 )
) [
2022-03-27 23:23:47 +00:00
for ( n = [ 0 , 8 , 4 ] )
let ( k = ( n + h / 30 ) % 12 )
l - s * min ( l , 1 - l ) * max ( min ( k - 3 , 9 - k , 1 ) , - 1 ) ,
if ( is_def ( a ) ) a
2022-01-15 01:31:24 +00:00
] ;
2022-03-31 00:08:15 +00:00
module hsl ( h , s = 1 , l = 0.5 , a = 1 )
{
req_children ( $children ) ;
color ( hsl ( h , s , l ) , a ) children ( ) ;
}
2022-01-15 01:31:24 +00:00
2022-03-28 03:06:42 +00:00
// Function&Module: hsv()
2023-03-26 00:49:32 +00:00
// Synopsis: Sets the color of children to a hue, saturation, value and optional alpha channel value.
// See Also: hsl(), recolor(), color_this()
2022-01-15 01:31:24 +00:00
// Usage:
2022-03-31 22:12:23 +00:00
// hsv(h,[s],[v],[a]) CHILDREN;
2022-03-28 03:06:42 +00:00
// rgb = hsv(h,[s],[v],[a]);
2022-01-15 01:31:24 +00:00
// Description:
2022-03-27 23:23:47 +00:00
// When called as a function, returns the [R,G,B] color for the given hue `h`, saturation `s`, and value `v` from the HSV colorspace. If you supply
// the `a` value then you'll get a length 4 list [R,G,B,A].
// When called as a module, sets the color using the color() module to the given hue `h`, saturation `s`, and value `v` from the HSV colorspace.
2022-01-15 01:31:24 +00:00
// Arguments:
// h = The hue, given as a value between 0 and 360. 0=red, 60=yellow, 120=green, 180=cyan, 240=blue, 300=magenta.
// s = The saturation, given as a value between 0 and 1. 0 = grayscale, 1 = vivid colors. Default: 1
// v = The value, between 0 and 1. 0 = darkest black, 1 = bright. Default: 1
2022-03-27 23:23:47 +00:00
// a = Specifies the alpha channel as a value between 0 and 1. 0 = fully transparent, 1=opaque. Default: 1
2022-01-15 01:31:24 +00:00
// Example:
2022-03-28 03:06:42 +00:00
// hsv(h=120,s=1,v=1) sphere(d=60);
2022-01-15 01:31:24 +00:00
// Example:
2022-03-28 03:06:42 +00:00
// rgb = hsv(h=270,s=0.75,v=0.9);
2022-01-15 01:31:24 +00:00
// color(rgb) cube(60, center=true);
2022-03-28 03:06:42 +00:00
function hsv ( h , s = 1 , v = 1 , a ) =
2022-01-15 01:31:24 +00:00
assert ( s >= 0 && s < = 1 )
assert ( v >= 0 && v < = 1 )
2022-03-27 23:23:47 +00:00
assert ( is_undef ( a ) || a >= 0 && a < = 1 )
2022-01-15 01:31:24 +00:00
let (
h = posmod ( h , 360 ) ,
c = v * s ,
hprime = h / 60 ,
x = c * ( 1 - abs ( hprime % 2 - 1 ) ) ,
rgbprime = hprime < = 1 ? [ c , x , 0 ]
: hprime < = 2 ? [ x , c , 0 ]
: hprime < = 3 ? [ 0 , c , x ]
: hprime < = 4 ? [ 0 , x , c ]
: hprime < = 5 ? [ x , 0 , c ]
: hprime < = 6 ? [ c , 0 , x ]
: [ 0 , 0 , 0 ] ,
m = v - c
)
2022-03-27 23:23:47 +00:00
is_def ( a ) ? point4d ( add_scalar ( rgbprime , m ) , a )
: add_scalar ( rgbprime , m ) ;
2022-01-15 01:31:24 +00:00
2022-03-31 00:08:15 +00:00
module hsv ( h , s = 1 , v = 1 , a = 1 )
{
req_children ( $children ) ;
color ( hsv ( h , s , v ) , a ) children ( ) ;
}
2022-01-15 01:31:24 +00:00
2022-01-19 05:29:23 +00:00
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap