/* 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 #include #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); }