Engauge Digitizer 2
Loading...
Searching...
No Matches
CentipedeDebugPolar.cpp
Go to the documentation of this file.
1/******************************************************************************************************
2 * (C) 2020 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
9#include "Logger.h"
10#include "mmsubs.h"
11#include <QColor>
12#include <qdebug.h>
13#include <QGraphicsEllipseItem>
14#include <QGraphicsPolygonItem>
15#include <QGraphicsRectItem>
16#include <QGraphicsScene>
17#include <qmath.h>
18#include "QtToString.h"
19#include "Transformation.h"
20
22 m_posScreenParallelogramTL (0, 0),
23 m_posScreenParallelogramTR (0, 0),
24 m_posScreenParallelogramBL (0, 0),
25 m_posScreenParallelogramBR (0, 0),
26 m_angleGraphAxisFromScreenAxis (0),
27 m_angleEllipseFromMajorAxis (0),
28 m_aAligned (0),
29 m_bAligned (0),
30 m_radius (0),
31 m_legendYPos (0)
32{
33}
34
36 const QPointF &posScreenParallelogramTR,
37 const QPointF &posScreenParallelogramBL,
38 const QPointF &posScreenParallelogramBR,
41 double aAligned,
42 double bAligned,
43 double radius) :
44 m_posScreenParallelogramTL (posScreenParallelogramTL),
45 m_posScreenParallelogramTR (posScreenParallelogramTR),
46 m_posScreenParallelogramBL (posScreenParallelogramBL),
47 m_posScreenParallelogramBR (posScreenParallelogramBR),
48 m_angleGraphAxisFromScreenAxis (angleGraphAxisFromScreenAxis),
49 m_angleEllipseFromMajorAxis (angleEllipseFromMajorAxis),
50 m_aAligned (aAligned),
51 m_bAligned (bAligned),
52 m_radius (radius),
53 m_legendYPos (0)
54{
55}
56
58 m_posScreenParallelogramTL (other.posScreenParallelogramTL ()),
59 m_posScreenParallelogramTR (other.posScreenParallelogramTR ()),
60 m_posScreenParallelogramBL (other.posScreenParallelogramBL ()),
61 m_posScreenParallelogramBR (other.posScreenParallelogramBR ()),
62 m_angleGraphAxisFromScreenAxis (other.angleGraphAxisFromScreenAxis ()),
63 m_angleEllipseFromMajorAxis (other.angleEllipseFromMajorAxis ()),
64 m_aAligned (other.aAligned ()),
65 m_bAligned (other.bAligned ()),
66 m_radius (other.radius ()),
67 m_legendYPos (0)
68{
69}
70
72{
73 m_posScreenParallelogramTL = other.posScreenParallelogramTL ();
74 m_posScreenParallelogramTR = other.posScreenParallelogramTR ();
75 m_posScreenParallelogramBL = other.posScreenParallelogramBL ();
76 m_posScreenParallelogramBR = other.posScreenParallelogramBR ();
77 m_angleGraphAxisFromScreenAxis = other.angleGraphAxisFromScreenAxis ();
78 m_angleEllipseFromMajorAxis = other.angleEllipseFromMajorAxis ();
79 m_aAligned = other.aAligned ();
80 m_bAligned = other.bAligned ();
81 m_radius = other.radius ();
82 m_legendYPos = 0;
83
84 return *this;
85}
86
90
92{
93 return m_aAligned;
94}
95
96void CentipedeDebugPolar::addToLegend (QGraphicsScene &scene,
97 const QString &entry,
98 const QColor &color)
99{
100 const int LEGEND_X_POS = 5, LEGEND_Y_STEP = 20;
101
102 QGraphicsTextItem *itemGraphCoords = new QGraphicsTextItem (entry);
103 itemGraphCoords->setPos (QPointF (LEGEND_X_POS, LEGEND_Y_STEP * (m_legendYPos++)));
104 itemGraphCoords->setDefaultTextColor (color);
105 scene.addItem (itemGraphCoords);
106}
107
109{
110 return m_angleEllipseFromMajorAxis;
111}
112
114{
115 return m_angleGraphAxisFromScreenAxis;
116}
117
119{
120 return m_bAligned;
121}
122
123void CentipedeDebugPolar::display (QGraphicsScene &scene,
124 const DocumentModelCoords &modelCoords,
125 const Transformation &transformation)
126{
127 // LOG4CPP is below
128
129 if (mainCat->getPriority() == log4cpp::Priority::DEBUG) {
130
131 // Center
132 QPointF posOriginGraph (0, 0), posOriginScreen;
133 if (modelCoords.coordScaleYRadius() == COORD_SCALE_LOG) {
134 posOriginGraph = QPointF (0,
135 modelCoords.originRadius());
136 }
137 transformation.transformRawGraphToScreen (posOriginGraph,
138 posOriginScreen);
139
140 // Circumscribing parallelogram
141 QVector<QPointF> points;
142 points << m_posScreenParallelogramBL;
143 points << m_posScreenParallelogramTL;
144 points << m_posScreenParallelogramTR;
145 points << m_posScreenParallelogramBR;
146 points << m_posScreenParallelogramBL;
147 QGraphicsPolygonItem *parallelogram = new QGraphicsPolygonItem (points);
148 parallelogram->setPen (QPen (Qt::green));
149 addToLegend (scene,
150 QString ("Parallelogram a=%1 b=%2").arg (m_aAligned).arg (m_bAligned),
151 Qt::green);
152 scene.addItem (parallelogram);
153
154 // X axis in circumscribing parallelogram
155 QPointF posAbsolute0 = (m_posScreenParallelogramTR + m_posScreenParallelogramBR) / 2.0;
156 QLineF xAxisLine0 (posOriginScreen,
157 posAbsolute0);
158 QPointF posRelative0 = posAbsolute0 - posOriginScreen;
159 double ang = qDegreesToRadians (45.0);
160 double ca = qCos (ang);
161 double sa = qSin (ang);
162 QLineF xAxisLine45 (posOriginScreen,
163 posOriginScreen + QPointF (ca * posRelative0.x() + sa * posRelative0.y(),
164 -1.0 * sa * posRelative0.x() + ca * posRelative0.y()));
165 QGraphicsLineItem *xAxisParallelogram0 = new QGraphicsLineItem (xAxisLine0);
166 QGraphicsLineItem *xAxisParallelogram45 = new QGraphicsLineItem (xAxisLine45);
167 xAxisParallelogram0->setPen (QPen (Qt::green));
168 xAxisParallelogram45->setPen (QPen (Qt::green));
169 scene.addItem (xAxisParallelogram0);
170 scene.addItem (xAxisParallelogram45);
171
172 // Right-angled rectangle
173 QRectF rect (posOriginScreen.x() - m_aAligned,
174 posOriginScreen.y() - m_bAligned,
175 2 * m_aAligned,
176 2 * m_bAligned);
177 rect.setLeft (posOriginScreen.x() - m_aAligned);
178 rect.setTop (posOriginScreen.y() - m_bAligned);
179
180 // Circumscribing rectangle
181 QGraphicsRectItem *rectItem = new QGraphicsRectItem (rect);
182 rectItem->setTransformOriginPoint(posOriginScreen);
183 rectItem->setRotation (qRadiansToDegrees (m_angleEllipseFromMajorAxis));
184 rectItem->setPen (QPen (Qt::cyan));
185 addToLegend (scene,
186 QString ("Rectangle rotation=%1").arg (qRadiansToDegrees (m_angleEllipseFromMajorAxis)),
187 Qt::cyan);
188 scene.addItem (rectItem);
189
190 // X axis in circumscribing rectangle. Without screen-to-ellipse rotation this would be horizontal
191 QLineF xAxisRectangle (posOriginScreen,
192 (rect.topRight() + rect.bottomRight()) / 2.0);
193 QGraphicsLineItem *xAxisRect = new QGraphicsLineItem (xAxisRectangle);
194 xAxisRect->setTransformOriginPoint (posOriginScreen);
195 xAxisRect->setRotation (m_angleGraphAxisFromScreenAxis);
196 xAxisRect->setPen (QPen (Qt::cyan));
197 scene.addItem (xAxisRect);
198
199 // Put an ellipse in the circumscribing rectangle to see if they line up
200 QGraphicsEllipseItem *ellipse = new QGraphicsEllipseItem (rect);
201 ellipse->setTransformOriginPoint (posOriginScreen);
202 ellipse->setRotation (qRadiansToDegrees (m_angleGraphAxisFromScreenAxis));
203 ellipse->setPen (QPen (Qt::red));
204 scene.addItem (ellipse);
205
206 // A and B axes. These are NOT orthogonal when there is shear
207 QPointF posAAxisGraph (0, m_radius), posBAxisGraph (90, m_radius);
208 QPointF posAAxisScreen, posBAxisScreen;
209 transformation.transformRawGraphToScreen (posAAxisGraph,
210 posAAxisScreen);
211 transformation.transformRawGraphToScreen (posBAxisGraph,
212 posBAxisScreen);
213
214 displayTics (scene,
215 transformation,
216 posOriginScreen,
217 posAAxisScreen,
218 QColor (255, 0, 0),
219 QColor (255, 150, 150));
220
221 // Finish up with details in log stream
222 LOG4CPP_DEBUG_S ((*mainCat)) << "CentipedeDebugPolar::displayTics"
223 << " angleFromAxis=" << qDegreesToRadians (m_angleEllipseFromMajorAxis)
224 << " angleFromScreen=" << qDegreesToRadians (m_angleGraphAxisFromScreenAxis);
225 }
226}
227
228void CentipedeDebugPolar::displayTics (QGraphicsScene &scene,
229 const Transformation &transformation,
230 const QPointF &posOriginScreen,
231 const QPointF &posAAxisScreen,
232 const QColor &colorGraphCoordinates,
233 const QColor &colorScreenCoordinates)
234{
235 const int DEGREES_BETWEEN_HIGHLIGHTS = 10;
236
237 // Legend
238 addToLegend (scene,
239 "Graphics Coords",
240 colorGraphCoordinates);
241 addToLegend (scene,
242 "Screen Coords",
243 colorScreenCoordinates);
244
245 // Orthogonal basis vectors aligned to orthognal axes of ellipse, in screen coordinates
246 QPointF basisX = (posAAxisScreen - posOriginScreen) / magnitude (posAAxisScreen - posOriginScreen);
247 QPointF basisY (basisX.y(),
248 -1.0 * basisX.x());
249
250 // Show one inner set of radial tic lines and one outer set of radial tic lines
251 double cosOffset = qCos (m_angleGraphAxisFromScreenAxis);
252 double sinOffset = qSin (m_angleGraphAxisFromScreenAxis);
253 for (int degrees = 0; degrees < 360; degrees++) {
254
255 QString degreesMinus180ToPlus180 = QString::number (degrees > 180 ?
256 degrees - 360 :
257 degrees);
258
259 // Inner set of radial tic lines is regularly spaced in screen coordinates. We solve x=r*cosT, y=r*sinT,
260 // x^2/a^2 + y^2/b^2 = 1. Ellipse points are then rotated
261 double radians = qDegreesToRadians ((double) degrees) - m_angleEllipseFromMajorAxis;
262 double cosLoop = qCos(-1.0 * radians - m_angleEllipseFromMajorAxis);
263 double sinLoop = qSin(-1.0 * radians - m_angleEllipseFromMajorAxis);
264 double denominator = cosLoop * cosLoop / m_aAligned / m_aAligned + sinLoop * sinLoop / m_bAligned / m_bAligned;
265 double radius = qSqrt (1.0 / denominator);
266 double x = radius * cosLoop;
267 double y = radius * sinLoop;
268 double xRotated = cosOffset * x - sinOffset * y;
269 double yRotated = sinOffset * x + cosOffset * y;
270 QPointF posRadial (xRotated,
271 yRotated);
272
273 QLineF linePortion = portionOfLineLast (QLineF (posOriginScreen,
274 posOriginScreen + posRadial),
275 degrees,
276 DEGREES_BETWEEN_HIGHLIGHTS);
277 QGraphicsLineItem *radialFirst = new QGraphicsLineItem (linePortion);
278 radialFirst->setPen (QPen (colorScreenCoordinates));
279 scene.addItem (radialFirst);
280
281 if (degrees % DEGREES_BETWEEN_HIGHLIGHTS == 0) {
282 QGraphicsTextItem *labelFirst = new QGraphicsTextItem (degreesMinus180ToPlus180);
283 labelFirst->setPos (linePortion.p1());
284 labelFirst->setDefaultTextColor (colorScreenCoordinates);
285 scene.addItem (labelFirst);
286 }
287
288 // Second set of radial tic lines is regularly spaced in graph coordinates
289 transformation.transformRawGraphToScreen (QPointF (degrees,
290 m_radius),
291 posRadial);
292
293 linePortion = portionOfLineNext (QLineF (posOriginScreen,
294 posRadial),
295 degrees,
296 DEGREES_BETWEEN_HIGHLIGHTS);
297 QGraphicsLineItem *radialSecond = new QGraphicsLineItem (linePortion);
298 radialSecond->setPen (QPen (colorGraphCoordinates));
299 scene.addItem (radialSecond);
300
301 if (degrees % DEGREES_BETWEEN_HIGHLIGHTS == 0) {
302 QGraphicsTextItem *labelSecond = new QGraphicsTextItem (degreesMinus180ToPlus180);
303 labelSecond->setPos (linePortion.p1());
304 labelSecond->setDefaultTextColor (colorGraphCoordinates);
305 scene.addItem (labelSecond);
306 }
307 }
308}
309
310void CentipedeDebugPolar::dumpEllipseGraphicsItem (const QString &callerMethod,
311 const QGraphicsEllipseItem *ellipse) const
312{
313 if (mainCat->getPriority () == log4cpp::Priority::DEBUG) {
314
315 LOG4CPP_DEBUG_S ((*mainCat)) << "CentipedeDebugPolar::dumpEllipseGraphicsItem dump from "
316 << callerMethod.toLatin1().data();
317 LOG4CPP_DEBUG_S ((*mainCat)) << " rect=" << QRectFToString (ellipse->rect()).toLatin1().data();
318 LOG4CPP_DEBUG_S ((*mainCat)) << " rotation=" << ellipse->rotation();
319 LOG4CPP_DEBUG_S ((*mainCat)) << " start=" << (ellipse->startAngle() / 16.0);
320 LOG4CPP_DEBUG_S ((*mainCat)) << " span=" << (ellipse->spanAngle() / 16.0);
321 LOG4CPP_DEBUG_S ((*mainCat)) << " transformOrigin=" << QPointFToString (ellipse->transformOriginPoint()).toLatin1().data();
322 LOG4CPP_DEBUG_S ((*mainCat)) << " pos=" << QPointFToString (ellipse->pos ()).toLatin1().data();
323 LOG4CPP_DEBUG_S ((*mainCat)) << " radius=" << m_radius;
324 }
325}
326
327QLineF CentipedeDebugPolar::portionOfLineLast (const QLineF &line,
328 int degrees,
329 int degreesBetweenHighlights) const
330{
331 double s = (degrees % degreesBetweenHighlights == 0 ? 0.9 : 0.975);
332 QPointF posNewStart = (1.0 - s) * line.p1() + s * line.p2 ();
333 return QLineF(posNewStart,
334 line.p2());
335}
336
337QLineF CentipedeDebugPolar::portionOfLineNext (const QLineF &line,
338 int degrees,
339 int degreesBetweenHighlights) const
340{
341 double s = (degrees % degreesBetweenHighlights == 0 ? 1.1 : 1.025);
342 QPointF posNewStart = (1.0 - s) * line.p1() + s * line.p2 ();
343 return QLineF(posNewStart,
344 line.p2());
345}
346
348{
349 return m_posScreenParallelogramBL;
350}
351
353{
354 return m_posScreenParallelogramBR;
355}
356
358{
359 return m_posScreenParallelogramTL;
360}
361
363{
364 return m_posScreenParallelogramTR;
365}
366
368{
369 return m_radius;
370}
@ COORD_SCALE_LOG
Definition CoordScale.h:14
log4cpp::Category * mainCat
Definition Logger.cpp:14
QString QPointFToString(const QPointF &pos)
QString QRectFToString(const QRectF &rectF)
QPointF posScreenParallelogramTL() const
Get method for top left corner of rectangle.
double radius() const
Get method for radius.
QPointF posScreenParallelogramBL() const
Get method for bottom left corner of rectangle.
QPointF posScreenParallelogramBR() const
Get method for bottom right corner of rectangle.
void display(QGraphicsScene &scene, const DocumentModelCoords &modelCoords, const Transformation &transformation)
Display member variable values on scene.
CentipedeDebugPolar & operator=(const CentipedeDebugPolar &other)
Assignment operator.
double angleGraphAxisFromScreenAxis() const
Get method for top left corner of rectangle.
double aAligned() const
Get method for top left corner of rectangle.
double bAligned() const
Get method for top left corner of rectangle.
void dumpEllipseGraphicsItem(const QString &callerMethod, const QGraphicsEllipseItem *ellipse) const
Dump ellipse grahics item.
double angleEllipseFromMajorAxis() const
Get method for top left corner of rectangle.
CentipedeDebugPolar()
Default constructor with initial values overwritten later.
QPointF posScreenParallelogramTR() const
Get method for top right corner of rectangle.
Model for DlgSettingsCoords and CmdSettingsCoords.
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
double originRadius() const
Get method for origin radius in polar mode.
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...
#define LOG4CPP_DEBUG_S(logger)
Definition convenience.h:20
double magnitude(const QPointF &vec)
Norm of vector.
Definition mmsubs.cpp:193