# Color wheel

Color wheel is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Write a function to draw a HSV color wheel[1] completely with code.

This is strictly for learning purposes only. It's highly recommended that you use an image in an actual application to actually draw the color wheel   (as procedurally drawing is super slow). This does help you understand how color wheels work and this can easily be used to determine a color value based on a position within a circle.

## AppleScript

` choose color default color {0, 0, 0, 0} `

## GML

` for (var i = 1; i <= 360; i++) {    for (var j = 0; j < 255; j++) {         var hue = 255*(i/360);        var saturation = j;        var value = 255;         var c = make_colour_hsv(hue,saturation,value);         //size of circle determined by how far from the center it is        //if you just draw them too small the circle won't be full.         //it will have patches inside it that didn't get filled in with color        var r = max(1,3*(j/255));         //Math for built-in GMS functions        //lengthdir_x(len,dir) = +cos(degtorad(direction))*length;        //lengthdir_y(len,dir) = -sin(degtorad(direction))*length;        draw_circle_colour(x+lengthdir_x(m_radius*(j/255),i),y+lengthdir_y(m_radius*(j/255),i),r,c,c,false);    }} `

## Go

Library: Go Graphics
Translation of: Kotlin
`package main import (    "github.com/fogleman/gg"    "math") const tau = 2 * math.Pi func hsb2rgb(hue, sat, bri float64) (r, g, b int) {    u := int(bri*255 + 0.5)    if sat == 0 {        r, g, b = u, u, u    } else {        h := (hue - math.Floor(hue)) * 6        f := h - math.Floor(h)        p := int(bri*(1-sat)*255 + 0.5)        q := int(bri*(1-sat*f)*255 + 0.5)        t := int(bri*(1-sat*(1-f))*255 + 0.5)        switch int(h) {        case 0:            r, g, b = u, t, p        case 1:            r, g, b = q, u, p        case 2:            r, g, b = p, u, t        case 3:            r, g, b = p, q, u        case 4:            r, g, b = t, p, u        case 5:            r, g, b = u, p, q        }    }    return} func colorWheel(dc *gg.Context) {    width, height := dc.Width(), dc.Height()    centerX, centerY := width/2, height/2    radius := centerX    if centerY < radius {        radius = centerY    }    for y := 0; y < height; y++ {        dy := float64(y - centerY)        for x := 0; x < width; x++ {            dx := float64(x - centerX)            dist := math.Sqrt(dx*dx + dy*dy)            if dist <= float64(radius) {                theta := math.Atan2(dy, dx)                hue := (theta + math.Pi) / tau                r, g, b := hsb2rgb(hue, 1, 1)                dc.SetRGB255(r, g, b)                dc.SetPixel(x, y)            }        }    }} func main() {    const width, height = 480, 480    dc := gg.NewContext(width, height)    dc.SetRGB(1, 1, 1) // set background color to white    dc.Clear()    colorWheel(dc)    dc.SavePNG("color_wheel.png")}`
Output:
```Image is same as Kotlin entry
```

## Kotlin

We reuse the class in the Bitmap task for this and add a member function to draw the color wheel. To give a more 'wheel-like' image, a constant 'saturation' of 1.0 has been used rather than one which varies in line with distance from the center.

`// Version 1.2.41 import java.awt.Colorimport java.awt.Graphicsimport java.awt.image.BufferedImageimport java.io.Fileimport javax.imageio.ImageIOimport kotlin.math.* class BasicBitmapStorage(width: Int, height: Int) {    val image = BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR)     fun fill(c: Color) {        val g = image.graphics        g.color = c        g.fillRect(0, 0, image.width, image.height)    }     fun setPixel(x: Int, y: Int, c: Color) = image.setRGB(x, y, c.getRGB())     fun getPixel(x: Int, y: Int) = Color(image.getRGB(x, y))     fun colorWheel() {        val centerX = image.width / 2        val centerY = image.height / 2        val radius = minOf(centerX, centerY)        for (y in 0 until image.height) {            val dy = (y - centerY).toDouble()            for (x in 0 until image.width) {                val dx = (x - centerX).toDouble()                val dist = sqrt(dx * dx + dy * dy)                if (dist <= radius) {                    val theta = atan2(dy, dx)                    val hue = (theta + PI) / (2.0 * PI)                    val rgb = Color.HSBtoRGB(hue.toFloat(), 1.0f, 1.0f)                    setPixel(x, y, Color(rgb))                }            }        }    }} fun main(args: Array<String>) {    val bbs = BasicBitmapStorage(480, 480)    with (bbs) {        fill(Color.white)        colorWheel()        val cwFile = File("Color_wheel.png")        ImageIO.write(image, "png", cwFile)    }} `
Output:
```Looks like mirror image of Smart BASIC entry
```

