Engauge Digitizer 2
Loading...
Searching...
No Matches
GuidelineProjectorConstantT.cpp
Go to the documentation of this file.
1/******************************************************************************************************
2 * (C) 2019 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
3 * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4 * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
5 ******************************************************************************************************/
6
7#include <algorithm>
9#include <QList>
10#include <qmath.h>
11#include <QRectF>
12#include "Transformation.h"
13
17
21
23 const QRectF &sceneRect,
24 double thetaGraphDegrees)
25{
26 QPointF posGraphBL, posGraphTL, posGraphTR, posGraphBR;
27 calculateCorners (transformation,
28 sceneRect,
29 posGraphBL,
30 posGraphTL,
31 posGraphTR,
32 posGraphBR);
33
34 // These containers would be QVector2D to emphasize we are not working with x and y valuees, but
35 // QVector2D would give double/float conversion errors
36 QPointF anglesLeft (qMin (posGraphBL.x(), posGraphTL.x()),
37 qMax (posGraphBL.x(), posGraphTL.x()));
38 QPointF anglesTop (qMin (posGraphTL.x(), posGraphTR.x()),
39 qMax (posGraphTL.x(), posGraphTR.x()));
40 QPointF anglesRight (qMin (posGraphTR.x(), posGraphBR.x()),
41 qMax (posGraphTR.x(), posGraphBR.x()));
42 QPointF anglesBottom (qMin (posGraphBR.x(), posGraphBL.x()),
43 qMax (posGraphBR.x(), posGraphBL.x()));
44
45 // Fix any side that crosses over the discontinuous transition
46 if (qAbs (anglesLeft.y() - anglesLeft.x()) > 180.0) {
47 double temp = anglesLeft.x();
48 anglesLeft.setX (anglesLeft.y());
49 anglesLeft.setY (temp + 360.0);
50 }
51 if (qAbs (anglesTop.y() - anglesTop.x()) > 180.0) {
52 double temp = anglesTop.x();
53 anglesTop.setX (anglesTop.y());
54 anglesTop.setY (temp + 360.0);
55 }
56 if (qAbs (anglesRight.y() - anglesRight.x()) > 180.0) {
57 double temp = anglesRight.x();
58 anglesRight.setX (anglesRight.y());
59 anglesRight.setY (temp + 360.0);
60 }
61 if (qAbs (anglesBottom.y() - anglesBottom.x()) > 180.0) {
62 double temp = anglesBottom.x();
63 anglesBottom.setX (anglesBottom.y());
64 anglesBottom.setY (temp + 360.0);
65 }
66
67 // Which side matches theta?
68 QLineF line;
69 double thetaGraphPlus = thetaGraphDegrees + 360.0;
70 if ((anglesLeft.x() <= thetaGraphDegrees && thetaGraphDegrees <= anglesLeft.y()) ||
71 (anglesLeft.x() <= thetaGraphPlus && thetaGraphPlus <= anglesLeft.y())) {
72
73 // Left side
74 line = intersect (transformation,
75 thetaGraphDegrees,
76 posGraphBL,
77 posGraphTL);
78
79 } else if ((anglesTop.x() <= thetaGraphDegrees && thetaGraphDegrees <= anglesTop.y()) ||
80 (anglesTop.x() <= thetaGraphPlus && thetaGraphPlus <= anglesTop.y())) {
81
82 // Top side
83 line = intersect (transformation,
84 thetaGraphDegrees,
85 posGraphTL,
86 posGraphTR);
87
88 } else if ((anglesRight.x() <= thetaGraphDegrees && thetaGraphDegrees <= anglesRight.y()) ||
89 (anglesRight.x() <= thetaGraphPlus && thetaGraphPlus <= anglesRight.y())) {
90
91 // Right side
92 line = intersect (transformation,
93 thetaGraphDegrees,
94 posGraphTR,
95 posGraphBR);
96
97 } else {
98
99 // Bottom side
100 line = intersect (transformation,
101 thetaGraphDegrees,
102 posGraphBR,
103 posGraphBL);
104
105 }
106
107 return line;
108}
109
111 const QRectF &sceneRect,
112 const QPointF &posScreen)
113{
114 QPointF posGraph;
115 transformation.transformScreenToRawGraph (posScreen, posGraph);
116
117 return fromCoordinateT (transformation,
118 sceneRect,
119 posGraph.x());
120}
121
122QLineF GuidelineProjectorConstantT::intersect (const Transformation &transformation,
123 double thetaGraphDegrees,
124 const QPointF &posPolar1,
125 const QPointF &posPolar2) const
126{
127 QPointF p1, p2; // Cartesian coordinates
128 transformation.transformRawGraphToLinearCartesianGraph (posPolar1,
129 p1);
130 transformation.transformRawGraphToLinearCartesianGraph (posPolar2,
131 p2);
132
133 // Intersect y = x tan (theta) = slope * x
134 // (x - x0) / (x1 - x0) = (y - y0) / (y1 - y0)
135 // with divide by zero errors prevented by treating the second equation as either
136 // OPTION 1 (x - x0) = [(x1 - x0) / (y1 - y0)] * (y - y0)
137 // or
138 // OPTION 2 (y - y0) = [(y1 - y0) / (x1 - x0)] * (x - x0)
139
140 double deltaX = p2.x() - p1.x();
141 double deltaY = p2.y() - p1.y();
142
143 double x, y;
144 if (qAbs (deltaX) < qAbs (deltaY)) {
145
146 // Safe to compute since mostly horizontal
147 double slope = qTan (qDegreesToRadians (thetaGraphDegrees));
148
149 // Use OPTION 1 with x - x0 = fraction * (y - y0)
150 // substituting y = slope * x
151 // we get x * (1 - fraction * slope) = x0 - fraction * y0
152 // since line is mostly vertical (deltaX<deltaY) we know the line y=slope*x
153 // that intersects it is mostly horizontal so it cannot have infinite slope
154 // so the following code has no way to overflow (by inspection)
155 double fraction = deltaX / deltaY;
156 x = (p1.x () - fraction * p1.y ()) / (1.0 - fraction * slope);
157 y = slope * x;
158
159 } else {
160
161 // Safe to compute since mostly vertical. Derived from tan(theta)=y/x and tan(90-theta)=x/y
162 double slopeInverse = qTan (qDegreesToRadians (90.0 - thetaGraphDegrees));
163
164 // Use OPTION 2 with y - y0 = fraction * (x - x0)
165 // substituting x = y / slope
166 // we get y * (1 - fraction / slope) = y0 - fraction * x0
167 // since line is mostly horizontal (deltaY<deltaX) we know the line y=slope*x
168 // that intersects it is mostly vertical so it cannot have zero slope
169 // so the following code has no way to overflow (by inspection)
170 double fraction = deltaY / deltaX;
171 y = (p1.y () - fraction * p1.x ()) / (1.0 - fraction * slopeInverse);
172 x = slopeInverse * y;
173 }
174
175 QPointF posGraphCenter (0, 0);
176 if (transformation.modelCoords().coordScaleYRadius() == COORD_SCALE_LOG) {
177 posGraphCenter = QPointF (0,
178 transformation.modelCoords().originRadius());
179 }
180
181 // Convert graph coordinate points into screen coordinate line
182 QPointF posSceneCenter, posSceneOther;
183 transformation.transformRawGraphToScreen (posGraphCenter,
184 posSceneCenter);
185 transformation.transformLinearCartesianGraphToScreen (QPointF (x, y),
186 posSceneOther);
187
188 return QLineF (posSceneCenter,
189 posSceneOther);
190}
@ COORD_SCALE_LOG
Definition CoordScale.h:14
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
double originRadius() const
Get method for origin radius in polar mode.
void calculateCorners(const Transformation &transformation, const QRectF &sceneRect, QPointF &posGraphBL, QPointF &posGraphTL, QPointF &posGraphTR, QPointF &posGraphBR) const
Conpute four corners of scene in graph coordinates.
QLineF fromPosScreen(const Transformation &transformation, const QRectF &sceneRect, const QPointF &posScreen)
Return line through point in screen coordinates.
QLineF fromCoordinateT(const Transformation &transformation, const QRectF &sceneRect, double tGraph)
Return line through theta in graph coordinates.
Affine transformation between screen and graph coordinates, based on digitized axis points.
void transformRawGraphToScreen(const QPointF &pointRaw, QPointF &pointScreen) const
Transform from raw graph coordinates to linear cartesian graph coordinates, then to screen coordinate...
void transformScreenToRawGraph(const QPointF &coordScreen, QPointF &coordGraph) const
Transform from cartesian pixel screen coordinates to cartesian/polar graph coordinates.
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
void transformRawGraphToLinearCartesianGraph(const QPointF &pointRaw, QPointF &pointLinearCartesian) const
Convert graph coordinates (linear or log, cartesian or polar) to linear cartesian coordinates.
void transformLinearCartesianGraphToScreen(const QPointF &coordGraph, QPointF &coordScreen) const
Transform from linear cartesian graph coordinates to cartesian pixel screen coordinates.