File indexing completed on 2024-05-12 03:47:30

0001 /*
0002     File                 : Transform.cpp
0003     Project              : LabPlot
0004     Description          : transformation for mapping between scene and
0005     logical coordinates of Datapicker-image
0006     --------------------------------------------------------------------
0007     SPDX-FileCopyrightText: 2015 Ankit Wagadre <wagadre.ankit@gmail.com>
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "Transform.h"
0012 
0013 #include "backend/nsl/nsl_math.h"
0014 #include <gsl/gsl_math.h>
0015 // TODO: replace with GSL or better methods
0016 #include <cmath>
0017 
0018 // Transform::Transform() = default;
0019 
0020 bool Transform::mapTypeToCartesian(const DatapickerImage::ReferencePoints& axisPoints) {
0021     switch (axisPoints.type) {
0022     case DatapickerImage::GraphType::LnX: {
0023         for (int i = 0; i < 3; ++i) {
0024             if (axisPoints.logicalPos[i].x() <= 0)
0025                 return false;
0026             x[i] = log(axisPoints.logicalPos[i].x());
0027             y[i] = axisPoints.logicalPos[i].y();
0028         }
0029         break;
0030     }
0031     case DatapickerImage::GraphType::LnY: {
0032         for (int i = 0; i < 3; ++i) {
0033             if (axisPoints.logicalPos[i].y() <= 0)
0034                 return false;
0035             x[i] = axisPoints.logicalPos[i].x();
0036             y[i] = log(axisPoints.logicalPos[i].y());
0037         }
0038         break;
0039     }
0040     case DatapickerImage::GraphType::LnXY: {
0041         for (int i = 0; i < 3; ++i) {
0042             if (axisPoints.logicalPos[i].x() <= 0)
0043                 return false;
0044             x[i] = log(axisPoints.logicalPos[i].x());
0045             y[i] = log(axisPoints.logicalPos[i].y());
0046         }
0047         break;
0048     }
0049     case DatapickerImage::GraphType::Log10X: {
0050         for (int i = 0; i < 3; ++i) {
0051             if (axisPoints.logicalPos[i].x() <= 0)
0052                 return false;
0053             x[i] = log10(axisPoints.logicalPos[i].x());
0054             y[i] = axisPoints.logicalPos[i].y();
0055         }
0056         break;
0057     }
0058     case DatapickerImage::GraphType::Log10Y: {
0059         for (int i = 0; i < 3; ++i) {
0060             if (axisPoints.logicalPos[i].y() <= 0)
0061                 return false;
0062             x[i] = axisPoints.logicalPos[i].x();
0063             y[i] = log10(axisPoints.logicalPos[i].y());
0064         }
0065         break;
0066     }
0067     case DatapickerImage::GraphType::Log10XY: {
0068         for (int i = 0; i < 3; ++i) {
0069             if (axisPoints.logicalPos[i].x() <= 0)
0070                 return false;
0071             x[i] = log10(axisPoints.logicalPos[i].x());
0072             y[i] = log10(axisPoints.logicalPos[i].y());
0073         }
0074         break;
0075     }
0076     case DatapickerImage::GraphType::PolarInDegree: {
0077         for (int i = 0; i < 3; ++i) {
0078             if (axisPoints.logicalPos[i].x() < 0)
0079                 return false;
0080             x[i] = axisPoints.logicalPos[i].x() * cos(axisPoints.logicalPos[i].y() * M_PI_180);
0081             y[i] = axisPoints.logicalPos[i].x() * sin(axisPoints.logicalPos[i].y() * M_PI_180);
0082         }
0083         break;
0084     }
0085     case DatapickerImage::GraphType::PolarInRadians: {
0086         for (int i = 0; i < 3; ++i) {
0087             if (axisPoints.logicalPos[i].x() < 0)
0088                 return false;
0089             x[i] = axisPoints.logicalPos[i].x() * cos(axisPoints.logicalPos[i].y());
0090             y[i] = axisPoints.logicalPos[i].x() * sin(axisPoints.logicalPos[i].y());
0091         }
0092         break;
0093     }
0094     case DatapickerImage::GraphType::Ternary: {
0095         for (int i = 0; i < 3; ++i) {
0096             x[i] = (2 * axisPoints.logicalPos[i].y() + axisPoints.logicalPos[i].z()) / (2 * axisPoints.ternaryScale);
0097             y[i] = (M_SQRT3 * axisPoints.logicalPos[i].z()) / (2 * axisPoints.ternaryScale);
0098         }
0099         break;
0100     }
0101     case DatapickerImage::GraphType::Linear: {
0102         for (int i = 0; i < 3; ++i) {
0103             x[i] = axisPoints.logicalPos[i].x();
0104             y[i] = axisPoints.logicalPos[i].y();
0105         }
0106         break;
0107     }
0108     }
0109 
0110     for (int i = 0; i < 3; i++) {
0111         X[i] = axisPoints.scenePos[i].x();
0112         Y[i] = axisPoints.scenePos[i].y();
0113     }
0114 
0115     return true;
0116 }
0117 
0118 Vector3D Transform::mapSceneToLogical(QPointF scenePoint, const DatapickerImage::ReferencePoints& axisPoints) {
0119     X[3] = scenePoint.x();
0120     Y[3] = scenePoint.y();
0121 
0122     if (mapTypeToCartesian(axisPoints)) {
0123         double sin;
0124         double cos;
0125         double scaleOfX;
0126         double scaleOfY;
0127         if (((Y[1] - Y[0]) * (x[2] - x[0]) - (Y[2] - Y[0]) * (x[1] - x[0])) != 0) {
0128             double tan = ((X[1] - X[0]) * (x[2] - x[0]) - (X[2] - X[0]) * (x[1] - x[0])) / ((Y[1] - Y[0]) * (x[2] - x[0]) - (Y[2] - Y[0]) * (x[1] - x[0]));
0129             sin = tan / sqrt(1 + tan * tan);
0130             cos = sqrt(1 - sin * sin);
0131         } else {
0132             sin = 1;
0133             cos = 0;
0134         }
0135 
0136         if ((x[1] - x[0]) != 0)
0137             scaleOfX = (x[1] - x[0]) / ((X[1] - X[0]) * cos - (Y[1] - Y[0]) * sin);
0138         else
0139             scaleOfX = (x[2] - x[0]) / ((X[2] - X[0]) * cos - (Y[2] - Y[0]) * sin);
0140 
0141         if ((y[1] - y[0]) != 0)
0142             scaleOfY = (y[1] - y[0]) / ((X[1] - X[0]) * sin + (Y[1] - Y[0]) * cos);
0143         else
0144             scaleOfY = (y[2] - y[0]) / ((X[2] - X[0]) * sin + (Y[2] - Y[0]) * cos);
0145 
0146         x[3] = x[0] + (((X[3] - X[0]) * cos - (Y[3] - Y[0]) * sin) * scaleOfX);
0147         y[3] = y[0] + (((X[3] - X[0]) * sin + (Y[3] - Y[0]) * cos) * scaleOfY);
0148         return mapCartesianToType(QPointF(x[3], y[3]), axisPoints);
0149     }
0150     return {};
0151 }
0152 
0153 Vector3D Transform::mapSceneLengthToLogical(QPointF errorSpan, const DatapickerImage::ReferencePoints& axisPoints) {
0154     return mapSceneToLogical(errorSpan, axisPoints) - mapSceneToLogical(QPointF(0, 0), axisPoints);
0155 }
0156 
0157 Vector3D Transform::mapCartesianToType(QPointF point, const DatapickerImage::ReferencePoints& axisPoints) const {
0158     switch (axisPoints.type) {
0159     case DatapickerImage::GraphType::Linear:
0160         return Vector3D(point.x(), point.y(), 0);
0161     case DatapickerImage::GraphType::LnXY:
0162         return Vector3D(exp(point.x()), exp(point.y()), 0);
0163     case DatapickerImage::GraphType::LnX:
0164         return Vector3D(exp(point.x()), point.y(), 0);
0165     case DatapickerImage::GraphType::LnY:
0166         return Vector3D(point.x(), exp(point.y()), 0);
0167     case DatapickerImage::GraphType::Log10XY:
0168         return Vector3D(pow(10, point.x()), pow(10, point.y()), 0);
0169     case DatapickerImage::GraphType::Log10X:
0170         return Vector3D(pow(10, point.x()), point.y(), 0);
0171     case DatapickerImage::GraphType::Log10Y:
0172         return Vector3D(point.x(), pow(10, point.y()), 0);
0173     case DatapickerImage::GraphType::PolarInDegree: {
0174         double r = sqrt(point.x() * point.x() + point.y() * point.y());
0175         double angle = atan(point.y() / point.x()) * M_180_PI;
0176         return Vector3D(r, angle, 0);
0177     }
0178     case DatapickerImage::GraphType::PolarInRadians: {
0179         double r = sqrt(point.x() * point.x() + point.y() * point.y());
0180         double angle = atan(point.y() / point.x());
0181         return Vector3D(r, angle, 0);
0182     }
0183     case DatapickerImage::GraphType::Ternary: {
0184         double c = (point.y() * 2 * axisPoints.ternaryScale) / M_SQRT3;
0185         double b = (point.x() * 2 * axisPoints.ternaryScale - c) / 2;
0186         double a = axisPoints.ternaryScale - b - c;
0187         return Vector3D(a, b, c);
0188     }
0189     }
0190     return Vector3D(point.x(), point.y(), 0); // should never happen
0191 }