## M2000 Interpreter

` Module Check {      \\ we use an internal object for Math functions (here for Atan2)      Declare Math Math      Const tau=2*Pi, Center=2      \\ change console size,  and center it ( using ;) to current monitor            Window 12, 800*twipsX,600*twipsY;      \\ actual size maybe less (so can fit text exactly)      Double  ' Double height characters      Report Center, "Color wheel"      Normal  ' restore to normal      Atan2=Lambda Math (a, b) ->{            Method Math, "Atan2", a, b As ret            =ret      }      \\ brightness=1 for this program      hsb2rgb=Lambda (hue, sat) ->{            If sat == 0 Then {                = 255, 255, 255           } Else {                  h=frac(hue+1)*6                  f = frac(h)                    p = Int((1-sat)*255 + 0.5)                  q = Int((1-sat*f)*255 + 0.5)                  t = Int((1-sat*(1-f))*255 + 0.5)                  Select Case Int(h)                  Case 1                      = q, 255, p                  Case 2                      = p, 255, t                  Case 3                     = p, q, 255                  Case 4                      = t, p, 255                  Case 5                      = 255, p, q                  Else Case                      = 255, t, p                  End Select          }      }      Let OffsetX=X.twips/2-128*TwipsX, OffsetY=Y.twips/2-128*TwipsY      \\ a pixel has a size of TwipsX x TwipsY      OffsetX=(OffsetX div TwipsX)*TwipsX      OffsetY=(OffsetY div TwipsY)*TwipsY      \\ We set hsb2rgb, OffsetX, OffsetY as closures to PrintPixel      \\ We send to stack the R G B values using Stack ! array      \\ hsb2rgb() return an array of values      \\ we pop these values using Number      PrintPixel = Lambda  hsb2rgb, OffsetX, OffsetY (x,y, theta, sat)  -> {            Stack ! hsb2rgb(theta,sat)              PSet Color(number, number, number), x*TwipsX+offsetX, y*TwipsY+offsetY      }      \\ set Atan2, tau as closures to HueCircle      \\ we can rotate/flip the wheel by changing signs in Atan2() and      \\ by changing order of arguments (dx,dy) or (dy,dx). 8 combinations      HueCircle= Lambda Atan2, tau (PrintPixel) -> {            Let  c_width=256, c_height=256            Let  cx=c_width/2, cy=c_height/2            Let  radius=If(cx<=cy->cx, cy)            c_width--            c_height--            dy=-cy            For y=0 To c_height {                  dy++ : dy2=dy*dy : dx=-cx                  For x=0 To c_width {                        dx++ : dist=Sqrt(dx^2+dy2)                        If dist>radius Then continue                        Call PrintPixel(x,y, Atan2(dx, -dy)/tau, dist/radius)                  }            }      }      Call HueCircle(PrintPixel)      Scr\$=""  ' we use this string  to load an image      Move 0,0      \\ scale.x, scale.y are twips height and width, of current layer      Copy scale.x, scale.y to Scr\$      Clipboard Scr\$  ' save window to clipboard}Check `
Output:

see this image

## Perl

