Color wheel: Difference between revisions

From Rosetta Code
Content added Content deleted
Line 89: Line 89:


for x in range(im.width):
for x in range(im.width):
for y in range(im.width):
for y in range(im.height):
rx = x - centre[0]
rx = x - centre[0]
ry = y - centre[1]
ry = y - centre[1]

Revision as of 05:00, 18 December 2016

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.

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 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>

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>

zkl

Each point in a square is converted to polar coordinates, the angle is hue and the radius is saturation (which is scaled by the distance from the pole). If the radius/saturation is in the circle, render it.

Uses 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> Until local image uploading is re-enabled, see this image.

References