Color wheel: Difference between revisions
Line 909: | Line 909: | ||
<lang ring> |
<lang ring> |
||
#===================================================================# |
#===================================================================# |
||
# |
# Sample: Color Wheel |
||
# |
# Author: Gal Zsolt, Bert Mariani, Ilir Liburn & Mahmoud Fayed |
||
#===================================================================# |
#===================================================================# |
||
load "guilib.ring" |
load "guilib.ring" |
||
⚫ | |||
paint = null |
|||
⚫ | |||
⚫ | |||
⚫ | |||
MyApp = new qapp |
|||
{ |
{ |
||
win1 = new qwidget() |
|||
{ setwindowtitle("ColorWheel-FastDraw") |
|||
{ |
|||
⚫ | |||
setWindowTitle("Color wheel") |
|||
⚫ | |||
Canvas = new qlabel(win1) |
|||
{ ### daVinci paints the MonaLisa on the Canvas |
|||
{ |
|||
MonaLisa = new qPixMap2( xWidth, yHeight) |
|||
color = new qcolor(){ setrgb(255,255,255,0) } |
|||
MonaLisa = new QPixMap2( xWidth, yHeight) |
|||
pen = new qpen() { setwidth(1) } |
|||
MonaLisa.fill(color) |
|||
daVinci = new qpainter() |
|||
{ |
|||
{ begin(MonaLisa) |
|||
#endpaint() ### This will Stop the Painting. For Animation comment it out |
|||
} |
|||
} |
|||
⚫ | |||
} |
|||
⚫ | |||
⚫ | |||
} |
|||
colorWheel() |
|||
⚫ | |||
⚫ | |||
} |
|||
ColorWheel() |
|||
⚫ | |||
} |
} |
||
//===================== |
|||
Func colorWheel |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
pi = 3.14159265359 |
|||
diameter = pi * 2 |
|||
radius = yHeight / 2 |
|||
v = 1 // value/brightness 1 to 100 1=bright 0=dark |
|||
⚫ | |||
iradius = i - radius |
|||
p = pow( iradius, 2) |
|||
for j = 1 to yHeight |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
h = (atan2( iradius, j-radius ) + pi ) / diameter // hue/color 1 to 360 |
|||
⚫ | |||
⚫ | |||
pi = 3.14 |
|||
radius = 150 |
|||
⚫ | |||
⚫ | |||
⚫ | |||
p = pow(i-radius,2) |
|||
ok |
|||
h = (atan2(i-radius,j-radius)+pi)/(2*pi) |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
ok |
|||
⚫ | |||
⚫ | |||
#=====================================================================# |
|||
? "Start drawing..." |
|||
t2 = clock() |
|||
? "Clock : " + t2 |
|||
#=====================================================================# |
|||
daVinci.drawHSVFList(aList) |
|||
Canvas.setPixMap(MonaLisa) |
|||
#=====================================================================# |
|||
? "Done..." |
|||
t3 = clock() |
|||
? "Clock : " + t3 |
|||
#=====================================================================# |
|||
? "Processing Time: " + ( (t2-t1)/ClocksPerSecond() ) + " seconds " |
|||
? "Drawing Time: " + ( (t3-t2)/ClocksPerSecond() ) + " seconds " |
|||
? "Total Time: " + ( (t3-t1)/ClocksPerSecond() ) + " seconds " |
|||
#=====================================================================# |
|||
return |
|||
//================== |
|||
</lang> |
</lang> |
||
Revision as of 12:41, 17 September 2021
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
Write a function to draw a HSV color wheel 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>
C++
This program draws an HSV color wheel in a window. <lang cpp>// colorwheelwidget.cpp
- include "colorwheelwidget.h"
- include <QPainter>
- include <QPaintEvent>
- include <cmath>
namespace {
QColor hsvToRgb(int h, double s, double v) {
double hp = h/60.0; double c = s * v; double x = c * (1 - std::abs(std::fmod(hp, 2) - 1)); double m = v - c; double r = 0, g = 0, b = 0; if (hp <= 1) { r = c; g = x; } else if (hp <= 2) { r = x; g = c; } else if (hp <= 3) { g = c; b = x; } else if (hp <= 4) { g = x; b = c; } else if (hp <= 5) { r = x; b = c; } else { r = c; b = x; } r += m; g += m; b += m; return QColor(r * 255, g * 255, b * 255);
}
}
ColorWheelWidget::ColorWheelWidget(QWidget *parent)
: QWidget(parent) { setWindowTitle(tr("Color Wheel")); resize(400, 400);
}
void ColorWheelWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); const QColor backgroundColor(0, 0, 0); const QColor white(255, 255, 255); painter.fillRect(event->rect(), backgroundColor); const int margin = 10; const double diameter = std::min(width(), height()) - 2*margin; QPointF center(width()/2.0, height()/2.0); QRectF rect(center.x() - diameter/2.0, center.y() - diameter/2.0, diameter, diameter); for (int angle = 0; angle < 360; ++angle) { QColor color(hsvToRgb(angle, 1.0, 1.0)); QRadialGradient gradient(center, diameter/2.0); gradient.setColorAt(0, white); gradient.setColorAt(1, color); QBrush brush(gradient); QPen pen(brush, 1.0); painter.setPen(pen); painter.setBrush(brush); painter.drawPie(rect, angle * 16, 16); }
}</lang>
<lang cpp>// colorwheelwidget.h
- ifndef COLORWHEELWIDGET_H
- define COLORWHEELWIDGET_H
- include <QWidget>
class ColorWheelWidget : public QWidget {
Q_OBJECT
public:
ColorWheelWidget(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent *event) override;
};
- endif // COLORWHEELWIDGET_H</lang>
<lang cpp>// main.cpp
- include "colorwheelwidget.h"
- include <QApplication>
int main(int argc, char *argv[]) {
QApplication app(argc, argv); ColorWheelWidget widget; widget.show(); return app.exec();
}</lang>
- Output:
Screenshot: colorwheel.png (offsite PNG image)
Delphi
<lang Delphi> program Color_wheel;
{$APPTYPE CONSOLE}
uses
Winapi.Windows, System.SysUtils, Vcl.Graphics, System.Math, Vcl.Imaging.pngimage;
const
TAU = 2 * PI;
function HSBtoColor(hue, sat, bri: Double): TColor; var
f, h: Double; u, p, q, t: Byte;
begin
u := Trunc(bri * 255 + 0.5); if sat = 0 then Exit(rgb(u, u, u));
h := (hue - Floor(hue)) * 6; f := h - Floor(h); p := Trunc(bri * (1 - sat) * 255 + 0.5); q := Trunc(bri * (1 - sat * f) * 255 + 0.5); t := Trunc(bri * (1 - sat * (1 - f)) * 255 + 0.5);
case Trunc(h) of 0: result := rgb(u, t, p); 1: result := rgb(q, u, p); 2: result := rgb(p, u, t); 3: result := rgb(p, q, u); 4: result := rgb(t, p, u); 5: result := rgb(u, p, q); else result := clwhite; end;
end;
function ColorWheel(Width, Height: Integer): TPngImage; var
Center: TPoint; Radius: Integer; x, y: Integer; Hue, dy, dx, dist, theta: Double; Bmp: TBitmap;
begin
Bmp := TBitmap.Create; Bmp.SetSize(Width, Height); with Bmp.Canvas do begin Brush.Color := clWhite; FillRect(ClipRect); Center := ClipRect.CenterPoint; Radius := Center.X; if Center.Y < Radius then Radius := Center.Y; for y := 0 to Height - 1 do begin dy := y - Center.y; for x := 0 to Width - 1 do begin dx := x - Center.x; dist := Sqrt(Sqr(dx) + Sqr(dy)); if dist <= Radius then begin theta := ArcTan2(dy, dx); Hue := (theta + PI) / TAU; Pixels[x, y] := HSBtoColor(Hue, 1, 1); end; end; end; end;
Result := TPngImage.Create; Result.Assign(Bmp); Bmp.Free;
end;
begin
with ColorWheel(500, 500) do begin SaveToFile('ColorWheel.png'); Free; end;
end.</lang>
- Output:
Png Image [1].
Fōrmulæ
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.
Programs in Fōrmulæ are created/edited online in its website, However they run on execution servers. By default remote servers are used, but they are limited in memory and processing power, since they are intended for demonstration and casual use. A local server can be downloaded and installed, it has no limitations (it runs in your own computer). Because of that, example programs can be fully visualized and edited, but some of them will not run if they require a moderate or heavy computation/memory resources, and no local server is being used.
In this page you can see the program(s) related to this task and their results.
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>
Go
<lang go>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")
}</lang>
- Output:
Image is same as Kotlin entry
Java
This program draws a color wheel in a window. <lang java>import java.awt.*; import javax.swing.*;
public class ColorWheel {
public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { ColorWheelFrame frame = new ColorWheelFrame(); frame.setVisible(true); } }); }
private static class ColorWheelFrame extends JFrame { private ColorWheelFrame() { super("Color Wheel"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); getContentPane().add(new ColorWheelPanel()); pack(); } }
private static class ColorWheelPanel extends JComponent { private ColorWheelPanel() { setPreferredSize(new Dimension(400, 400)); } public void paint(Graphics g) { Graphics2D g2 = (Graphics2D)g; int w = getWidth(); int h = getHeight(); int margin = 10; int radius = (Math.min(w, h) - 2 * margin)/2; int cx = w/2; int cy = h/2; float[] dist = {0.F, 1.0F}; g2.setColor(Color.BLACK); g2.fillRect(0, 0, w, h); for (int angle = 0; angle < 360; ++angle) { Color color = hsvToRgb(angle, 1.0, 1.0); Color[] colors = {Color.WHITE, color}; RadialGradientPaint paint = new RadialGradientPaint(cx, cy, radius, dist, colors); g2.setPaint(paint); g2.fillArc(cx - radius, cy - radius, radius*2, radius*2, angle, 1); } } }
private static Color hsvToRgb(int h, double s, double v) { double hp = h/60.0; double c = s * v; double x = c * (1 - Math.abs(hp % 2.0 - 1)); double m = v - c; double r = 0, g = 0, b = 0; if (hp <= 1) { r = c; g = x; } else if (hp <= 2) { r = x; g = c; } else if (hp <= 3) { g = c; b = x; } else if (hp <= 4) { g = x; b = c; } else if (hp <= 5) { r = x; b = c; } else { r = c; b = x; } r += m; g += m; b += m; return new Color((int)(r * 255), (int)(g * 255), (int)(b * 255)); }
}</lang>
- Output:
Screenshot: color_wheel_java.png (offsite PNG image)
Julia
<lang julia>using Gtk, Graphics, Colors
const win = GtkWindow("Color Wheel", 450, 450) |> (const can = @GtkCanvas()) set_gtk_property!(can, :expand, true)
@guarded draw(can) do widget
ctx = getgc(can) h = height(can) w = width(can) center = (x = w / 2, y = h / 2) anglestep = 1/w for θ in 0:0.1:360 rgb = RGB(HSV(θ, 1, 1)) set_source_rgb(ctx, rgb.r, rgb.g, rgb.b) line_to(ctx, center...) arc(ctx, center.x, center.y, w/2.2, 2π * θ / 360, anglestep) line_to(ctx, center...) stroke(ctx) end
end
show(can) const condition = Condition() endit(w) = notify(condition) signal_connect(endit, win, :destroy) wait(condition) </lang>
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. <lang scala>// Version 1.2.41
import java.awt.Color import java.awt.Graphics import java.awt.image.BufferedImage import java.io.File import javax.imageio.ImageIO import 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) }
} </lang>
- Output:
Looks like mirror image of Smart BASIC entry
M2000 Interpreter
<lang 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 </lang>
- Output:
see this image
Mathematica/Wolfram Language
<lang Mathematica>r = 100; Image[Table[
If[x^2 + y^2 <= r^2, angle = Mod[ArcTan[N@x, y]/(2 Pi), 1]; List @@ RGBColor[Hue[angle, Sqrt[x^2 + y^2]/N[r], 1.0]] , {1, 1, 1} ], {x, -r, r}, {y, -r, r}] ]</lang>
- Output:
Outputs an image.
Nim
As Rust code does, we store the color wheel in a PNG image.
<lang Nim>import math
import imageman
- ---------------------------------------------------------------------------------------------------
func hsvToRgb(h, s, v: float): ColorRGBU =
## Convert HSV values to RGB values.
let hp = h / 60 let c = s * v let x = c * (1 - abs(hp mod 2 - 1)) let m = v - c var r, g, b = 0.0 if hp <= 1: r = c g = x elif hp <= 2: r = x g = c elif hp <= 3: g = c b = x elif hp <= 4: g = x b= c elif hp <= 5: r = x b = c else: r = c b = x r += m g += m b += m result = ColorRGBU [byte(r * 255), byte(g * 255), byte(b * 255)]
- ---------------------------------------------------------------------------------------------------
func buildColorWheel(image: var Image) =
## Build a color wheel into the image.
const Margin = 10 let diameter = min(image.w, image.h) - 2 * Margin let xOffset = (image.w - diameter) div 2 let yOffset = (image.h - diameter) div 2 let radius = diameter / 2
for x in 0..diameter: let rx = x.toFloat - radius for y in 0..diameter: let ry = y.toFloat - radius let r = hypot(rx, ry) / radius if r > 1: continue let a = 180 + arctan2(ry, -rx).radToDeg() image[x + xOffset, y + yOffset] = hsvToRgb(a, r, 1)
- ———————————————————————————————————————————————————————————————————————————————————————————————————
const
Side = 400 Output = "color_wheel.png"
var image = initImage[ColorRGBU](Side, Side) image.buildColorWheel()
image.savePNG(Output, compression = 9)</lang>
Perl
<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>
Phix
You can run this online here.
-- -- demo\rosetta\Colour_wheel.exw -- ============================= -- -- Note: Made non-resizeable since maximising this is far too slow. -- with javascript_semantics include pGUI.e constant title = "Colour wheel" Ihandle dlg, canvas cdCanvas cddbuffer, cdcanvas function redraw_cb(Ihandle /*ih*/, integer /*posx*/, /*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_DEFAULT end 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_DEFAULT end function procedure main() IupOpen() canvas = IupCanvas(NULL) IupSetAttribute(canvas, "RASTERSIZE", "300x300") IupSetCallback(canvas, "MAP_CB", Icallback("map_cb")) dlg = IupDialog(canvas,`TITLE="%s",RESIZE=NO`,{title}) IupSetCallback(canvas, "ACTION", Icallback("redraw_cb")) IupShowXY(dlg,IUP_CENTER,IUP_CENTER) if platform()!=JS then IupMainLoop() IupClose() end if end procedure main()
Processing
<lang java>size(300, 300); background(0); float radius = min(width, height) / 2.0; float cx = width / 2; float cy = width / 2; for (int x = 0; x < width; x++) {
for (int y = 0; y < width; y++) { float rx = x - cx; float ry = y - cy; float s = sqrt(sq(rx) + sq(ry)) / radius; if (s <= 1.0) { float h = ((atan2(ry, rx) / PI) + 1.0) / 2.0; colorMode(HSB); color c = color(int(h * 255), int(s * 255), 255); set(x, y, c); } }
}</lang>
Processing Python mode
<lang python>size(300, 300) background(0) radius = min(width, height) / 2.0 cx, cy = width / 2, width / 2 for x in range(width):
for y in range(height): rx = x - cx ry = y - cy s = sqrt(rx ** 2 + ry ** 2) / radius if s <= 1.0: h = ((atan2(ry, rx) / PI) + 1.0) / 2.0 colorMode(HSB) c = color(int(h * 255), int(s * 255), 255) set(x, y, c) # note set() used as Processing set() not as Python set()</lang>
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 cx, cy = 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 - cx ry = y - cy s = (rx ** 2.0 + ry ** 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>
Racket
With the colors package
<lang racket>#lang racket
(require racket/draw
colors)
(define DIM 500) (define target (make-bitmap DIM DIM)) (define dc (new bitmap-dc% [bitmap target])) (define radius 200) (define center (/ DIM 2))
(define (atan2 y x) (if (= 0 y x) 0 (atan y x)))
(for* ([x (in-range DIM)]
[y (in-range DIM)] [rx (in-value (- x center))] [ry (in-value (- y center))] [s (in-value (/ (sqrt (+ (sqr rx) (sqr ry))) radius))] #:when (<= s 1)) (define h (* 0.5 (+ 1 (/ (atan2 ry rx) pi)))) (send dc set-pen (hsv->color (hsv (if (= 1 h) 0 h) s 1)) 1 'solid) (send dc draw-point x y))
target</lang>
Raku
(formerly Perl 6)
<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 ) {
^$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
}</lang>
Until local image uploading is re-enabled, see Color-wheel-perl6.png
Ring
<lang ring>
- ===================================================================#
- Sample: Color Wheel
- Author: Gal Zsolt, Bert Mariani, Ilir Liburn & Mahmoud Fayed
- ===================================================================#
load "guilib.ring"
xWidth = 400 yHeight = 400
MyApp = new qapp {
win1 = new qwidget() { setwindowtitle("ColorWheel-FastDraw") setgeometry(500,150,xWidth,yHeight) Canvas = new qlabel(win1) { ### daVinci paints the MonaLisa on the Canvas MonaLisa = new qPixMap2( xWidth, yHeight) color = new qcolor(){ setrgb(255,255,255,0) } pen = new qpen() { setwidth(1) } MonaLisa.fill(color)
daVinci = new qpainter() { begin(MonaLisa) #endpaint() ### This will Stop the Painting. For Animation comment it out } setPixMap(MonaLisa) } show() } ColorWheel() exec()
}
//=====================
Func colorWheel
#=====================================================================# ? "Start Processing..." t1 = clock() ? "Clock : " + t1 #=====================================================================#
aList = [] pi = 3.14159265359 diameter = pi * 2 radius = yHeight / 2 v = 1 // value/brightness 1 to 100 1=bright 0=dark
for i = 1 to xWidth iradius = i - radius p = pow( iradius, 2)
for j = 1 to yHeight
h = (atan2( iradius, j-radius ) + pi ) / diameter // hue/color 1 to 360 s = sqrt( p + pow( j-radius, 2)) / radius // saturation/intensity 1 to 100 if s <= 1 and h <= 1 aList + [i,j,h,s,v,1] ok next next
#=====================================================================# ? "Start drawing..." t2 = clock() ? "Clock : " + t2 #=====================================================================#
daVinci.drawHSVFList(aList) Canvas.setPixMap(MonaLisa)
#=====================================================================# ? "Done..." t3 = clock() ? "Clock : " + t3 #=====================================================================# ? "Processing Time: " + ( (t2-t1)/ClocksPerSecond() ) + " seconds " ? "Drawing Time: " + ( (t3-t2)/ClocksPerSecond() ) + " seconds " ? "Total Time: " + ( (t3-t1)/ClocksPerSecond() ) + " seconds " #=====================================================================# return
//================== </lang>
Ruby
<lang ruby> def settings
size(300, 300)
end
def setup
sketch_title 'Color Wheel' background(0) radius = width / 2.0 center = width / 2 grid(width, height) do |x, y| rx = x - center ry = y - center sat = Math.hypot(rx, ry) / radius if sat <= 1.0 hue = ((Math.atan2(ry, rx) / PI) + 1) / 2.0 color_mode(HSB) col = color((hue * 255).to_i, (sat * 255).to_i, 255) set(x, y, col) end end
end </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>
Rust
Output is a file in PNG format. <lang rust>// [dependencies] // image = "0.23"
use image::error::ImageResult; use image::{Rgb, RgbImage};
fn hsv_to_rgb(h: f64, s: f64, v: f64) -> Rgb<u8> {
let hp = h / 60.0; let c = s * v; let x = c * (1.0 - (hp % 2.0 - 1.0).abs()); let m = v - c; let mut r = 0.0; let mut g = 0.0; let mut b = 0.0; if hp <= 1.0 { r = c; g = x; } else if hp <= 2.0 { r = x; g = c; } else if hp <= 3.0 { g = c; b = x; } else if hp <= 4.0 { g = x; b = c; } else if hp <= 5.0 { r = x; b = c; } else { r = c; b = x; } r += m; g += m; b += m; Rgb([(r * 255.0) as u8, (g * 255.0) as u8, (b * 255.0) as u8])
}
fn write_color_wheel(filename: &str, width: u32, height: u32) -> ImageResult<()> {
let mut image = RgbImage::new(width, height); let margin = 10; let diameter = std::cmp::min(width, height) - 2 * margin; let xoffset = (width - diameter) / 2; let yoffset = (height - diameter) / 2; let radius = diameter as f64 / 2.0; for x in 0..=diameter { let rx = x as f64 - radius; for y in 0..=diameter { let ry = y as f64 - radius; let r = ry.hypot(rx) / radius; if r > 1.0 { continue; } let a = 180.0 + ry.atan2(-rx).to_degrees(); image.put_pixel(x + xoffset, y + yoffset, hsv_to_rgb(a, r, 1.0)); } } image.save(filename)
}
fn main() {
match write_color_wheel("color_wheel.png", 400, 400) { Ok(()) => {} Err(error) => eprintln!("{}", error), }
}</lang>
- Output:
See: color_wheel.png (offsite PNG image)
Sidef
<lang ruby>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')</lang> Output image: Color wheel
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 This file is no longer there!!! 10 Sep 2021
Wren
<lang ecmascript>import "graphics" for Canvas, Color import "dome" for Window import "random" for Random
class Game {
static init() { Window.title = "Color Wheel" __width = 640 __height = 640 Window.resize(__width, __height) Canvas.resize(__width, __height) colorWheel() }
static colorWheel() { var cx = (__width/2).floor var cy = (__height/2).floor var r = (cx < cy) ? cx : cy for (y in 0...__height) { var dy = y - cy for (x in 0...__width) { var dx = x - cx var dist = (dx*dx + dy*dy).sqrt if (dist <= r) { var theta = dy.atan(dx) var h = (theta + Num.pi) / Num.pi * 180 var col = Color.hsv(h, dist/r, 1) Canvas.pset(x, y, col) } } } }
static update() {}
static draw(alpha) {}
}</lang>
XPL0
Algorithm is from "Computer Graphics ..." by Foley et al. The output is the same as Zkl. <lang XPL0>def Radius = 480/2; real Hue, Sat, Dist, I, F, P, Q, T; real XX, YY, RR, GG, BB; int X, Y, R, G, B; def Pi = 3.141592654; def V = 1.; \Value [SetVid($112); \640x480x24 graphics for Y:= -Radius to Radius do
for X:= -Radius to Radius do [XX:= float(X); YY:= float(Y); Dist:= sqrt(XX*XX + YY*YY); if Dist <= float(Radius) then [Sat:= Dist/float(Radius); \0 >= Sat <= 1 Hue:= ATan2(YY, XX); \-Pi >= Hue <= Pi if Hue < 0. then Hue:= Hue + 2.*Pi; Hue:= Hue * 180./Pi; \radians to degrees Hue:= Hue / 60.; \0 >= Hue < 6 I:= Floor(Hue); \integer part of Hue F:= Hue - I; \fractional part of Hue P:= 1. - Sat; Q:= 1. - Sat*F; T:= 1. - Sat*(1.-F); case fix(I) of 0: [RR:= V; GG:= T; BB:= P]; 1: [RR:= Q; GG:= V; BB:= P]; 2: [RR:= P; GG:= V; BB:= T]; 3: [RR:= P; GG:= Q; BB:= V]; 4: [RR:= T; GG:= P; BB:= V]; 5: [RR:= V; GG:= P; BB:= Q] other [exit 1]; R:= fix(RR*255.); G:= fix(GG*255.); B:= fix(BB*255.); Point(X+Radius, Radius-Y, R<<16+G<<8+B); ]; ];
]</lang>
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
- Programming Tasks
- Basic language learning
- AppleScript
- C++
- Qt
- Delphi
- Winapi.Windows
- System.SysUtils
- Vcl.Graphics
- System.Math
- Vcl.Imaging.pngimage
- Fōrmulæ
- GML
- Go
- Go Graphics
- Java
- Julia
- Kotlin
- M2000 Interpreter
- Mathematica
- Wolfram Language
- Nim
- Imageman
- Perl
- Phix
- Phix/pGUI
- Phix/online
- Processing
- Processing Python mode
- Python
- Racket
- Raku
- Ring
- Ruby
- RubyGems
- JRubyArt
- Run BASIC
- Rust
- Sidef
- Smart BASIC
- Wren
- DOME
- XPL0
- Zkl