aboutsummaryrefslogtreecommitdiff
path: root/libcrystfel/src/colscale.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcrystfel/src/colscale.c')
-rw-r--r--libcrystfel/src/colscale.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/libcrystfel/src/colscale.c b/libcrystfel/src/colscale.c
new file mode 100644
index 00000000..4a39de8d
--- /dev/null
+++ b/libcrystfel/src/colscale.c
@@ -0,0 +1,246 @@
+/*
+ * colscale.c
+ *
+ * Colour scales
+ *
+ * Copyright © 2012-2021 Deutsches Elektronen-Synchrotron DESY,
+ * a research centre of the Helmholtz Association.
+ *
+ * Authors:
+ * 2009-2020 Thomas White <taw@physics.org>
+ *
+ * This file is part of CrystFEL.
+ *
+ * CrystFEL is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * CrystFEL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with CrystFEL. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+
+#include "colscale.h"
+
+/** \file colscale.h */
+
+static void render_rgb(double val, double max,
+ double *rp, double *gp, double *bp)
+{
+ int s;
+ double p;
+ double r, g, b;
+
+ s = val / (max/6);
+ p = fmod(val, max/6.0);
+ p /= (max/6.0);
+
+ r = 0.0; g = 0.0; b = 0.0;
+
+ if ( (val < 0.0) ) {
+ p = fabs(val) / (max/6.0);
+ *rp = 0.0;
+ *gp = 0.5*p;
+ *bp = 0.0;
+ return;
+ }
+ if ( (val > max) ) {
+ s = 6;
+ }
+ switch ( s ) {
+
+ case 0 : /* Black to blue */
+ r = 0; g = 0; b = p;
+ break;
+
+ case 1 : /* Blue to pink */
+ r = p; g = 0; b = 1.0;
+ break;
+
+ case 2 : /* Pink to red */
+ r = 1.0; g = 0; b = (1.0-p)*1.0;
+ break;
+
+ case 3 : /* Red to Orange */
+ r = 1.0; g = 0.5*p; b = 0;
+ break;
+
+ case 4 : /* Orange to Yellow */
+ r = 1.0; g = 0.5 + 0.5*p; b = 0;
+ break;
+
+ case 5 : /* Yellow to White */
+ r = 1.0; g = 1.0; b = 1.0*p;
+ break;
+
+ case 6 : /* Pixel has hit the maximum value */
+ r = 1.0; g = 1.0; b = 1.0;
+ break;
+
+ }
+
+ *rp = r;
+ *gp = g;
+ *bp = b;
+}
+
+
+static void render_geoptimiser(double val, double max,
+ double *rp, double *gp, double *bp)
+{
+ double r;
+ double p;
+
+ r = val/max;
+
+ if ( val < 0.0 ) {
+ *rp = 0.0;
+ *gp = 0.0;
+ *bp = 0.0;
+ return;
+ }
+
+ if ( r >= 0.0 && r < 0.059 ) {
+ p = (r-0.0)/(0.059-0.0);
+ *rp = 0.0;
+ *gp = 0.0;
+ *bp = ((91.0/256.0)-0.0)*p;
+ return;
+ }
+
+ if ( r >= 0.059 && r < 0.220 ) {
+ p = (r-0.059)/(0.220-0.059);
+ *rp = ((122.0/256.0)-0.0)*p;
+ *gp = 0.0;
+ *bp = ((227.0/256.0)-(91.0/256.0))*p+(91.0/256.0);
+ return;
+ }
+
+ if ( r >= 0.220 && r < 0.376 ) {
+ p = (r-0.220)/(0.376-0.220);
+ *rp = ((195.0/256.0)-(122.0/256.0))*p+(122.0/256.0);
+ *gp = 0.0;
+ *bp = ((93.0/256.0)-(227.0/256.0))*p+(227.0/256.0);
+ return;
+ }
+
+ if ( r >= 0.376 && r < 0.498 ) {
+ p = (r-0.376)/(0.498-0.376);
+ *rp = ((238.0/256.0)-(195.0/256.0))*p+(195.0/256.0);
+ *gp = ((76.0/256.0)-0.0)*p;
+ *bp = (0.0-(93.0/256.0))*p+(93.0/256.0);
+ return;
+ }
+
+ if ( r >= 0.498 && r < 0.564 ) {
+ p = (r-0.498)/(0.564-0.498);
+ *rp = (1.0-(238.0/256.0))*p+(238.0/256.0);
+ *gp = ((117.0/256.0)-(76.0/256.0))*p+(76.0/256.0);
+ *bp = 0.0;
+ return;
+ }
+
+ if ( r >= 0.564 && r < 0.815 ) {
+ p = (r-0.564)/(0.815-0.564);
+ *rp = 1.0;
+ *gp = ((234.0/256.0)-(117.0/256.0))*p+(117.0/256.0);
+ *bp = 0.0;
+ return;
+ }
+
+ if ( r >= 0.815 && r < 1.0 ) {
+ p = (r-0.815)/(1.0-0.815);
+ *rp = 1.0;
+ *gp = (1.0-(234.0/256.0))*p+(234.0/256.0);
+ *bp = (1.0-0.0)*p;
+ return;
+ }
+
+ if ( r >= 1.0 ) {
+ *rp = 1.0; *gp = 1.0; *bp = 1.0;
+ return;
+ }
+}
+
+
+static void render_ratio(double val, double max,
+ double *rp, double *gp, double *bp)
+{
+ if ( val <= 1.0 ) {
+ render_rgb(val, 2.0, rp, gp, bp);
+ } else {
+ /* Your homework is to simplify this expression */
+ val = ((val-1.0)/(max-1.0)) * (max/2.0) + max/2.0;
+ render_rgb(val, max, rp, gp, bp);
+ }
+}
+
+
+static void render_mono(double val, double max,
+ double *rp, double *gp, double *bp)
+{
+ double p;
+ p = val / max;
+ if ( val < 0.0 ) p = 0.0;
+ if ( val > max ) p = 1.0;
+ *rp = p;
+ *gp = p;
+ *bp = p;
+}
+
+
+static void render_invmono(double val, double max,
+ double *rp, double *gp, double *bp)
+{
+ double p;
+ p = val / max;
+ p = 1.0 - p;
+ if ( val < 0.0 ) p = 1.0;
+ if ( val > max ) p = 0.0;
+ *rp = p;
+ *gp = p;
+ *bp = p;
+}
+
+
+void colscale_lookup(double val, double max, int scale,
+ double *rp, double *gp, double *bp)
+{
+ switch ( scale ) {
+
+ case SCALE_COLOUR :
+ render_rgb(val, max, rp, gp, bp);
+ break;
+
+ case SCALE_MONO :
+ render_mono(val, max, rp, gp, bp);
+ break;
+
+ case SCALE_INVMONO :
+ render_invmono(val, max, rp, gp, bp);
+ break;
+
+ case SCALE_RATIO :
+ render_ratio(val, max, rp, gp, bp);
+ break;
+
+ case SCALE_GEOPTIMISER :
+ render_geoptimiser(val, max, rp, gp, bp);
+ break;
+ }
+}