diff options
Diffstat (limited to 'generator/ppmwheel.c')
-rw-r--r-- | generator/ppmwheel.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/generator/ppmwheel.c b/generator/ppmwheel.c new file mode 100644 index 00000000..ef5021f9 --- /dev/null +++ b/generator/ppmwheel.c @@ -0,0 +1,157 @@ +/* ppmwheel.c - create a color circle of a specified size +** +** This was adapted by Bryan Henderson in January 2003 from ppmcirc.c by +** Peter Kirchgessner: +** +** Copyright (C) 1995 by Peter Kirchgessner. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +#include <string.h> +#include <math.h> + +#include "ppm.h" + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +#ifndef ABS +#define ABS(a) ((a) < 0 ? -(a) : (a)) +#endif + +static void +hsv_rgb(double const in_h, double const in_s, double const in_v, + double * const r, double * const g, double * const b) { +/*---------------------------------------------------------------------------- + This is a stripped down hsv->rgb converter that works only for + Saturation of zero. +-----------------------------------------------------------------------------*/ + double h, s, v; + + h = in_h < 0.0 ? 0.0 : in_h > 360.0 ? 360.0 : in_h; + + v = in_v < 0.0 ? 0.0 : in_v > 1.0 ? 1.0 : in_v; + + s = in_s < 0.0 ? 0.0 : in_s > 1.0 ? 1.0 : in_s; + + if (s != 0.0) + pm_error("Internal error: non-zero saturation"); + + if (h <= 60.0) { /* from red to yellow */ + *r = 1.0; + *g = h / 60.0; + *b = 0.0; + } else if ( h <= 120.0 ) { /* from yellow to green */ + *r = 1.0 - (h - 60.0) / 60.0; + *g = 1.0; + *b = 0.0; + } else if ( h <= 180.0 ) { /* from green to cyan */ + *r = 0.0; + *g = 1.0; + *b = (h - 120.0) / 60.0; + } else if ( h <= 240.0 ) { /* from cyan to blue */ + *r = 0.0; + *g = 1.0 - (h - 180.0) / 60.0; + *b = 1.0; + } else if ( h <= 300.0) { /* from blue to magenta */ + *r = (h - 240.0) / 60.0; + *g = 0.0; + *b = 1.0; + } else { /* from magenta to red */ + *r = 1.0; + *g = 0.0; + *b = 1.0 - (h - 300.0) / 60.0; + } + + if ( v >= 0.5) { + v = 2.0 - 2.0 * v; + v = sqrt (v); + *r = 1.0 + v * (*r - 1.0); + *g = 1.0 + v * (*g - 1.0); + *b = 1.0 + v * (*b - 1.0); + } else { + v *= 2.0; + v = sqrt (sqrt ( sqrt (v))); + *r *= v; + *g *= v; + *b *= v; + } +} + + +int +main(int argc, char *argv[]) { + pixel *orow; + int rows, cols; + pixval maxval; + unsigned int row; + unsigned int xcenter, ycenter, radius; + long diameter; + char * tailptr; + + ppm_init( &argc, argv ); + + if (argc-1 != 1) + pm_error("Program takes one argument: diameter of color wheel"); + + diameter = strtol(argv[1], &tailptr, 10); + if (strlen(argv[1]) == 0 || *tailptr != '\0') + pm_error("You specified an invalid diameter: '%s'", argv[1]); + if (diameter <= 0) + pm_error("Diameter must be positive. You specified %ld.", diameter); + if (diameter < 4) + pm_error("Diameter must be at least 4. You specified %ld", diameter); + + cols = rows = diameter; + + orow = ppm_allocrow(cols); + + maxval = PPM_MAXMAXVAL; + ppm_writeppminit(stdout, cols, rows, maxval, 0); + + radius = diameter/2 - 1; + + xcenter = cols / 2; + ycenter = rows / 2; + + for (row = 0; row < rows; ++row) { + unsigned int col; + for (col = 0; col < cols; ++col) { + double const dx = (int)col - (int)xcenter; + double const dy = (int)row - (int)ycenter; + double const dist = sqrt(dx*dx + dy*dy); + + pixval r, g, b; + + if (dist > radius) { + r = g = b = maxval; + } else { + double hue, sat, val; + double dr, dg, db; + + hue = atan2(dx, dy) / PI * 180.0; + if (hue < 0.0) + hue = 360.0 + hue; + sat = 0.0; + val = dist / radius; + + hsv_rgb(hue, sat, val, &dr, &dg, &db); + + r = (pixval)(maxval * dr); + g = (pixval)(maxval * dg); + b = (pixval)(maxval * db); + } + PPM_ASSIGN (orow[col], r, g, b ); + } + ppm_writeppmrow(stdout, orow, cols, maxval, 0); + } + pm_close(stdout); + exit(0); +} |