Engauge Digitizer 2
Loading...
Searching...
No Matches
Transformation.cpp
Go to the documentation of this file.
1/******************************************************************************************************
2 * (C) 2014 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
8#include "Document.h"
9#include "EngaugeAssert.h"
10#include "FormatCoordsUnits.h"
11#include "Logger.h"
12#include <QDebug>
13#include <qmath.h>
14#include <QObject>
15#include <QtGlobal>
16#include "QtToString.h"
17#include "Transformation.h"
18
19using namespace std;
20
23const int PRECISION_DIGITS = 4;
24
25const double ZERO_OFFSET_AFTER_LOG = 1; // Log of this value is zero
26
28 m_transformIsDefined (false)
29{
30}
31
33 m_transformIsDefined (other.transformIsDefined()),
34 m_transform (other.transformMatrix())
35{
36 setModelCoords (other.modelCoords(),
37 other.modelGeneral(),
38 other.modelMainWindow());
39}
40
42{
43 m_transformIsDefined = other.transformIsDefined();
44 m_transform = other.transformMatrix ();
45 setModelCoords (other.modelCoords(),
46 other.modelGeneral(),
47 other.modelMainWindow());
48
49 return *this;
50}
51
53{
54 return (m_transformIsDefined != other.transformIsDefined()) ||
55 (m_transform != other.transformMatrix ());
56}
57
59 const QPointF &posFrom1,
60 const QPointF &posFrom2,
61 const QPointF &posTo0,
62 const QPointF &posTo1,
63 const QPointF &posTo2)
64{
65 LOG4CPP_INFO_S ((*mainCat)) << "Transformation::calculateTransformFromLinearCartesianPoints";
66
67 QTransform from, to;
68 from.setMatrix (posFrom0.x(), posFrom1.x(), posFrom2.x(),
69 posFrom0.y(), posFrom1.y(), posFrom2.y(),
70 1.0, 1.0, 1.0);
71
72 to.setMatrix (posTo0.x(), posTo1.x(), posTo2.x(),
73 posTo0.y(), posTo1.y(), posTo2.y(),
74 1.0, 1.0, 1.0);
75 QTransform fromInv = from.inverted ();
76
77 return to * fromInv;
78}
79
81 const QPointF &posGraphIn)
82{
83 // Initialize assuming input coordinates are already cartesian
84 QPointF posGraphCartesian = posGraphIn;
85
86 if (modelCoords.coordsType() == COORDS_TYPE_POLAR) {
87
88 // Input coordinates are polar so convert them
89 double angleRadians = 0; // Initialized to prevent compiler warning
90 switch (modelCoords.coordUnitsTheta())
91 {
96 angleRadians = posGraphIn.x () * M_PI / 180.0;
97 break;
98
100 angleRadians = posGraphIn.x () * M_PI / 200.0;
101 break;
102
104 angleRadians = posGraphIn.x ();
105 break;
106
108 angleRadians = posGraphIn.x () * 2.0 * M_PI;
109 break;
110
111 default:
112 ENGAUGE_ASSERT (false);
113 }
114
115 double radius = posGraphIn.y ();
116 posGraphCartesian.setX (radius * cos (angleRadians));
117 posGraphCartesian.setY (radius * sin (angleRadians));
118 }
119
120 return posGraphCartesian;
121}
122
124 const QPointF &posGraphIn)
125{
126 // Initialize assuming output coordinates are to be cartesian
127 QPointF posGraphCartesianOrPolar = posGraphIn;
128
129 if (modelCoords.coordsType() == COORDS_TYPE_POLAR) {
130
131 // Output coordinates are to be polar so convert them
132 double angleRadians = qAtan2 (posGraphIn.y (),
133 posGraphIn.x ());
134 switch (modelCoords.coordUnitsTheta())
135 {
140 posGraphCartesianOrPolar.setX (angleRadians * 180.0 / M_PI);
141 break;
142
144 posGraphCartesianOrPolar.setX (angleRadians * 200.0 / M_PI);
145 break;
146
148 posGraphCartesianOrPolar.setX (angleRadians);
149 break;
150
152 posGraphCartesianOrPolar.setX (angleRadians / (2.0 * M_PI));
153 break;
154
155 default:
156 ENGAUGE_ASSERT (false);
157 }
158
159 double radius = qSqrt (posGraphIn.x () * posGraphIn.x () + posGraphIn.y () * posGraphIn.y ());
160 posGraphCartesianOrPolar.setY (radius);
161 }
162
163 return posGraphCartesianOrPolar;
164}
165
166void Transformation::coordTextForStatusBar (QPointF cursorScreen,
167 QString &coordsScreen,
168 QString &coordsGraph,
169 QString &resolutionsGraph,
170 bool usingScaleBar)
171{
172 const int UNCONSTRAINED_FIELD_WIDTH = 0;
173 const double X_DELTA_PIXELS = 1.0, Y_DELTA_PIXELS = 1.0;
174 const char FORMAT = 'g';
175
176 QString needMoreText = (usingScaleBar ?
177 QObject::tr ("Need scale bar") :
178 QObject::tr ("Need more axis points"));
179
180 if (cursorScreen.x() < 0 ||
181 cursorScreen.y() < 0) {
182
183 // Out of bounds, so return empty text
184 coordsScreen = "";
185 coordsGraph = "";
186 resolutionsGraph = "";
187
188 } else {
189
190 coordsScreen = QString("(%1, %2)")
191 .arg (cursorScreen.x ())
192 .arg (cursorScreen.y ());
193
194 if (m_transformIsDefined) {
195
196 // For resolution we compute graph coords for cursorScreen, and then for cursorScreen plus a delta
197 QPointF cursorScreenDelta (cursorScreen.x () + X_DELTA_PIXELS,
198 cursorScreen.y () + Y_DELTA_PIXELS);
199
200 // Convert to graph coordinates
201 QPointF pointGraph, pointGraphDelta;
202 transformScreenToRawGraph (cursorScreen,
203 pointGraph);
204 transformScreenToRawGraph (cursorScreenDelta,
205 pointGraphDelta);
206
207 // Compute graph resolutions at cursor
208 double resolutionXGraph = qAbs ((pointGraphDelta.x () - pointGraph.x ()) / X_DELTA_PIXELS);
209 double resolutionYGraph = qAbs ((pointGraphDelta.y () - pointGraph.y ()) / Y_DELTA_PIXELS);
210
211 // Formatting for date/time and degrees/minutes/seconds is only done on coordinates, and not on resolution
212 FormatCoordsUnits format;
213 QString xThetaFormatted, yRadiusFormatted;
214 format.unformattedToFormatted (pointGraph.x(),
215 pointGraph.y(),
216 m_modelCoords,
217 m_modelGeneral,
218 m_modelMainWindow,
219 xThetaFormatted,
220 yRadiusFormatted,
221 *this);
222
223 coordsGraph = QString ("(%1, %2)")
224 .arg (xThetaFormatted)
225 .arg (yRadiusFormatted);
226
227 resolutionsGraph = QString ("(%1, %2)")
228 .arg (resolutionXGraph, UNCONSTRAINED_FIELD_WIDTH, FORMAT, PRECISION_DIGITS)
229 .arg (resolutionYGraph, UNCONSTRAINED_FIELD_WIDTH, FORMAT, PRECISION_DIGITS);
230
231 } else {
232
233 coordsGraph = QString ("<font color=\"red\">%1</font>")
234 .arg (needMoreText);
235 resolutionsGraph = coordsGraph;
236
237 }
238 }
239}
240
242{
243 // Initialize assuming points (0,0) (1,0) (0,1)
244 m_transformIsDefined = true;
245
246 QTransform ident;
247 m_transform = ident;
248}
249
251{
252 return qLn (xy);
253}
254
256 double rCenter)
257{
258 return qLn (r) - qLn (rCenter);
259}
260
262{
263 return m_modelCoords;
264}
265
267{
268 return m_modelGeneral;
269}
270
272{
273 return m_modelMainWindow;
274}
275
276ostringstream &operator<<(ostringstream &strOuter,
277 const Transformation &transformation)
278{
279 QString text;
280 QTextStream strInner (&text);
281 transformation.printStream ("", strInner);
282
283 strOuter << text.toLatin1().data ();
284
285 return strOuter;
286}
287
288void Transformation::printStream (QString indentation,
289 QTextStream &str) const
290{
291 str << "Transformation\n";
292
293 indentation += INDENTATION_DELTA;
294
295 if (m_transformIsDefined) {
296
297 str << indentation << "affine=" << (m_transform.isAffine() ? "yes" : "no") << " matrix=("
298 << m_transform.m11() << ", " << m_transform.m12() << ", " << m_transform.m13() << ", "
299 << m_transform.m21() << ", " << m_transform.m22() << ", " << m_transform.m23() << ", "
300 << m_transform.m31() << ", " << m_transform.m32() << ", " << m_transform.m33() << ")";
301
302 } else {
303
304 str << indentation << "undefined";
305
306 }
307}
308
310{
311 LOG4CPP_INFO_S ((*mainCat)) << "Transformation::resetOnLoad";
312
313 m_transformIsDefined = false;
314}
315
316double Transformation::roundOffSmallValues (double value, double range)
317{
318 if (qAbs (value) < range / qPow (10.0, PRECISION_DIGITS)) {
319 value = 0.0;
320 }
321
322 return value;
323}
324
325void Transformation::setModelCoords (const DocumentModelCoords &modelCoords,
326 const DocumentModelGeneral &modelGeneral,
327 const MainWindowModel &modelMainWindow)
328{
329 m_modelCoords = modelCoords;
330 m_modelGeneral = modelGeneral;
331 m_modelMainWindow = modelMainWindow;
332}
333
335{
336 return m_transformIsDefined;
337}
338
339void Transformation::transformLinearCartesianGraphToRawGraph (const QPointF &pointLinearCartesianGraph,
340 QPointF &pointRawGraph) const
341{
342 // WARNING - the code in this method must mirror the code in transformRawGraphToLinearCartesianGraph. In
343 // other words, making a change here without a corresponding change there will produce a bug
344
345 pointRawGraph = pointLinearCartesianGraph;
346
347 // Apply polar coordinates if appropriate
348 if (m_modelCoords.coordsType() == COORDS_TYPE_POLAR) {
349 pointRawGraph = cartesianOrPolarFromCartesian (m_modelCoords,
350 pointRawGraph);
351 }
352
353 // Apply linear offset to radius if appropriate
354 if ((m_modelCoords.coordsType() == COORDS_TYPE_POLAR) &&
355 (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR)) {
356 pointRawGraph.setY (pointRawGraph.y() + m_modelCoords.originRadius());
357 }
358
359 // Apply log scaling if appropriate
360 if (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LOG) {
361 pointRawGraph.setX (qExp (pointRawGraph.x()));
362 }
363
364 if (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG) {
365 double offset;
366 if (m_modelCoords.coordsType() == COORDS_TYPE_CARTESIAN) {
367 // Cartesian
368 offset = ZERO_OFFSET_AFTER_LOG;
369 } else {
370 // Polar radius
371 offset = m_modelCoords.originRadius();
372 }
373
374 pointRawGraph.setY (qExp (pointRawGraph.y() + qLn (offset)));
375 }
376}
377
379 QPointF &coordScreen) const
380{
381 ENGAUGE_ASSERT (m_transformIsDefined);
382
383 coordScreen = m_transform.inverted ().transposed ().map (coordGraph);
384}
385
387{
388 return m_transform;
389}
390
392 QPointF &pointLinearCartesian) const
393{
394 // WARNING - the code in this method must mirror the code in transformLinearCartesianGraphToRawGraph. In
395 // other words, making a change here without a corresponding change there will produce a bug
396
397 double x = pointRaw.x();
398 double y = pointRaw.y();
399
400 // Apply linear offset to radius if appropriate
401 if ((m_modelCoords.coordsType() == COORDS_TYPE_POLAR) &&
402 (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR)) {
403 y -= m_modelCoords.originRadius();
404 }
405
406 // Apply log scaling if appropriate
407 if (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LOG) {
408 x = logToLinearCartesian (x);
409 }
410
411 if (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG) {
412 if (m_modelCoords.coordsType() == COORDS_TYPE_POLAR) {
413 y = logToLinearRadius (y,
414 m_modelCoords.originRadius());
415 } else {
416 y = logToLinearRadius (y,
418 }
419 }
420
421 // Apply polar coordinates if appropriate. Note range coordinate has just been transformed if it has log scaling
422 if (m_modelCoords.coordsType() == COORDS_TYPE_POLAR) {
423 QPointF pointCart = cartesianFromCartesianOrPolar (m_modelCoords,
424 QPointF (x, y));
425 x = pointCart.x();
426 y = pointCart.y();
427 }
428
429 pointLinearCartesian.setX (x);
430 pointLinearCartesian.setY (y);
431}
432
433void Transformation::transformRawGraphToScreen (const QPointF &pointRaw,
434 QPointF &pointScreen) const
435{
436 QPointF pointLinearCartesianGraph;
437
439 pointLinearCartesianGraph);
440 transformLinearCartesianGraphToScreen (pointLinearCartesianGraph,
441 pointScreen);
442}
443
445 QPointF &coordGraph) const
446{
447 ENGAUGE_ASSERT (m_transformIsDefined);
448
449 coordGraph = m_transform.transposed ().map (coordScreen);
450}
451
452void Transformation::transformScreenToRawGraph (const QPointF &coordScreen,
453 QPointF &coordGraph) const
454{
455 QPointF pointLinearCartesianGraph;
457 pointLinearCartesianGraph);
458 transformLinearCartesianGraphToRawGraph (pointLinearCartesianGraph,
459 coordGraph);
460}
461
462void Transformation::update (bool fileIsLoaded,
463 const CmdMediator &cmdMediator,
465{
466 LOG4CPP_DEBUG_S ((*mainCat)) << "Transformation::update";
467
468 if (!fileIsLoaded) {
469
470 m_transformIsDefined = false;
471
472 } else {
473
474 setModelCoords (cmdMediator.document().modelCoords(),
475 cmdMediator.document().modelGeneral(),
477
478 CallbackUpdateTransform ftor (m_modelCoords,
479 cmdMediator.document().documentAxesPointsRequired());
480
481 Functor2wRet<const QString &, const Point&, CallbackSearchReturn> ftorWithCallback = functor_ret (ftor,
483 cmdMediator.iterateThroughCurvePointsAxes (ftorWithCallback);
484
485 if (ftor.transformIsDefined ()) {
486
487 updateTransformFromMatrices (ftor.matrixScreen(),
488 ftor.matrixGraph());
489
490 } else {
491
492 m_transformIsDefined = false;
493
494 }
495 }
496}
497
498void Transformation::updateTransformFromMatrices (const QTransform &matrixScreen,
499 const QTransform &matrixGraph)
500{
501 // LOG4CPP_INFO_S is below
502
503 m_transformIsDefined = true;
504
505 // Extract points from 3x3 matrices
506 QPointF pointGraphRaw0 (matrixGraph.m11(),
507 matrixGraph.m21());
508 QPointF pointGraphRaw1 (matrixGraph.m12(),
509 matrixGraph.m22());
510 QPointF pointGraphRaw2 (matrixGraph.m13(),
511 matrixGraph.m23());
512
513 QPointF pointGraphLinearCart0, pointGraphLinearCart1, pointGraphLinearCart2;
515 pointGraphLinearCart0);
517 pointGraphLinearCart1);
519 pointGraphLinearCart2);
520
521 // Calculate the transform
522 m_transform = calculateTransformFromLinearCartesianPoints (QPointF (matrixScreen.m11(), matrixScreen.m21()),
523 QPointF (matrixScreen.m12(), matrixScreen.m22()),
524 QPointF (matrixScreen.m13(), matrixScreen.m23()),
525 QPointF (pointGraphLinearCart0.x(), pointGraphLinearCart0.y()),
526 QPointF (pointGraphLinearCart1.x(), pointGraphLinearCart1.y()),
527 QPointF (pointGraphLinearCart2.x(), pointGraphLinearCart2.y()));
528
529 // Logging
530 QTransform matrixGraphLinear (pointGraphLinearCart0.x(),
531 pointGraphLinearCart1.x(),
532 pointGraphLinearCart2.x(),
533 pointGraphLinearCart0.y(),
534 pointGraphLinearCart1.y(),
535 pointGraphLinearCart2.y());
536
537 QPointF pointScreenRoundTrip0, pointScreenRoundTrip1, pointScreenRoundTrip2;
538 transformRawGraphToScreen (pointGraphRaw0,
539 pointScreenRoundTrip0);
540 transformRawGraphToScreen (pointGraphRaw1,
541 pointScreenRoundTrip1);
542 transformRawGraphToScreen (pointGraphRaw2,
543 pointScreenRoundTrip2);
544
545 QPointF pointScreen0 (matrixScreen.m11(),
546 matrixScreen.m21());
547 QPointF pointScreen1 (matrixScreen.m12(),
548 matrixScreen.m22());
549 QPointF pointScreen2 (matrixScreen.m13(),
550 matrixScreen.m23());
551
552 LOG4CPP_INFO_S ((*mainCat)) << "Transformation::updateTransformFromMatrices"
553 << " matrixScreen=\n" << QTransformToString (matrixScreen).toLatin1().data () << " "
554 << " matrixGraphRaw=\n" << QTransformToString (matrixGraph).toLatin1().data() << " "
555 << " matrixGraphLinear=\n" << QTransformToString (matrixGraphLinear).toLatin1().data() << "\n"
556 << " originalScreen0=" << QPointFToString (pointScreen0).toLatin1().data() << "\n"
557 << " originalScreen1=" << QPointFToString (pointScreen1).toLatin1().data() << "\n"
558 << " originalScreen2=" << QPointFToString (pointScreen2).toLatin1().data() << "\n"
559 << " roundTripScreen0=" << QPointFToString (pointScreenRoundTrip0).toLatin1().data() << "\n"
560 << " roundTripScreen1=" << QPointFToString (pointScreenRoundTrip1).toLatin1().data() << "\n"
561 << " roundTripScreen2=" << QPointFToString (pointScreenRoundTrip2).toLatin1().data() << "\n";
562}
@ COORD_SCALE_LINEAR
Definition CoordScale.h:13
@ COORD_SCALE_LOG
Definition CoordScale.h:14
@ COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW
@ COORD_UNITS_POLAR_THETA_TURNS
@ COORD_UNITS_POLAR_THETA_RADIANS
@ COORD_UNITS_POLAR_THETA_DEGREES_MINUTES
@ COORD_UNITS_POLAR_THETA_DEGREES
@ COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS
@ COORD_UNITS_POLAR_THETA_GRADIANS
@ COORDS_TYPE_POLAR
Definition CoordsType.h:14
@ COORDS_TYPE_CARTESIAN
Definition CoordsType.h:13
#define ENGAUGE_ASSERT(cond)
Drop in replacement for Q_ASSERT.
log4cpp::Category * mainCat
Definition Logger.cpp:14
const QString INDENTATION_DELTA
QString QTransformToString(const QTransform &transform)
QString QPointFToString(const QPointF &pos)
ostringstream & operator<<(ostringstream &strOuter, const Transformation &transformation)
const int PRECISION_DIGITS
Max number of significant digits.
const double ZERO_OFFSET_AFTER_LOG
QTransform matrixGraph() const
Returns graph coordinates matrix after transformIsDefined has already indicated success.
CallbackSearchReturn callback(const QString &curveName, const Point &point)
Callback method.
QTransform matrixScreen() const
Returns screen coordinates matrix after transformIsDefined has already indicated success.
Callback for collecting axis points and then calculating the current transform from those axis points...
bool transformIsDefined() const
True if enough Points were available to create a Transformation.
Command queue stack.
Definition CmdMediator.h:24
void iterateThroughCurvePointsAxes(const Functor2wRet< const QString &, const Point &, CallbackSearchReturn > &ftorWithCallback)
See Curve::iterateThroughCurvePoints, for the single axes curve.
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Model for DlgSettingsCoords and CmdSettingsCoords.
Model for DlgSettingsGeneral and CmdSettingsGeneral.
DocumentModelGeneral modelGeneral() const
Get method for DocumentModelGeneral.
Definition Document.cpp:735
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition Document.cpp:707
DocumentAxesPointsRequired documentAxesPointsRequired() const
Get method for DocumentAxesPointsRequired.
Definition Document.cpp:369
Highest-level wrapper around other Formats classes.
void unformattedToFormatted(double xThetaUnformatted, double yRadiusUnformatted, const DocumentModelCoords &modelCoords, const DocumentModelGeneral &modelGeneral, const MainWindowModel &mainWindowModel, QString &xThetaFormatted, QString &yRadiusFormatted, const Transformation &transformation) const
Convert unformatted numeric value to formatted string. Transformation is used to determine best resol...
Model for DlgSettingsMainWindow.
Affine transformation between screen and graph coordinates, based on digitized axis points.
void identity()
Identity transformation.
bool operator!=(const Transformation &other)
Inequality operator. This is marked as defined.
void printStream(QString indentation, QTextStream &str) const
Debugging method that supports print method of this class and printStream method of some other class(...
static QTransform calculateTransformFromLinearCartesianPoints(const QPointF &posFrom0, const QPointF &posFrom1, const QPointF &posFrom2, const QPointF &posTo0, const QPointF &posTo1, const QPointF &posTo2)
Calculate QTransform using from/to points that have already been adjusted for, when applicable,...
void coordTextForStatusBar(QPointF cursorScreen, QString &coordsScreen, QString &coordsGraph, QString &resolutionGraph, bool usingScaleBar)
Return string descriptions of cursor coordinates for status bar.
Transformation()
Default constructor. This is marked as undefined until the proper number of axis points are added.
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.
void transformLinearCartesianGraphToRawGraph(const QPointF &coordGraph, QPointF &coordScreen) const
Transform from linear cartesian graph coordinates to cartesian, polar, linear, log coordinates.
static double logToLinearCartesian(double xy)
Convert cartesian scaling from log to linear. Calling code is responsible for determining if this is ...
static QPointF cartesianOrPolarFromCartesian(const DocumentModelCoords &modelCoords, const QPointF &posGraphIn)
Output cartesian or polar coordinates from input cartesian coordinates. This is static for easier use...
Transformation & operator=(const Transformation &other)
Assignment operator.
static QPointF cartesianFromCartesianOrPolar(const DocumentModelCoords &modelCoords, const QPointF &posGraphIn)
Output cartesian coordinates from input cartesian or polar coordinates. This is static for easier use...
void resetOnLoad()
Reset, when loading a document after the first, to same state that first document was at when loaded.
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
QTransform transformMatrix() const
Get method for copying only, for the transform matrix.
static double logToLinearRadius(double r, double rCenter)
Convert radius scaling from log to linear. Calling code is responsible for determining if this is nec...
void transformRawGraphToLinearCartesianGraph(const QPointF &pointRaw, QPointF &pointLinearCartesian) const
Convert graph coordinates (linear or log, cartesian or polar) to linear cartesian coordinates.
bool transformIsDefined() const
Transform is defined when at least three axis points have been digitized.
void update(bool fileIsLoaded, const CmdMediator &cmdMediator, const MainWindowModel &modelMainWindow)
Update transform by iterating through the axis points.
DocumentModelGeneral modelGeneral() const
Get method for DocumentModelGeneral.
MainWindowModel modelMainWindow() const
Get method for MainWindowModel.
void transformScreenToLinearCartesianGraph(const QPointF &pointScreen, QPointF &pointLinearCartesian) const
Transform screen coordinates to linear cartesian coordinates.
void transformLinearCartesianGraphToScreen(const QPointF &coordGraph, QPointF &coordScreen) const
Transform from linear cartesian graph coordinates to cartesian pixel screen coordinates.
#define LOG4CPP_INFO_S(logger)
Definition convenience.h:18
#define LOG4CPP_DEBUG_S(logger)
Definition convenience.h:20