about summary refs log tree commit diff
path: root/generator/ppmwheel.c
diff options
context:
space:
mode:
Diffstat (limited to 'generator/ppmwheel.c')
-rw-r--r--generator/ppmwheel.c157
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);
+}