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 }