diff options
author | Christian Daniel <cd@maintech.de> | 2013-03-22 11:18:30 +0100 |
---|---|---|
committer | Christian Daniel <cd@maintech.de> | 2013-03-22 11:18:30 +0100 |
commit | eca56e35be841396f6c57bab540a3e1503253d56 (patch) | |
tree | 4a0a29cd53a84339e56754c32bf67391c83494fe /sdrbase/gui/scaleengine.cpp | |
parent | 2c8c930b39fe069b36d81caa00401d9ac182a9d8 (diff) |
monster rework
- pluginify whole project
- reorganize directory structure
- fix PortAudio detection script
- implement generic channelizer
- fix several OpenGL problems
- rework presets
- add audio mixing
- too many more
Diffstat (limited to 'sdrbase/gui/scaleengine.cpp')
-rw-r--r-- | sdrbase/gui/scaleengine.cpp | 569 |
1 files changed, 569 insertions, 0 deletions
diff --git a/sdrbase/gui/scaleengine.cpp b/sdrbase/gui/scaleengine.cpp new file mode 100644 index 0000000..06bde36 --- /dev/null +++ b/sdrbase/gui/scaleengine.cpp @@ -0,0 +1,569 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // +// written by Christian Daniel // +// // +// This program 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 as version 3 of the License, or // +// // +// This program 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 V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see <http://www.gnu.org/licenses/>. // +/////////////////////////////////////////////////////////////////////////////////// + +#include <math.h> +#include <QFontMetrics> +#include <QDataStream> +#include "gui/scaleengine.h" + +/* +static double trunc(double d) +{ + return (d > 0) ? floor(d) : ceil(d); +} +*/ + +QString ScaleEngine::formatTick(double value, int decimalPlaces, bool fancyTime) +{ + if((m_physicalUnit != Unit::Time) || (!fancyTime) || 1) { + return QString("%1").arg(value, 0, 'f', decimalPlaces); + } else { + QString str; + double orig = fabs(value); + double tmp; + + if(orig >= 86400.0) { + tmp = floor(value / 86400.0); + str = QString("%1.").arg(tmp, 0, 'f', 0); + value -= tmp * 86400.0; + if(value < 0.0) + value *= -1.0; + } + + if(orig >= 3600.0) { + tmp = floor(value / 3600.0); + str += QString("%1:").arg(tmp, 2, 'f', 0, QChar('0')); + value -= tmp * 3600.0; + if(value < 0.0) + value *= -1.0; + } + + if(orig >= 60.0) { + tmp = floor(value / 60.0); + str += QString("%1:").arg(tmp, 2, 'f', 0, QChar('0')); + value -= tmp * 60.0; + if(value < 0.0) + value *= -1.0; + } + + tmp = value; + str += QString("%1").arg(tmp, 2, 'f', decimalPlaces, QChar('0')); + + return str; + } +} + +void ScaleEngine::calcCharSize() +{ + QFontMetricsF fontMetrics(m_font); + + if(m_orientation == Qt::Vertical) { + m_charSize = fontMetrics.height(); + } else { + QString str("012345679.,-"); + int i; + float size; + float max = 0.0f; + for(i = 0; i < str.length(); i++) { + size = fontMetrics.width(QString(str[i])); + if(size > max) + max = size; + } + m_charSize = max; + } +} + +void ScaleEngine::calcScaleFactor() +{ + double median; + + median = ((m_rangeMax - m_rangeMin) / 2.0) + m_rangeMin; + m_scale = 1.0; + + switch(m_physicalUnit) { + case Unit::None: + m_unitStr.clear(); + break; + + case Unit::Frequency: + if(median < 1000.0) { + m_unitStr = QObject::tr("Hz"); + } else if(median < 1000000.0) { + m_unitStr = QObject::tr("kHz"); + m_scale = 1000.0; + } else if(median < 1000000000.0) { + m_unitStr = QObject::tr("MHz"); + m_scale = 1000000.0; + } else if(median < 1000000000000.0){ + m_unitStr = QObject::tr("GHz"); + m_scale = 1000000000.0; + } else { + m_unitStr = QObject::tr("THz"); + m_scale = 1000000000000.0; + } + break; + + case Unit::Information: + if(median < 1024.0) { + m_unitStr = QObject::tr("Bytes"); + } else if(median < 1048576.0) { + m_unitStr = QObject::tr("KiBytes"); + m_scale = 1024.0; + } else if(median < 1073741824.0) { + m_unitStr = QObject::tr("MiBytes"); + m_scale = 1048576.0; + } else if(median < 1099511627776.0) { + m_unitStr = QObject::tr("GiBytes"); + m_scale = 1073741824.0; + } else if(median < 1125899906842624.0) { + m_unitStr = QObject::tr("TiBytes"); + m_scale = 1099511627776.0; + } else { + m_unitStr = QObject::tr("PiBytes"); + m_scale = 1125899906842624.0; + } + break; + + case Unit::Percent: + m_unitStr = QString("%"); + break; + + case Unit::Decibel: + m_unitStr = QString("dB"); + break; + + case Unit::DecibelMilliWatt: + m_unitStr = QString("dBm"); + break; + + case Unit::DecibelMicroVolt: + m_unitStr = QString("dBµV"); + break; + + case Unit::AngleDegrees: + m_unitStr = QString("°"); + + case Unit::Time: + if(median < 0.001) { + m_unitStr = QString("µs"); + m_scale = 0.000001; + } else if(median < 1.0) { + m_unitStr = QString("ms"); + m_scale = 0.001; + } else { + m_unitStr = QString("s"); + } + break; + } +} + +double ScaleEngine::calcMajorTickUnits(double distance, int* retDecimalPlaces) +{ + double sign; + double log10x; + double exponent; + double base; + int decimalPlaces; + + if(distance == 0.0) + return 0.0; + + sign = (distance > 0.0) ? 1.0 : -1.0; + log10x = log10(fabs(distance)); + exponent = floor(log10x); + base = pow(10.0, log10x - exponent); + decimalPlaces = (int)(-exponent); +/* + if((m_physicalUnit == Unit::Time) && (distance >= 1.0)) { + if(retDecimalPlaces != NULL) + *retDecimalPlaces = 0; + if(distance < 1.0) + return 1.0; + else if(distance < 5.0) + return 5.0; + else if(distance < 10.0) + return 10.0; + else if(distance < 15.0) + return 15.0; + else if(distance < 30.0) + return 30.0; + else if(distance < 60.0) + return 60.0; + else if(distance < 5.0 * 60.0) + return 5.0 * 60.0; + else if(distance < 10.0 * 60.0) + return 10.0 * 60.0; + else if(distance < 15.0 * 60.0) + return 15.0 * 60.0; + else if(distance < 30.0 * 60.0) + return 30.0 * 60.0; + else if(distance < 3600.0) + return 3600.0; + else if(distance < 2.0 * 3600.0) + return 2.0 * 3600.0; + else if(distance < 3.0 * 3600.0) + return 3.0 * 3600.0; + else if(distance < 6.0 * 3600.0) + return 6.0 * 3600.0; + else if(distance < 12.0 * 3600.0) + return 12.0 * 3600.0; + else if(distance < 86000.0) + return 86000.0; + else if(distance < 2.0 * 86000.0) + return 2.0 * 86000.0; + else if(distance < 7.0 * 86000.0) + return 7.0 * 86000.0; + else if(distance < 10.0 * 86000.0) + return 10.0 * 86000.0; + else if(distance < 30.0 * 86000.0) + return 30.0 * 86000.0; + else return 90.0 * 86000.0; + } else {*/ + if(base <= 1.0) { + base = 1.0; + } else if(base <= 2.0) { + base = 2.0; + } else if(base <= 2.5) { + base = 2.5; + if(decimalPlaces >= 0) + decimalPlaces++; + } else if(base <= 5.0) { + base = 5.0; + } else { + base = 10.0; + }/* + }*/ + + if(retDecimalPlaces != NULL) { + if(decimalPlaces < 0) + decimalPlaces = 0; + *retDecimalPlaces = decimalPlaces; + } + + return sign * base * pow(10.0, exponent); +} + +int ScaleEngine::calcTickTextSize() +{ + int tmp; + int tickLen; + int decimalPlaces; + + tickLen = 1; + tmp = formatTick(m_rangeMin / m_scale, 0).length(); + if(tmp > tickLen) + tickLen = tmp; + tmp = formatTick(m_rangeMax / m_scale, 0).length(); + if(tmp > tickLen) + tickLen = tmp; + + calcMajorTickUnits((m_rangeMax - m_rangeMin) / m_scale, &decimalPlaces); + + return tickLen + decimalPlaces + 1; +} + +void ScaleEngine::forceTwoTicks() +{ + Tick tick; + QFontMetricsF fontMetrics(m_font); + + m_tickList.clear(); + tick.major = true; + + tick.pos = getPosFromValue(m_rangeMin); + tick.text = formatTick(m_rangeMin / m_scale, m_decimalPlaces); + tick.textSize = fontMetrics.boundingRect(tick.text).width(); + if(m_orientation == Qt::Vertical) + tick.textPos = tick.pos - fontMetrics.ascent() / 2; + else tick.textPos = tick.pos - fontMetrics.boundingRect(tick.text).width() / 2; + m_tickList.append(tick); + + tick.pos = getPosFromValue(m_rangeMax); + tick.text = formatTick(m_rangeMax / m_scale, m_decimalPlaces); + tick.textSize = fontMetrics.boundingRect(tick.text).width(); + if(m_orientation == Qt::Vertical) + tick.textPos = tick.pos - fontMetrics.ascent() / 2; + else tick.textPos = tick.pos - fontMetrics.boundingRect(tick.text).width() / 2; + m_tickList.append(tick); +} + +void ScaleEngine::reCalc() +{ + float majorTickSize; + double rangeMinScaled; + double rangeMaxScaled; + int maxNumMajorTicks; + int numMajorTicks; + int step; + int skip; + double value; + double value2; + int i; + int j; + Tick tick; + float pos; + QString str; + QFontMetricsF fontMetrics(m_font); + float endPos; + float lastEndPos; + bool done; + + if(!m_recalc) + return; + m_recalc = false; + + m_tickList.clear(); + + calcScaleFactor(); + rangeMinScaled = m_rangeMin / m_scale; + rangeMaxScaled = m_rangeMax / m_scale; + + if(m_orientation == Qt::Vertical) { + maxNumMajorTicks = (int)(m_size / (fontMetrics.lineSpacing() * 1.3f)); + } else { + majorTickSize = (calcTickTextSize() + 2) * m_charSize; + if(majorTickSize != 0.0) + maxNumMajorTicks = (int)(m_size / majorTickSize); + else maxNumMajorTicks = 20; + } + + m_majorTickValueDistance = calcMajorTickUnits((rangeMaxScaled - rangeMinScaled) / maxNumMajorTicks, &m_decimalPlaces); + numMajorTicks = (int)((rangeMaxScaled - rangeMinScaled) / m_majorTickValueDistance); + + if(numMajorTicks == 0) { + forceTwoTicks(); + return; + } + + if(maxNumMajorTicks > 0) + m_numMinorTicks = (int)(m_size / (maxNumMajorTicks * fontMetrics.height())); + else m_numMinorTicks = 0; + if(m_numMinorTicks < 1) + m_numMinorTicks = 0; + else if(m_numMinorTicks < 2) + m_numMinorTicks = 1; + else if(m_numMinorTicks < 5) + m_numMinorTicks = 2; + else if(m_numMinorTicks < 10) + m_numMinorTicks = 5; + else m_numMinorTicks = 10; + + m_firstMajorTickValue = floor(rangeMinScaled / m_majorTickValueDistance) * m_majorTickValueDistance; + + skip = 0; + + if(rangeMinScaled == rangeMaxScaled) + return; + + while(true) { + m_tickList.clear(); + + step = 0; + lastEndPos = -100000000; + done = true; + + for(i = 0; true; i++) { + value = majorTickValue(i); + + for(j = 1; j < m_numMinorTicks; j++) { + value2 = value + minorTickValue(j); + if(value2 < rangeMinScaled) + continue; + if(value2 > rangeMaxScaled) + break; + pos = getPosFromValue((value + minorTickValue(j)) * m_scale); + if((pos >= 0) && (pos < m_size)) { + tick.pos = pos; + tick.major = false; + tick.textPos = -1; + tick.textSize = -1; + tick.text.clear(); + } + m_tickList.append(tick); + } + + pos = getPosFromValue(value * m_scale); + if(pos < 0.0) + continue; + if(pos >= m_size) + break; + + tick.pos = pos; + tick.major = true; + tick.textPos = -1; + tick.textSize = -1; + tick.text.clear(); + + if(step % (skip + 1) != 0) { + m_tickList.append(tick); + step++; + continue; + } + step++; + + str = formatTick(value, m_decimalPlaces); + tick.text = str; + tick.textSize = fontMetrics.boundingRect(tick.text).width(); + if(m_orientation == Qt::Vertical) { + tick.textPos = pos - fontMetrics.ascent() / 2; + endPos = tick.textPos + fontMetrics.ascent(); + } else { + tick.textPos = pos - fontMetrics.boundingRect(tick.text).width() / 2; + endPos = tick.textPos + tick.textSize; + } + + if(lastEndPos >= tick.textPos) { + done = false; + break; + } else { + lastEndPos = endPos; + } + + m_tickList.append(tick); + } + if(done) + break; + skip++; + } + + // make sure we have at least two major ticks with numbers + numMajorTicks = 0; + for(i = 0; i < m_tickList.count(); i++) { + tick = m_tickList.at(i); + if(tick.major) + numMajorTicks++; + } + if(numMajorTicks < 2) + forceTwoTicks(); +} + +double ScaleEngine::majorTickValue(int tick) +{ + return m_firstMajorTickValue + (tick * m_majorTickValueDistance); +} + +double ScaleEngine::minorTickValue(int tick) +{ + if(m_numMinorTicks < 1) + return 0.0; + return (m_majorTickValueDistance * tick) / m_numMinorTicks; +} + +ScaleEngine::ScaleEngine() : + m_orientation(Qt::Horizontal), + m_physicalUnit(Unit::None), + m_rangeMin(-1.0), + m_rangeMax(1.0), + m_recalc(true) +{ +} + +void ScaleEngine::setOrientation(Qt::Orientation orientation) +{ + m_orientation = orientation; + m_recalc = true; +} + +void ScaleEngine::setFont(const QFont& font) +{ + m_font = font; + m_recalc = true; + calcCharSize(); +} + +void ScaleEngine::setSize(float size) +{ + if(size > 0.0f) { + m_size = size; + } else { + m_size = 1.0f; + } + m_recalc = true; +} + +void ScaleEngine::setRange(Unit::Physical physicalUnit, float rangeMin, float rangeMax) +{ + double tmpRangeMin; + double tmpRangeMax; +/* + if(rangeMin < rangeMax) { + tmpRangeMin = rangeMin; + tmpRangeMax = rangeMax; + } else if(rangeMin > rangeMax) { + tmpRangeMin = rangeMax; + tmpRangeMax = rangeMin; + } else { + tmpRangeMin = rangeMin * 0.99; + tmpRangeMax = rangeMin * 1.01 + 0.01; + } +*/ + tmpRangeMin = rangeMin; + tmpRangeMax = rangeMax; + + if((tmpRangeMin != m_rangeMin) || (tmpRangeMax != m_rangeMax) || (m_physicalUnit != physicalUnit)) { + m_physicalUnit = physicalUnit; + m_rangeMin = tmpRangeMin; + m_rangeMax = tmpRangeMax; + m_recalc = true; + } +} + +float ScaleEngine::getPosFromValue(double value) +{ + return ((value - m_rangeMin) / (m_rangeMax - m_rangeMin)) * (m_size - 1.0); +} + +float ScaleEngine::getValueFromPos(double pos) +{ + return ((pos * (m_rangeMax - m_rangeMin)) / (m_size - 1.0)) + m_rangeMin; +} + +const ScaleEngine::TickList& ScaleEngine::getTickList() +{ + reCalc(); + return m_tickList; +} + +QString ScaleEngine::getRangeMinStr() +{ + if(m_unitStr.length() > 0) + return QString("%1 %2").arg(formatTick(m_rangeMin / m_scale, m_decimalPlaces, false)).arg(m_unitStr); + else return QString("%1").arg(formatTick(m_rangeMin / m_scale, m_decimalPlaces, false)); +} + +QString ScaleEngine::getRangeMaxStr() +{ + if(m_unitStr.length() > 0) + return QString("%1 %2").arg(formatTick(m_rangeMax / m_scale, m_decimalPlaces, false)).arg(m_unitStr); + else return QString("%1").arg(formatTick(m_rangeMax / m_scale, m_decimalPlaces, false)); +} + +float ScaleEngine::getScaleWidth() +{ + float max; + float len; + int i; + + reCalc(); + max = 0.0f; + for(i = 0; i < m_tickList.count(); i++) { + len = m_tickList[i].textSize; + if(len > max) + max = len; + } + return max; +} |