File indexing completed on 2024-05-12 15:26:43

0001 /***************************************************************************
0002     File                 : Transform.cpp
0003     Project              : LabPlot
0004     Description          : transformation for mapping between scene and
0005                            logical coordinates of Datapicker-image
0006     --------------------------------------------------------------------
0007     Copyright            : (C) 2015 by Ankit Wagadre (wagadre.ankit@gmail.com)
0008  ***************************************************************************/
0009 /***************************************************************************
0010  *                                                                         *
0011  *  This program is free software; you can redistribute it and/or modify   *
0012  *  it under the terms of the GNU General Public License as published by   *
0013  *  the Free Software Foundation; either version 2 of the License, or      *
0014  *  (at your option) any later version.                                    *
0015  *                                                                         *
0016  *  This program is distributed in the hope that it will be useful,        *
0017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0019  *  GNU General Public License for more details.                           *
0020  *                                                                         *
0021  *   You should have received a copy of the GNU General Public License     *
0022  *   along with this program; if not, write to the Free Software           *
0023  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0024  *   Boston, MA  02110-1301  USA                                           *
0025  *                                                                         *
0026  ***************************************************************************/
0027 
0028 #include "Transform.h"
0029 //TODO: replace with GSL or better methods
0030 #include <cmath>
0031 
0032 extern "C" {
0033 #include <gsl/gsl_math.h>
0034 #include "backend/nsl/nsl_math.h"
0035 }
0036 
0037 //Transform::Transform() = default;
0038 
0039 bool Transform::mapTypeToCartesian(const DatapickerImage::ReferencePoints& axisPoints) {
0040     if (axisPoints.type == DatapickerImage::GraphType::LogarithmicX) {
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] = axisPoints.logicalPos[i].y();
0046             X[i] = axisPoints.scenePos[i].x();
0047             Y[i] = axisPoints.scenePos[i].y();
0048         }
0049     } else if (axisPoints.type == DatapickerImage::GraphType::LogarithmicY) {
0050         for (int i = 0; i < 3; ++i) {
0051             if (axisPoints.logicalPos[i].y() <= 0)
0052                 return false;
0053             x[i] = axisPoints.logicalPos[i].x();
0054             y[i] = log(axisPoints.logicalPos[i].y());
0055             X[i] = axisPoints.scenePos[i].x();
0056             Y[i] = axisPoints.scenePos[i].y();
0057         }
0058     } else if (axisPoints.type == DatapickerImage::GraphType::PolarInDegree) {
0059         for (int i = 0; i < 3; ++i) {
0060             if (axisPoints.logicalPos[i].x() < 0)
0061                 return false;
0062             x[i] = axisPoints.logicalPos[i].x()*cos(axisPoints.logicalPos[i].y() * M_PI_180);
0063             y[i] = axisPoints.logicalPos[i].x()*sin(axisPoints.logicalPos[i].y() * M_PI_180);
0064             X[i] = axisPoints.scenePos[i].x();
0065             Y[i] = axisPoints.scenePos[i].y();
0066         }
0067     } else if (axisPoints.type == DatapickerImage::GraphType::PolarInRadians) {
0068         for (int i = 0; i < 3; ++i) {
0069             if (axisPoints.logicalPos[i].x() < 0)
0070                 return false;
0071             x[i] = axisPoints.logicalPos[i].x()*cos(axisPoints.logicalPos[i].y());
0072             y[i] = axisPoints.logicalPos[i].x()*sin(axisPoints.logicalPos[i].y());
0073             X[i] = axisPoints.scenePos[i].x();
0074             Y[i] = axisPoints.scenePos[i].y();
0075         }
0076     } else if (axisPoints.type == DatapickerImage::GraphType::Ternary) {
0077         for (int i = 0; i < 3; ++i) {
0078             x[i] = (2*axisPoints.logicalPos[i].y() + axisPoints.logicalPos[i].z())/(2*axisPoints.ternaryScale);
0079             y[i] = (M_SQRT3 * axisPoints.logicalPos[i].z())/(2*axisPoints.ternaryScale);
0080             X[i] = axisPoints.scenePos[i].x();
0081             Y[i] = axisPoints.scenePos[i].y();
0082         }
0083     } else {
0084         for (int i = 0; i < 3; ++i) {
0085             x[i] = axisPoints.logicalPos[i].x();
0086             y[i] = axisPoints.logicalPos[i].y();
0087             X[i] = axisPoints.scenePos[i].x();
0088             Y[i] = axisPoints.scenePos[i].y();
0089         }
0090     }
0091 
0092     return true;
0093 }
0094 
0095 QVector3D Transform::mapSceneToLogical(QPointF scenePoint, const DatapickerImage::ReferencePoints& axisPoints) {
0096     X[3] = scenePoint.x();
0097     Y[3] = scenePoint.y();
0098 
0099     if (mapTypeToCartesian(axisPoints)) {
0100         double sin;
0101         double cos;
0102         double scaleOfX;
0103         double scaleOfY;
0104         if (((Y[1] - Y[0])*(x[2] - x[0]) - (Y[2] - Y[0])*(x[1] - x[0])) != 0) {
0105             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]));
0106             sin = tan/sqrt(1 + tan*tan);
0107             cos = sqrt(1 - sin*sin);
0108         } else {
0109             sin = 1;
0110             cos = 0;
0111         }
0112 
0113         if ((x[1] - x[0]) != 0) {
0114             scaleOfX = (x[1] - x[0])/((X[1] - X[0])*cos - (Y[1] - Y[0])*sin);
0115         } else {
0116             scaleOfX = (x[2] - x[0])/((X[2] - X[0])*cos - (Y[2] - Y[0])*sin);
0117         }
0118 
0119         if ((y[1]-y[0]) != 0) {
0120             scaleOfY = (y[1] - y[0])/((X[1] - X[0])*sin + (Y[1] - Y[0])*cos);
0121         } else {
0122             scaleOfY = (y[2] - y[0])/((X[2] - X[0])*sin + (Y[2] - Y[0])*cos);
0123         }
0124 
0125         x[3] = x[0] + (((X[3] - X[0])*cos - (Y[3] - Y[0])*sin)*scaleOfX);
0126         y[3] = y[0] + (((X[3] - X[0])*sin + (Y[3] - Y[0])*cos)*scaleOfY);
0127         return mapCartesianToType(QPointF(x[3], y[3]), axisPoints);
0128     }
0129     return QVector3D{};
0130 }
0131 
0132 QVector3D Transform::mapSceneLengthToLogical(QPointF errorSpan, const DatapickerImage::ReferencePoints& axisPoints) {
0133     return mapSceneToLogical(errorSpan, axisPoints) - mapSceneToLogical(QPointF(0,0), axisPoints);
0134 }
0135 
0136 QVector3D Transform::mapCartesianToType(QPointF point, const DatapickerImage::ReferencePoints &axisPoints) const {
0137     if (axisPoints.type == DatapickerImage::GraphType::LogarithmicX) {
0138         return QVector3D(exp(point.x()), point.y(), 0);
0139     } else if (axisPoints.type == DatapickerImage::GraphType::LogarithmicY) {
0140         return QVector3D(point.x(), exp(point.y()), 0);
0141     } else if (axisPoints.type == DatapickerImage::GraphType::PolarInDegree) {
0142         double r = sqrt(point.x()*point.x() + point.y()*point.y());
0143         double angle = atan(point.y() / point.x() * M_180_PI);
0144         return QVector3D(r, angle, 0);
0145     } else if (axisPoints.type == DatapickerImage::GraphType::PolarInRadians) {
0146         double r = sqrt(point.x()*point.x() + point.y()*point.y());
0147         double angle = atan(point.y()/point.x());
0148         return QVector3D(r, angle, 0);
0149     } else if (axisPoints.type == DatapickerImage::GraphType::Ternary) {
0150         double c = (point.y()*2*axisPoints.ternaryScale)/M_SQRT3;
0151         double b = (point.x()*2*axisPoints.ternaryScale - c)/2;
0152         double a = axisPoints.ternaryScale - b - c;
0153         return QVector3D(a, b, c);
0154     } else {
0155         return QVector3D(point.x(), point.y(), 0);
0156     }
0157 }
0158