Chris@277: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@277: Chris@277: /* Chris@277: Sonic Visualiser Chris@277: An audio file viewer and annotation editor. Chris@277: Centre for Digital Music, Queen Mary, University of London. Chris@277: This file copyright 2006-2007 Chris Cannam and QMUL. Chris@277: Chris@277: This program is free software; you can redistribute it and/or Chris@277: modify it under the terms of the GNU General Public License as Chris@277: published by the Free Software Foundation; either version 2 of the Chris@277: License, or (at your option) any later version. See the file Chris@277: COPYING included with this distribution for more information. Chris@277: */ Chris@277: Chris@277: #include "ColourMapper.h" Chris@277: Chris@277: #include Chris@277: Chris@277: #include Chris@277: Chris@277: ColourMapper::ColourMapper(int map, float min, float max) : Chris@277: QObject(), Chris@277: m_map(map), Chris@277: m_min(min), Chris@277: m_max(max) Chris@277: { Chris@277: if (m_min == m_max) { Chris@277: std::cerr << "WARNING: ColourMapper: min == max (== " << m_min Chris@277: << "), adjusting" << std::endl; Chris@277: m_max = m_min + 1; Chris@277: } Chris@277: } Chris@277: Chris@277: ColourMapper::~ColourMapper() Chris@277: { Chris@277: } Chris@277: Chris@277: int Chris@277: ColourMapper::getColourMapCount() Chris@277: { Chris@277: return 11; Chris@277: } Chris@277: Chris@277: QString Chris@277: ColourMapper::getColourMapName(int n) Chris@277: { Chris@277: if (n >= getColourMapCount()) return tr(""); Chris@277: StandardMap map = (StandardMap)n; Chris@277: Chris@277: switch (map) { Chris@277: case DefaultColours: return tr("Default"); Chris@277: case WhiteOnBlack: return tr("White on Black"); Chris@277: case BlackOnWhite: return tr("Black on White"); Chris@277: case RedOnBlue: return tr("Red on Blue"); Chris@277: case YellowOnBlack: return tr("Yellow on Black"); Chris@277: case BlueOnBlack: return tr("Blue on Black"); Chris@277: case Sunset: return tr("Sunset"); Chris@277: case FruitSalad: return tr("Fruit Salad"); Chris@277: case Banded: return tr("Banded"); Chris@277: case Highlight: return tr("Highlight"); Chris@277: case Printer: return tr("Printer"); Chris@277: } Chris@277: Chris@277: return tr(""); Chris@277: } Chris@277: Chris@277: QColor Chris@277: ColourMapper::map(float value) const Chris@277: { Chris@277: float norm = (value - m_min) / (m_max - m_min); Chris@277: if (norm < 0.f) norm = 0.f; Chris@277: if (norm > 1.f) norm = 1.f; Chris@277: Chris@277: float h = 0.f, s = 0.f, v = 0.f, r = 0.f, g = 0.f, b = 0.f; Chris@277: bool hsv = true; Chris@277: Chris@277: // float red = 0.f, green = 0.3333f; Chris@277: float blue = 0.6666f, pieslice = 0.3333f; Chris@277: Chris@277: if (m_map >= getColourMapCount()) return Qt::black; Chris@277: StandardMap map = (StandardMap)m_map; Chris@277: Chris@277: switch (map) { Chris@277: Chris@277: case DefaultColours: Chris@277: h = blue - norm * 2.f * pieslice; Chris@277: s = 0.5f + norm/2.f; Chris@277: v = norm; Chris@277: break; Chris@277: Chris@277: case WhiteOnBlack: Chris@277: r = g = b = norm; Chris@277: hsv = false; Chris@277: break; Chris@277: Chris@277: case BlackOnWhite: Chris@277: r = g = b = 1.f - norm; Chris@277: hsv = false; Chris@277: break; Chris@277: Chris@277: case RedOnBlue: Chris@277: h = blue - pieslice/4.f + norm * (pieslice + pieslice/4.f); Chris@277: s = 1.f; Chris@277: v = norm; Chris@277: break; Chris@277: Chris@277: case YellowOnBlack: Chris@277: h = 0.15f; Chris@277: s = 1.f; Chris@277: v = norm; Chris@277: break; Chris@277: Chris@277: case BlueOnBlack: Chris@277: h = blue; Chris@277: s = 1.f; Chris@277: v = norm * 2.f; Chris@277: if (v > 1.f) { Chris@277: v = 1.f; Chris@277: s = 1.f - (sqrtf(norm) - 0.707f) * 3.413f; Chris@277: if (s < 0.f) s = 0.f; Chris@277: if (s > 1.f) s = 1.f; Chris@277: } Chris@277: break; Chris@277: Chris@277: case Sunset: Chris@277: r = (norm - 0.24f) * 2.38f; Chris@277: if (r > 1.f) r = 1.f; Chris@277: if (r < 0.f) r = 0.f; Chris@277: g = (norm - 0.64f) * 2.777f; Chris@277: if (g > 1.f) g = 1.f; Chris@277: if (g < 0.f) g = 0.f; Chris@277: b = (3.6f * norm); Chris@277: if (norm > 0.277f) b = 2.f - b; Chris@277: if (b > 1.f) b = 1.f; Chris@277: if (b < 0.f) b = 0.f; Chris@277: hsv = false; Chris@277: break; Chris@277: Chris@277: case FruitSalad: Chris@277: h = blue + (pieslice/6.f) - norm; Chris@277: if (h < 0.f) h += 1.f; Chris@277: s = 1.f; Chris@277: v = 1.f; Chris@277: break; Chris@277: Chris@277: case Banded: Chris@277: if (norm < 0.125) return Qt::darkGreen; Chris@277: else if (norm < 0.25) return Qt::green; Chris@277: else if (norm < 0.375) return Qt::darkBlue; Chris@277: else if (norm < 0.5) return Qt::blue; Chris@277: else if (norm < 0.625) return Qt::darkYellow; Chris@277: else if (norm < 0.75) return Qt::yellow; Chris@277: else if (norm < 0.875) return Qt::darkRed; Chris@277: else return Qt::red; Chris@277: break; Chris@277: Chris@277: case Highlight: Chris@277: if (norm > 0.99) return Qt::white; Chris@277: else return Qt::darkBlue; Chris@277: Chris@277: case Printer: Chris@277: if (norm > 0.8) { Chris@277: r = 1.f; Chris@277: } else if (norm > 0.7) { Chris@277: r = 0.9f; Chris@277: } else if (norm > 0.6) { Chris@277: r = 0.8f; Chris@277: } else if (norm > 0.5) { Chris@277: r = 0.7f; Chris@277: } else if (norm > 0.4) { Chris@277: r = 0.6f; Chris@277: } else if (norm > 0.3) { Chris@277: r = 0.5f; Chris@277: } else if (norm > 0.2) { Chris@277: r = 0.4f; Chris@277: } else { Chris@277: r = 0.f; Chris@277: } Chris@277: r = g = b = 1.f - r; Chris@277: hsv = false; Chris@277: break; Chris@277: } Chris@277: Chris@277: if (hsv) { Chris@277: return QColor::fromHsvF(h, s, v); Chris@277: } else { Chris@277: return QColor::fromRgbF(r, g, b); Chris@277: } Chris@277: } Chris@277: Chris@277: QColor Chris@277: ColourMapper::getContrastingColour() const Chris@277: { Chris@277: if (m_map >= getColourMapCount()) return Qt::white; Chris@277: StandardMap map = (StandardMap)m_map; Chris@277: Chris@277: switch (map) { Chris@277: Chris@277: case DefaultColours: Chris@277: return QColor(255, 150, 50); Chris@277: Chris@277: case WhiteOnBlack: Chris@277: return Qt::red; Chris@277: Chris@277: case BlackOnWhite: Chris@277: return Qt::darkGreen; Chris@277: Chris@277: case RedOnBlue: Chris@277: return Qt::green; Chris@277: Chris@277: case YellowOnBlack: Chris@277: return QColor::fromHsv(240, 255, 255); Chris@277: Chris@277: case BlueOnBlack: Chris@277: return Qt::red; Chris@277: Chris@277: case Sunset: Chris@277: return Qt::white; Chris@277: Chris@277: case FruitSalad: Chris@277: return Qt::white; Chris@277: Chris@277: case Banded: Chris@277: return Qt::cyan; Chris@277: Chris@277: case Highlight: Chris@277: return Qt::red; Chris@277: Chris@277: case Printer: Chris@277: return Qt::red; Chris@277: } Chris@277: Chris@277: return Qt::white; Chris@277: } Chris@277: Chris@277: bool Chris@277: ColourMapper::hasLightBackground() const Chris@277: { Chris@277: if (m_map >= getColourMapCount()) return false; Chris@277: StandardMap map = (StandardMap)m_map; Chris@277: Chris@277: switch (map) { Chris@277: Chris@277: case BlackOnWhite: Chris@277: case Printer: Chris@277: return true; Chris@277: Chris@277: default: Chris@277: return false; Chris@277: } Chris@277: } Chris@277: Chris@277: