svgui  1.9
ColourMapper.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006-2007 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "ColourMapper.h"
00017 
00018 #include <iostream>
00019 
00020 #include <cmath>
00021 
00022 #include "base/Debug.h"
00023 
00024 ColourMapper::ColourMapper(int map, float min, float max) :
00025     QObject(),
00026     m_map(map),
00027     m_min(min),
00028     m_max(max)
00029 {
00030     if (m_min == m_max) {
00031         cerr << "WARNING: ColourMapper: min == max (== " << m_min
00032                   << "), adjusting" << endl;
00033         m_max = m_min + 1;
00034     }
00035 }
00036 
00037 ColourMapper::~ColourMapper()
00038 {
00039 }
00040 
00041 int
00042 ColourMapper::getColourMapCount()
00043 {
00044     return 12;
00045 }
00046 
00047 QString
00048 ColourMapper::getColourMapName(int n)
00049 {
00050     if (n >= getColourMapCount()) return tr("<unknown>");
00051     StandardMap map = (StandardMap)n;
00052 
00053     switch (map) {
00054     case DefaultColours:   return tr("Default");
00055     case WhiteOnBlack:     return tr("White on Black");
00056     case BlackOnWhite:     return tr("Black on White");
00057     case RedOnBlue:        return tr("Red on Blue");
00058     case YellowOnBlack:    return tr("Yellow on Black");
00059     case BlueOnBlack:      return tr("Blue on Black");
00060     case Sunset:           return tr("Sunset");
00061     case FruitSalad:       return tr("Fruit Salad");
00062     case Banded:           return tr("Banded");
00063     case Highlight:        return tr("Highlight");
00064     case Printer:          return tr("Printer");
00065     case HighGain:         return tr("High Gain");
00066     }
00067 
00068     return tr("<unknown>");
00069 }
00070 
00071 QColor
00072 ColourMapper::map(float value) const
00073 {
00074     float norm = (value - m_min) / (m_max - m_min);
00075     if (norm < 0.f) norm = 0.f;
00076     if (norm > 1.f) norm = 1.f;
00077     
00078     float h = 0.f, s = 0.f, v = 0.f, r = 0.f, g = 0.f, b = 0.f;
00079     bool hsv = true;
00080 
00081 //    float red = 0.f, green = 0.3333f;
00082     float blue = 0.6666f, pieslice = 0.3333f;
00083 
00084     if (m_map >= getColourMapCount()) return Qt::black;
00085     StandardMap map = (StandardMap)m_map;
00086 
00087     switch (map) {
00088 
00089     case DefaultColours:
00090         h = blue - norm * 2.f * pieslice;
00091         s = 0.5f + norm/2.f;
00092         v = norm;
00093         break;
00094 
00095     case WhiteOnBlack:
00096         r = g = b = norm;
00097         hsv = false;
00098         break;
00099 
00100     case BlackOnWhite:
00101         r = g = b = 1.f - norm;
00102         hsv = false;
00103         break;
00104 
00105     case RedOnBlue:
00106         h = blue - pieslice/4.f + norm * (pieslice + pieslice/4.f);
00107         s = 1.f;
00108         v = norm;
00109         break;
00110 
00111     case YellowOnBlack:
00112         h = 0.15f;
00113         s = 1.f;
00114         v = norm;
00115         break;
00116 
00117     case BlueOnBlack:
00118         h = blue;
00119         s = 1.f;
00120         v = norm * 2.f;
00121         if (v > 1.f) {
00122             v = 1.f;
00123             s = 1.f - (sqrtf(norm) - 0.707f) * 3.413f;
00124             if (s < 0.f) s = 0.f;
00125             if (s > 1.f) s = 1.f;
00126         }
00127         break;
00128 
00129     case Sunset:
00130         r = (norm - 0.24f) * 2.38f;
00131         if (r > 1.f) r = 1.f;
00132         if (r < 0.f) r = 0.f;
00133         g = (norm - 0.64f) * 2.777f;
00134         if (g > 1.f) g = 1.f;
00135         if (g < 0.f) g = 0.f;
00136         b = (3.6f * norm);
00137         if (norm > 0.277f) b = 2.f - b;
00138         if (b > 1.f) b = 1.f;
00139         if (b < 0.f) b = 0.f;
00140         hsv = false;
00141         break;
00142 
00143     case FruitSalad:
00144         h = blue + (pieslice/6.f) - norm;
00145         if (h < 0.f) h += 1.f;
00146         s = 1.f;
00147         v = 1.f;
00148         break;
00149 
00150     case Banded:
00151         if      (norm < 0.125) return Qt::darkGreen;
00152         else if (norm < 0.25)  return Qt::green;
00153         else if (norm < 0.375) return Qt::darkBlue;
00154         else if (norm < 0.5)   return Qt::blue;
00155         else if (norm < 0.625) return Qt::darkYellow;
00156         else if (norm < 0.75)  return Qt::yellow;
00157         else if (norm < 0.875) return Qt::darkRed;
00158         else                   return Qt::red;
00159         break;
00160 
00161     case Highlight:
00162         if (norm > 0.99) return Qt::white;
00163         else return Qt::darkBlue;
00164 
00165     case Printer:
00166         if (norm > 0.8) {
00167             r = 1.f;
00168         } else if (norm > 0.7) {
00169             r = 0.9f;
00170         } else if (norm > 0.6) {
00171             r = 0.8f;
00172         } else if (norm > 0.5) {
00173             r = 0.7f;
00174         } else if (norm > 0.4) {
00175             r = 0.6f;
00176         } else if (norm > 0.3) {
00177             r = 0.5f;
00178         } else if (norm > 0.2) {
00179             r = 0.4f;
00180         } else {
00181             r = 0.f;
00182         }
00183         r = g = b = 1.f - r;
00184         hsv = false;
00185         break;
00186 
00187     case HighGain:
00188         if (norm <= 1.f / 256.f) {
00189             norm = 0.f;
00190         } else {
00191             norm = 0.1f + (powf(((norm - 0.5f) * 2.f), 3.f) + 1.f) / 2.081f;
00192         }
00193         // now as for Sunset
00194         r = (norm - 0.24f) * 2.38f;
00195         if (r > 1.f) r = 1.f;
00196         if (r < 0.f) r = 0.f;
00197         g = (norm - 0.64f) * 2.777f;
00198         if (g > 1.f) g = 1.f;
00199         if (g < 0.f) g = 0.f;
00200         b = (3.6f * norm);
00201         if (norm > 0.277f) b = 2.f - b;
00202         if (b > 1.f) b = 1.f;
00203         if (b < 0.f) b = 0.f;
00204         hsv = false;
00205 /*
00206         if (r > 1.f) r = 1.f;
00207         r = g = b = 1.f - r;
00208         hsv = false;
00209 */
00210         break;
00211     }
00212 
00213     if (hsv) {
00214         return QColor::fromHsvF(h, s, v);
00215     } else {
00216         return QColor::fromRgbF(r, g, b);
00217     }
00218 }
00219 
00220 QColor
00221 ColourMapper::getContrastingColour() const
00222 {
00223     if (m_map >= getColourMapCount()) return Qt::white;
00224     StandardMap map = (StandardMap)m_map;
00225 
00226     switch (map) {
00227 
00228     case DefaultColours:
00229         return QColor(255, 150, 50);
00230 
00231     case WhiteOnBlack:
00232         return Qt::red;
00233 
00234     case BlackOnWhite:
00235         return Qt::darkGreen;
00236 
00237     case RedOnBlue:
00238         return Qt::green;
00239 
00240     case YellowOnBlack:
00241         return QColor::fromHsv(240, 255, 255);
00242 
00243     case BlueOnBlack:
00244         return Qt::red;
00245 
00246     case Sunset:
00247         return Qt::white;
00248 
00249     case FruitSalad:
00250         return Qt::white;
00251 
00252     case Banded:
00253         return Qt::cyan;
00254 
00255     case Highlight:
00256         return Qt::red;
00257 
00258     case Printer:
00259         return Qt::red;
00260 
00261     case HighGain:
00262         return Qt::red;
00263     }
00264 
00265     return Qt::white;
00266 }
00267 
00268 bool
00269 ColourMapper::hasLightBackground() const
00270 {
00271     if (m_map >= getColourMapCount()) return false;
00272     StandardMap map = (StandardMap)m_map;
00273 
00274     switch (map) {
00275 
00276     case BlackOnWhite:
00277     case Printer:
00278     case HighGain:
00279         return true;
00280 
00281     case DefaultColours:
00282     case Sunset:
00283     case WhiteOnBlack:
00284     case RedOnBlue:
00285     case YellowOnBlack:
00286     case BlueOnBlack:
00287     case FruitSalad:
00288     case Banded:
00289     case Highlight:
00290         
00291     default:
00292         return false;
00293     }
00294 }
00295 
00296