Color wheel

From Rosetta Code
Revision as of 10:55, 8 May 2018 by PureFox (talk | contribs) (→‎{{header|Smart Basic}}: Corrected capitalization of language so it now links to the existing category.)
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.
Task

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

<lang AppleScript> choose color default color {0, 0, 0, 0} </lang>

GML

<lang 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);
   }

} </lang>


Perl

Translation of: Sidef

<lang perl>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');</lang>

Perl 6

Works with: Rakudo version 2016.08

<lang perl6>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 ) {

   for ^$w -> $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 ){ # inputs normalized 0-1

   my $c = $v * $s;
   my $x = $c * (1 - abs( (($h*6) % 2) - 1 ) );
   my $m = $v - $c;
   my ($r, $g, $b) = 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 }
   }
   ( $r, $g, $b ) = map { (($_+$m) * 255).Int }, $r, $g, $b;

}</lang>

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

Python

<lang python>from PIL import Image import colorsys import 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()</lang>

Run BASIC

<lang Runbasic>' ----------------------------------- ' color wheel ' ----------------------------------- global pi pi = 22 / 7 steps = 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 y next x render #g end

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 /2 end if

if y = 0 and (x <> 0) then r$ = "Y" if x > 0 then atan2 = 0 if x < 0 then atan2 = pi end 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 if end if end function</lang>

Sidef

Translation of: Perl 6

<lang ruby>require('Imager')

var (width, height) = (300, 300) var center = Complex(width/2 , height/2)

var img = %s|Imager|.new(

                     xsize => width,
                     ysize => height,
                    )

for y, x in (^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')</lang>

Smart BASIC

<lang smart basic>' Runs on iOS GET SCREEN SIZE sw,sh xmax=0.45*3/7*(sw+sh) x0=sw/2!y0=sh/2 twopi=2*3.1415926 GRAPHICS GRAPHICS CLEAR DIM triX(1000), triY(1000) triX(0)=x0 ! triY(0)=y0 steps=INT(1^2*360)+1 dAngle=twopi/steps dAngle2=dAngle/2 REFRESH OFF FOR 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+1

NEXT i REFRESH ON END

DEF pal(tint) tint=tint*360 h=(tint%360)/60 ! f=FRACT(h) ! z=1-f ! ic=FLOOR(h)+1 ON 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</lang> 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 <lang 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));

}</lang>

Output:

See this image

References