| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | // 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() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2015-06-21 12:46:47 +02:00
										 |  |  | 	double median, range, freqBase; | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	median = ((m_rangeMax - m_rangeMin) / 2.0) + m_rangeMin; | 
					
						
							| 
									
										
										
										
											2015-06-21 12:46:47 +02:00
										 |  |  | 	range = (m_rangeMax - m_rangeMin); | 
					
						
							|  |  |  | 	freqBase = (median == 0 ? range : median); | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 	m_scale = 1.0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch(m_physicalUnit) { | 
					
						
							|  |  |  | 		case Unit::None: | 
					
						
							|  |  |  | 			m_unitStr.clear(); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case Unit::Frequency: | 
					
						
							| 
									
										
										
										
											2015-06-21 12:46:47 +02:00
										 |  |  | 			if(freqBase < 1000.0) { | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				m_unitStr = QObject::tr("Hz"); | 
					
						
							| 
									
										
										
										
											2015-06-21 12:46:47 +02:00
										 |  |  | 			} else if(freqBase < 1000000.0) { | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				m_unitStr = QObject::tr("kHz"); | 
					
						
							|  |  |  | 				m_scale = 1000.0; | 
					
						
							| 
									
										
										
										
											2015-06-21 12:46:47 +02:00
										 |  |  | 			} else if(freqBase < 1000000000.0) { | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				m_unitStr = QObject::tr("MHz"); | 
					
						
							|  |  |  | 				m_scale = 1000000.0; | 
					
						
							| 
									
										
										
										
											2015-06-21 12:46:47 +02:00
										 |  |  | 			} else if(freqBase < 1000000000000.0){ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				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("°"); | 
					
						
							| 
									
										
										
										
											2015-07-06 09:17:51 +02:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		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; | 
					
						
							| 
									
										
										
										
											2015-07-06 09:17:51 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		case Unit::Volt: | 
					
						
							|  |  |  | 			if (median < 1e-9) { | 
					
						
							|  |  |  | 				m_unitStr = QString("pV"); | 
					
						
							|  |  |  | 				m_scale = 1e-12; | 
					
						
							|  |  |  | 			} else if (median < 1e-6) { | 
					
						
							|  |  |  | 				m_unitStr = QString("nV"); | 
					
						
							|  |  |  | 				m_scale = 1e-9; | 
					
						
							|  |  |  | 			} else if (median < 1e-3) { | 
					
						
							|  |  |  | 				m_unitStr = QString("µV"); | 
					
						
							|  |  |  | 				m_scale = 1e-6; | 
					
						
							|  |  |  | 			} else if (median < 1.0) { | 
					
						
							|  |  |  | 				m_unitStr = QString("mV"); | 
					
						
							|  |  |  | 				m_scale = 1e-3; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				m_unitStr = QString("V"); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							|  |  |  | } |