Translation of: Sidef
`use Imager;use Math::Complex qw(cplx i pi); my (\$width, \$height) = (300, 300);my \$center = cplx(\$width/2, \$height/2); my \$img = Imager->new(xsize => \$width,                      ysize => \$height); foreach my \$y (0 .. \$height - 1) {    foreach my \$x (0 .. \$width - 1) {         my \$vec = \$center - \$x - \$y * i;        my \$mag = 2 * abs(\$vec) / \$width;        my \$dir = (pi + atan2(\$vec->Re, \$vec->Im)) / (2 * pi);         \$img->setpixel(x => \$x, y => \$y,            color => {hsv => [360 * \$dir, \$mag, \$mag < 1 ? 1 : 0]});    }} \$img->write(file => 'color_wheel.png');`

## Perl 6

Works with: Rakudo version 2016.08
`use Image::PNG::Portable; my (\$w, \$h) = 300, 300; my \$out = Image::PNG::Portable.new: :width(\$w), :height(\$h); my \$center = \$w/2 + \$h/2*i; color-wheel(\$out); \$out.write: 'Color-wheel-perl6.png'; sub color-wheel ( \$png ) {    ^\$w .race.map: -> \$x {        for ^\$h -> \$y {            my \$vector    = \$center - \$x - \$y*i;            my \$magnitude = \$vector.abs * 2 / \$w;            my \$direction = ( π + atan2( |\$vector.reals ) ) / τ;            \$png.set: \$x, \$y, |hsv2rgb( \$direction, \$magnitude, \$magnitude < 1 );        }    }} sub hsv2rgb ( \$h, \$s, \$v ){    my \$c = \$v * \$s;    my \$x = \$c * (1 - abs( ((\$h*6) % 2) - 1 ) );    my \$m = \$v - \$c;    (do given \$h {        when   0..^1/6 { \$c, \$x, 0 }        when 1/6..^1/3 { \$x, \$c, 0 }        when 1/3..^1/2 { 0, \$c, \$x }        when 1/2..^2/3 { 0, \$x, \$c }        when 2/3..^5/6 { \$x, 0, \$c }        when 5/6..1    { \$c, 0, \$x }    } ).map: ((*+\$m) * 255).Int}`

Until local image uploading is re-enabled, see Color-wheel-perl6.png

## Phix

`-- demo\rosetta\Colour_wheel.exwinclude pGUI.e Ihandle dlg, canvascdCanvas cddbuffer, cdcanvas function hsv_to_rgb(atom h, s, v)    atom r,g,b    if s=0 then        {r,g,b} @= v    else        integer i = floor(h*6)        atom f = h*6-i,             p = v*(1-s),             q = v*(1-s*f),             t = v*(1-s*(1-f))        switch i do            case 0,                 6: {r,g,b} = {v, t, p}            case 1: {r,g,b} = {q, v, p}            case 2: {r,g,b} = {p, v, t}            case 3: {r,g,b} = {p, q, v}            case 4: {r,g,b} = {t, p, v}            case 5: {r,g,b} = {v, p, q}        end switch    end if    return cdEncodeColor(r*255, g*255, b*255)end function function redraw_cb(Ihandle /*ih*/, integer /*posx*/, integer /*posy*/)    integer {w, h} = IupGetIntInt(canvas, "DRAWSIZE")    cdCanvasActivate(cddbuffer)    integer radius = floor(min(w,h)/2)    integer cx = floor(w/2),            cy = floor(h/2)    for x=1 to w do        for y=1 to h do            integer rx = x - cx,                    ry = y - cy            atom s = sqrt(rx*rx+ry*ry) / radius            if s <= 1.0 then                atom hue = ((atan2(ry, rx) / PI) + 1.0) / 2.0                cdCanvasPixel(cddbuffer, x, h-y, hsv_to_rgb(hue, s, 1))             end if         end for    end for    cdCanvasFlush(cddbuffer)    return IUP_DEFAULTend function function map_cb(Ihandle ih)    cdcanvas = cdCreateCanvas(CD_IUP, ih)    cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)    cdCanvasSetBackground(cddbuffer, CD_WHITE)    cdCanvasSetForeground(cddbuffer, CD_MAGENTA)    return IUP_DEFAULTend function procedure main()    IupOpen()     canvas = IupCanvas(NULL)    IupSetAttribute(canvas, "RASTERSIZE", "400x400") -- initial size    IupSetCallback(canvas, "MAP_CB", Icallback("map_cb"))     dlg = IupDialog(canvas)    IupSetAttribute(dlg, "TITLE", "Colour wheel")    IupSetCallback(canvas, "ACTION", Icallback("redraw_cb"))    IupCloseOnEscape(dlg)     IupMap(dlg)    IupSetAttribute(canvas, "RASTERSIZE", NULL)    IupShowXY(dlg,IUP_CENTER,IUP_CENTER)    IupMainLoop()    IupClose()end procedure main()`

