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 }