File indexing completed on 2025-01-26 03:34:10
0001 /* 0002 File : CartesianScale.cpp 0003 Project : LabPlot 0004 Description : Cartesian coordinate system for plots. 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2012-2016 Alexander Semke <alexander.semke@web.de> 0007 SPDX-FileCopyrightText: 2020-2021 Stefan Gerlach <stefan.gerlach@uni.kn> 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later 0010 */ 0011 0012 #include "CartesianScale.h" 0013 0014 #include <gsl/gsl_math.h> 0015 0016 /** 0017 * \class CartesianScale 0018 * \brief Base class for cartesian coordinate system scales. 0019 */ 0020 CartesianScale::CartesianScale(const Range<double>& range, double a, double b, double c) 0021 : m_range(range) 0022 , m_a(a) 0023 , m_b(b) 0024 , m_c(c) { 0025 } 0026 0027 CartesianScale::~CartesianScale() = default; 0028 0029 void CartesianScale::getProperties(Range<double>* range, double* a, double* b, double* c) const { 0030 if (range) 0031 *range = m_range; 0032 if (a) 0033 *a = m_a; 0034 if (b) 0035 *b = m_b; 0036 if (c) 0037 *c = m_c; 0038 } 0039 0040 /** 0041 * \class CartesianCoordinateSystem::LinearScale 0042 * \brief implementation of a linear scale for cartesian coordinate systems 0043 * y = b * x + a. a - offset, b - gradient 0044 */ 0045 class LinearScale : public CartesianScale { 0046 public: 0047 LinearScale(const Range<double>& range, double offset, double gradient) 0048 : CartesianScale(range, offset, gradient, 0) { 0049 Q_ASSERT(gradient != 0.0); 0050 } 0051 0052 ~LinearScale() override = default; 0053 0054 bool map(double* value) const override { 0055 *value = *value * m_b + m_a; 0056 return true; 0057 } 0058 0059 bool inverseMap(double* value) const override { 0060 *value = (*value - m_a) / m_b; 0061 return true; 0062 } 0063 0064 int direction() const override { 0065 return m_b < 0 ? -1 : 1; 0066 } 0067 }; 0068 0069 /** 0070 * \class CartesianCoordinateSystem::LogScale 0071 * \brief implementation of a logarithmic scale for cartesian coordinate systems 0072 * y = TODO. a - offset, b - scaleFactor, c - base 0073 */ 0074 class LogScale : public CartesianScale { 0075 public: 0076 LogScale(const Range<double>& range, double offset, double scaleFactor, double base) 0077 : CartesianScale(range, offset, scaleFactor, base) { 0078 Q_ASSERT(scaleFactor != 0.0); 0079 Q_ASSERT(base > 0.0); 0080 } 0081 0082 ~LogScale() override = default; 0083 0084 bool map(double* value) const override { 0085 CHECK(*value > 0) 0086 0087 *value = log(*value) / log(m_c) * m_b + m_a; 0088 0089 return true; 0090 } 0091 0092 bool inverseMap(double* value) const override { 0093 *value = pow(m_c, (*value - m_a) / m_b); 0094 return true; 0095 } 0096 int direction() const override { 0097 return m_b < 0 ? -1 : 1; 0098 } 0099 }; 0100 0101 /** 0102 * \class CartesianCoordinateSystem::SqrtScale 0103 * \brief implementation of a square-root scale for cartesian coordinate systems 0104 * y = TODO. a - offset, b - scaleFactor 0105 */ 0106 class SqrtScale : public CartesianScale { 0107 public: 0108 SqrtScale(const Range<double>& range, double offset, double scaleFactor) 0109 : CartesianScale(range, offset, scaleFactor, 0) { 0110 Q_ASSERT(scaleFactor != 0.0); 0111 } 0112 0113 ~SqrtScale() override = default; 0114 0115 bool map(double* value) const override { 0116 CHECK(*value >= 0) 0117 *value = sqrt(*value) * m_b + m_a; 0118 return true; 0119 } 0120 0121 bool inverseMap(double* value) const override { 0122 *value = gsl_pow_2((*value - m_a) / m_b); 0123 return true; 0124 } 0125 int direction() const override { 0126 return m_b < 0 ? -1 : 1; 0127 } 0128 }; 0129 0130 /** 0131 * \class CartesianCoordinateSystem::SquareScale 0132 * \brief implementation of a square scale for cartesian coordinate systems 0133 * y = TODO. a - offset, b - scaleFactor 0134 */ 0135 class SquareScale : public CartesianScale { 0136 public: 0137 SquareScale(const Range<double>& range, double offset, double scaleFactor) 0138 : CartesianScale(range, offset, scaleFactor, 0) { 0139 Q_ASSERT(scaleFactor != 0.0); 0140 } 0141 0142 ~SquareScale() override = default; 0143 0144 bool map(double* value) const override { 0145 *value = gsl_pow_2(*value) * m_b + m_a; 0146 return true; 0147 } 0148 0149 bool inverseMap(double* value) const override { 0150 *value = std::sqrt(std::abs((*value - m_a) / m_b)); 0151 return true; 0152 } 0153 int direction() const override { 0154 return m_b < 0 ? -1 : 1; 0155 } 0156 }; 0157 0158 /** 0159 * \class CartesianCoordinateSystem::InverseScale 0160 * \brief implementation of an inverse scale for cartesian coordinate systems 0161 * y = TODO. a - offset, b - scaleFactor 0162 */ 0163 class InverseScale : public CartesianScale { 0164 public: 0165 InverseScale(const Range<double>& range, double offset, double scaleFactor) 0166 : CartesianScale(range, offset, scaleFactor, 0) { 0167 Q_ASSERT(scaleFactor != 0.0); 0168 } 0169 0170 ~InverseScale() override = default; 0171 0172 bool map(double* value) const override { 0173 CHECK(*value != 0) 0174 0175 *value = m_b / (*value) + m_a; 0176 return true; 0177 } 0178 0179 bool inverseMap(double* value) const override { 0180 CHECK(*value != m_a) 0181 0182 *value = m_b / (*value - m_a); 0183 return true; 0184 } 0185 int direction() const override { 0186 return m_b < 0 ? -1 : 1; 0187 } 0188 }; 0189 0190 /***************************************************************/ 0191 0192 CartesianScale* CartesianScale::createLinearScale(const Range<double>& range, const Range<double>& sceneRange, const Range<double>& logicalRange) { 0193 if (logicalRange.size() == 0.0) 0194 return nullptr; 0195 0196 double b = sceneRange.size() / logicalRange.size(); 0197 double a = sceneRange.start() - b * logicalRange.start(); 0198 0199 return new LinearScale(range, a, b); 0200 } 0201 0202 CartesianScale* 0203 CartesianScale::createLogScale(const Range<double>& range, const Range<double>& sceneRange, const Range<double>& logicalRange, RangeT::Scale scale) { 0204 if (logicalRange.start() <= 0.0 || logicalRange.end() <= 0.0 || logicalRange.isZero()) { 0205 DEBUG(Q_FUNC_INFO << ", WARNING: invalid range for log scale : " << logicalRange.toStdString()) 0206 return nullptr; 0207 } 0208 0209 double base; 0210 if (scale == RangeT::Scale::Log10) 0211 base = 10.0; 0212 else if (scale == RangeT::Scale::Log2) 0213 base = 2.0; 0214 else // RangeT::Scale::Ln 0215 base = M_E; 0216 0217 const double lDiff = (log(logicalRange.end()) - log(logicalRange.start())) / log(base); 0218 double b = sceneRange.size() / lDiff; 0219 double a = sceneRange.start() - b * log(logicalRange.start()) / log(base); 0220 0221 return new LogScale(range, a, b, base); 0222 } 0223 0224 CartesianScale* CartesianScale::createSqrtScale(const Range<double>& range, const Range<double>& sceneRange, const Range<double>& logicalRange) { 0225 if (logicalRange.start() < 0.0 || logicalRange.end() < 0.0 || logicalRange.isZero()) { 0226 DEBUG(Q_FUNC_INFO << ", WARNING: invalid range for sqrt scale : " << logicalRange.toStdString()) 0227 return nullptr; 0228 } 0229 0230 const double lDiff = sqrt(logicalRange.end()) - sqrt(logicalRange.start()); 0231 double b = sceneRange.size() / lDiff; 0232 double a = sceneRange.start() - b * sqrt(logicalRange.start()); 0233 0234 return new SqrtScale(range, a, b); 0235 } 0236 0237 CartesianScale* CartesianScale::createSquareScale(const Range<double>& range, const Range<double>& sceneRange, const Range<double>& logicalRange) { 0238 const double lDiff = logicalRange.end() * logicalRange.end() - logicalRange.start() * logicalRange.start(); 0239 double b = sceneRange.size() / lDiff; 0240 double a = sceneRange.start() - b * logicalRange.start() * logicalRange.start(); 0241 0242 return new SquareScale(range, a, b); 0243 } 0244 0245 CartesianScale* CartesianScale::createInverseScale(const Range<double>& range, const Range<double>& sceneRange, const Range<double>& logicalRange) { 0246 const double lDiff = 1. / logicalRange.end() - 1. / logicalRange.start(); 0247 double b = sceneRange.size() / lDiff; 0248 double a = sceneRange.start() - b / logicalRange.start(); 0249 0250 return new InverseScale(range, a, b); 0251 }