## Python

`from PIL import Imageimport colorsysimport math if __name__ == "__main__": 	im = Image.new("RGB", (300,300))	radius = min(im.size)/2.0	centre = im.size[0]/2, im.size[1]/2	pix = im.load() 	for x in range(im.width):		for y in range(im.height):			rx = x - centre[0]			ry = y - centre[1]			s = ((x - centre[0])**2.0 + (y - centre[1])**2.0)**0.5 / radius			if s <= 1.0:				h = ((math.atan2(ry, rx) / math.pi) + 1.0) / 2.0				rgb = colorsys.hsv_to_rgb(h, s, 1.0)				pix[x,y] = tuple([int(round(c*255.0)) for c in rgb]) 	im.show()`

## Run BASIC

`' -----------------------------------' color wheel' -----------------------------------global pipi	= 22 / 7steps	= 1 graphic #g, 525, 525  for x =0 to 525 step steps	for y =0 to 525 step steps		angle   = atan2(y - 250, x - 250) * 360 / 2 / pi      '  full degrees....		sector  = int(angle / 60)                             '    60 degree sectors (0 to 5)		slope   = (angle mod 60) /60 * 255                    '     1 degree sectors. 		if  sector = 0 then  col\$    = "255 ";                    str\$( int( slope));      "   0"		if  sector = 1 then  col\$    = str\$(int(256 - slope)); " 255                          0"		if  sector = 2 then  col\$    = "0                         255 ";                     str\$( int( slope))		if  sector = 3 then  col\$    = "0 ";                      str\$( int( 256 -slope)); " 255"		if  sector = 4 then  col\$    = str\$(int(slope));    "     0                        255"		if  sector = 5 then  col\$    = "255                         0 ";                     str\$( int( 256 -slope)) 		red	= val( word\$( col\$, 1))		grn	= val( word\$( col\$, 2))		blu	= val( word\$( col\$, 3))		p	= ((x -270)^2 +(y -270)^2)^0.5 / 250		r	= min(255,p * red)		g	= min(255,p * grn)		b	= min(255,p * blu)		if p > 1 then  #g "color white" else #g color(r,g,b)		#g "set "; x; " "; y	next ynext xrender #gend function atan2(y,x)if (x = 0) and (y <> 0) then	r\$ = "Y"	if y > 0 then atan2 = pi /2	if y < 0 then atan2 = 3 * pi /2end if if y = 0 and (x <> 0) then	r\$ = "Y"	if x > 0 then atan2 = 0	if x < 0 then atan2 = piend if If r\$ <> "Y" then	if x = 0 and y = 0 then		atan2	= 0		else		baseAngle = atn(abs(y) / abs(x))		if x > 0 then			if y > 0 then atan2 = baseAngle			If y < 0 then atan2 = 2 * pi - baseAngle		end if		if x < 0 then			If y > 0 then atan2 = pi - baseAngle			If y < 0 then atan2 = pi + baseAngle		end if	end ifend ifend function`

## Sidef

Translation of: Perl 6
`require('Imager') var (width, height) = (300, 300)var center = Complex(width/2 , height/2) var img = %O<Imager>.new(xsize => width, ysize => height) for y=(^height), x=(^width) {    var vector    = (center - x - y.i)    var magnitude = (vector.abs * 2 / width)    var direction = ((Num.pi + atan2(vector.real, vector.imag)) / Num.tau)    img.setpixel(x => x, y => y,        color => Hash(hsv => [360*direction, magnitude, magnitude < 1 ? 1 : 0])    )} img.write(file => 'color_wheel.png')`

Output image: Color wheel

## Smart BASIC

`' Runs on iOSGET SCREEN SIZE sw,shxmax=0.45*3/7*(sw+sh)x0=sw/2!y0=sh/2twopi=2*3.1415926GRAPHICSGRAPHICS CLEARDIM triX(1000), triY(1000)triX(0)=x0 ! triY(0)=y0steps=INT(1^2*360)+1dAngle=twopi/stepsdAngle2=dAngle/2REFRESH OFFFOR i=0 TO steps-1  pal(i/steps+TintOffset)  ANGLE=i*dAngle  FILL COLOR pal.r,pal.g,pal.b  DRAW COLOR pal.r,pal.g,pal.b  x=x0+(xmax-radius)*COS(ANGLE)  y=y0-(xmax-radius)*SIN(ANGLE)  k=0  FOR j=-dAngle2 TO dAngle2 STEP 0.02    k+=1    triX(k)=x0+xmax*COS(ANGLE+j)    triY(k)=y0-xmax*SIN(ANGLE+j)  NEXT j  k+=1  triX(k)=x0+xmax*COS(ANGLE+dAngle2)  triY(k)=y0-xmax*SIN(ANGLE+dAngle2)  DRAW POLY triX,triY COUNT k+1  FILL POLY triX,triY COUNT k+1NEXT iREFRESH ONEND DEF pal(tint)tint=tint*360h=(tint%360)/60 ! f=FRACT(h) ! z=1-f ! ic=FLOOR(h)+1ON ic GOTO s1,s2,s3,s4,s5,s6  s1: r=1 ! g=f ! b=0 ! GOTO done  s2: r=z ! g=1 ! b=0 ! GOTO done  s3: r=0 ! g=1 ! b=f ! GOTO done  s4: r=0 ! g=z ! b=1 ! GOTO done  s5: r=f ! g=0 ! b=1 ! GOTO done  s6: r=1 ! g=0 ! b=z ! done:END DEF`

View the output on Dropbox https://www.dropbox.com/s/g3l5rbywo34bnp6/IMG_4600.PNG?dl=0

## zkl

Uses Image Magick and the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl

`var w=300,h=300,out=PPM(w,h);colorWheel(out);out.writeJPGFile("colorWheel.zkl.jpg"); fcn colorWheel(ppm){   zero,R:=ppm.w/2, zero;   foreach x,y in (w,h){      v,hue:=(x - zero).toFloat().toPolar(y - zero);       if(v<=R){    // only render in the circle	 if((hue = hue.toDeg())<0) hue+=360;  // (-pi..pi] to [0..2pi)	 s:=v/R;  // scale saturation zero at center to 1 at edge	 ppm[x,y]=hsv2rgb(hue,1.0,s);      }   }} fcn hsv2rgb(hue,v,s){  //  0<=H<360, 0<=v(brightness)<=1, 0<=saturation<=1		       // --> 24 bit RGB each R,G,B in [0..255]   to24bit:=fcn(r,g,b,m){      r,g,b=((r+m)*255).toInt(),((g+m)*255).toInt(),((b+m)*255).toInt();      r*0x10000 + g*0x100 + b   };   c:=v*s;   x:=c*(1.0 - (hue.toFloat()/60%2 - 1).abs());   m:=v - c;   if     (0  <=hue< 60) return(to24bit(c,  x,  0.0,m));   else if(60 <=hue<120) return(to24bit(x,  c,  0.0,m));   else if(120<=hue<180) return(to24bit(0.0,c,  x,  m));   else if(180<=hue<240) return(to24bit(0.0,x,  c,  m));   else if(240<=hue<300) return(to24bit(x,  0.0,c,  m));   else			 return(to24bit(c,  0.0,x,  m));}`
Output:

See this image

1. [1]