Engauge Digitizer  2
 All Classes Files Functions Variables Enumerations Enumerator Friends Pages
Transformation.cpp
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 
7 #include "CallbackUpdateTransform.h"
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 <QtGlobal>
15 #include "QtToString.h"
16 #include "Transformation.h"
17 
18 using namespace std;
19 
22 const int PRECISION_DIGITS = 4;
23 
24 const double PI = 3.1415926535;
25 const 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  {
92  case COORD_UNITS_POLAR_THETA_DEGREES:
93  case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES:
94  case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS:
95  case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW:
96  angleRadians = posGraphIn.x () * PI / 180.0;
97  break;
98 
99  case COORD_UNITS_POLAR_THETA_GRADIANS:
100  angleRadians = posGraphIn.x () * PI / 200.0;
101  break;
102 
103  case COORD_UNITS_POLAR_THETA_RADIANS:
104  angleRadians = posGraphIn.x ();
105  break;
106 
107  case COORD_UNITS_POLAR_THETA_TURNS:
108  angleRadians = posGraphIn.x () * 2.0 * 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  {
136  case COORD_UNITS_POLAR_THETA_DEGREES:
137  case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES:
138  case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS:
139  case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW:
140  posGraphCartesianOrPolar.setX (angleRadians * 180.0 / PI);
141  break;
142 
143  case COORD_UNITS_POLAR_THETA_GRADIANS:
144  posGraphCartesianOrPolar.setX (angleRadians * 200.0 / PI);
145  break;
146 
147  case COORD_UNITS_POLAR_THETA_RADIANS:
148  posGraphCartesianOrPolar.setX (angleRadians);
149  break;
150 
151  case COORD_UNITS_POLAR_THETA_TURNS:
152  posGraphCartesianOrPolar.setX (angleRadians / 2.0 / 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 
166 void Transformation::coordTextForStatusBar (QPointF cursorScreen,
167  QString &coordsScreen,
168  QString &coordsGraph,
169  QString &resolutionsGraph)
170 {
171  const int UNCONSTRAINED_FIELD_WIDTH = 0;
172  const double X_DELTA_PIXELS = 1.0, Y_DELTA_PIXELS = 1.0;
173  const char FORMAT = 'g';
174 
175  if (cursorScreen.x() < 0 ||
176  cursorScreen.y() < 0) {
177 
178  // Out of bounds, so return empty text
179  coordsScreen = "";
180  coordsGraph = "";
181  resolutionsGraph = "";
182 
183  } else {
184 
185  coordsScreen = QString("(%1, %2)")
186  .arg (cursorScreen.x ())
187  .arg (cursorScreen.y ());
188 
189  if (m_transformIsDefined) {
190 
191  // For resolution we compute graph coords for cursorScreen, and then for cursorScreen plus a delta
192  QPointF cursorScreenDelta (cursorScreen.x () + X_DELTA_PIXELS,
193  cursorScreen.y () + Y_DELTA_PIXELS);
194 
195  // Convert to graph coordinates
196  QPointF pointGraph, pointGraphDelta;
197  transformScreenToRawGraph (cursorScreen,
198  pointGraph);
199  transformScreenToRawGraph (cursorScreenDelta,
200  pointGraphDelta);
201 
202  // Compute graph resolutions at cursor
203  double resolutionXGraph = qAbs ((pointGraphDelta.x () - pointGraph.x ()) / X_DELTA_PIXELS);
204  double resolutionYGraph = qAbs ((pointGraphDelta.y () - pointGraph.y ()) / Y_DELTA_PIXELS);
205 
206  // Formatting for date/time and degrees/minutes/seconds is only done on coordinates, and not on resolution
207  FormatCoordsUnits format;
208  QString xThetaFormatted, yRadiusFormatted;
209  format.unformattedToFormatted (pointGraph.x(),
210  pointGraph.y(),
211  m_modelCoords,
212  m_modelGeneral,
213  m_modelMainWindow,
214  xThetaFormatted,
215  yRadiusFormatted,
216  *this);
217 
218  coordsGraph = QString ("(%1, %2)")
219  .arg (xThetaFormatted)
220  .arg (yRadiusFormatted);
221 
222  resolutionsGraph = QString ("(%1, %2)")
223  .arg (resolutionXGraph, UNCONSTRAINED_FIELD_WIDTH, FORMAT, PRECISION_DIGITS)
224  .arg (resolutionYGraph, UNCONSTRAINED_FIELD_WIDTH, FORMAT, PRECISION_DIGITS);
225 
226  } else {
227 
228  coordsGraph = "<font color=\"red\">Need more axis points</font>";
229  resolutionsGraph = coordsGraph;
230 
231  }
232  }
233 }
234 
236 {
237  // Initialize assuming points (0,0) (1,0) (0,1)
238  m_transformIsDefined = true;
239 
240  QTransform ident;
241  m_transform = ident;
242 }
243 
245 {
246  return qLn (xy);
247 }
248 
250  double rCenter)
251 {
252  return qLn (r) - qLn (rCenter);
253 }
254 
256 {
257  return m_modelCoords;
258 }
259 
261 {
262  return m_modelGeneral;
263 }
264 
266 {
267  return m_modelMainWindow;
268 }
269 
270 ostringstream &operator<<(ostringstream &strOuter,
271  const Transformation &transformation)
272 {
273  QString text;
274  QTextStream strInner (&text);
275  transformation.printStream ("", strInner);
276 
277  strOuter << text.toLatin1().data ();
278 
279  return strOuter;
280 }
281 
282 void Transformation::printStream (QString indentation,
283  QTextStream &str) const
284 {
285  str << "Transformation\n";
286 
287  indentation += INDENTATION_DELTA;
288 
289  if (m_transformIsDefined) {
290 
291  str << indentation << "affine=" << (m_transform.isAffine() ? "yes" : "no") << " matrix=("
292  << m_transform.m11() << ", " << m_transform.m12() << ", " << m_transform.m13() << ", "
293  << m_transform.m21() << ", " << m_transform.m22() << ", " << m_transform.m23() << ", "
294  << m_transform.m31() << ", " << m_transform.m32() << ", " << m_transform.m33() << ")";
295 
296  } else {
297 
298  str << indentation << "undefined";
299 
300  }
301 }
302 
304 {
305  LOG4CPP_INFO_S ((*mainCat)) << "Transformation::resetOnLoad";
306 
307  m_transformIsDefined = false;
308 }
309 
310 double Transformation::roundOffSmallValues (double value, double range)
311 {
312  if (qAbs (value) < range / qPow (10.0, PRECISION_DIGITS)) {
313  value = 0.0;
314  }
315 
316  return value;
317 }
318 
319 void Transformation::setModelCoords (const DocumentModelCoords &modelCoords,
320  const DocumentModelGeneral &modelGeneral,
321  const MainWindowModel &modelMainWindow)
322 {
323  m_modelCoords = modelCoords;
324  m_modelGeneral = modelGeneral;
325  m_modelMainWindow = modelMainWindow;
326 }
327 
329 {
330  return m_transformIsDefined;
331 }
332 
333 void Transformation::transformLinearCartesianGraphToRawGraph (const QPointF &pointLinearCartesianGraph,
334  QPointF &pointRawGraph) const
335 {
336  // WARNING - the code in this method must mirror the code in transformRawGraphToLinearCartesianGraph. In
337  // other words, making a change here without a corresponding change there will produce a bug
338 
339  pointRawGraph = pointLinearCartesianGraph;
340 
341  // Apply polar coordinates if appropriate
342  if (m_modelCoords.coordsType() == COORDS_TYPE_POLAR) {
343  pointRawGraph = cartesianOrPolarFromCartesian (m_modelCoords,
344  pointRawGraph);
345  }
346 
347  // Apply linear offset to radius if appropriate
348  if ((m_modelCoords.coordsType() == COORDS_TYPE_POLAR) &&
349  (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR)) {
350  pointRawGraph.setY (pointRawGraph.y() + m_modelCoords.originRadius());
351  }
352 
353  // Apply log scaling if appropriate
354  if (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LOG) {
355  pointRawGraph.setX (qExp (pointRawGraph.x()));
356  }
357 
358  if (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG) {
359  double offset;
360  if (m_modelCoords.coordsType() == COORDS_TYPE_CARTESIAN) {
361  // Cartesian
362  offset = ZERO_OFFSET_AFTER_LOG;
363  } else {
364  // Polar radius
365  offset = m_modelCoords.originRadius();
366  }
367 
368  pointRawGraph.setY (qExp (pointRawGraph.y() + qLn (offset)));
369  }
370 }
371 
373  QPointF &coordScreen) const
374 {
375  ENGAUGE_ASSERT (m_transformIsDefined);
376 
377  coordScreen = m_transform.inverted ().transposed ().map (coordGraph);
378 }
379 
381 {
382  return m_transform;
383 }
384 
386  QPointF &pointLinearCartesian) const
387 {
388  // WARNING - the code in this method must mirror the code in transformLinearCartesianGraphToRawGraph. In
389  // other words, making a change here without a corresponding change there will produce a bug
390 
391  double x = pointRaw.x();
392  double y = pointRaw.y();
393 
394  // Apply linear offset to radius if appropriate
395  if ((m_modelCoords.coordsType() == COORDS_TYPE_POLAR) &&
396  (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR)) {
397  y -= m_modelCoords.originRadius();
398  }
399 
400  // Apply log scaling if appropriate
401  if (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LOG) {
402  x = logToLinearCartesian (x);
403  }
404 
405  if (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG) {
406  if (m_modelCoords.coordsType() == COORDS_TYPE_POLAR) {
407  y = logToLinearRadius (y,
408  m_modelCoords.originRadius());
409  } else {
410  y = logToLinearRadius (y,
411  ZERO_OFFSET_AFTER_LOG);
412  }
413  }
414 
415  // Apply polar coordinates if appropriate. Note range coordinate has just been transformed if it has log scaling
416  if (m_modelCoords.coordsType() == COORDS_TYPE_POLAR) {
417  QPointF pointCart = cartesianFromCartesianOrPolar (m_modelCoords,
418  QPointF (x, y));
419  x = pointCart.x();
420  y = pointCart.y();
421  }
422 
423  pointLinearCartesian.setX (x);
424  pointLinearCartesian.setY (y);
425 }
426 
427 void Transformation::transformRawGraphToScreen (const QPointF &pointRaw,
428  QPointF &pointScreen) const
429 {
430  QPointF pointLinearCartesianGraph;
431 
433  pointLinearCartesianGraph);
434  transformLinearCartesianGraphToScreen (pointLinearCartesianGraph,
435  pointScreen);
436 }
437 
439  QPointF &coordGraph) const
440 {
441  ENGAUGE_ASSERT (m_transformIsDefined);
442 
443  coordGraph = m_transform.transposed ().map (coordScreen);
444 }
445 
446 void Transformation::transformScreenToRawGraph (const QPointF &coordScreen,
447  QPointF &coordGraph) const
448 {
449  QPointF pointLinearCartesianGraph;
451  pointLinearCartesianGraph);
452  transformLinearCartesianGraphToRawGraph (pointLinearCartesianGraph,
453  coordGraph);
454 }
455 
456 void Transformation::update (bool fileIsLoaded,
457  const CmdMediator &cmdMediator,
458  const MainWindowModel &modelMainWindow)
459 {
460  LOG4CPP_DEBUG_S ((*mainCat)) << "Transformation::update";
461 
462  if (!fileIsLoaded) {
463 
464  m_transformIsDefined = false;
465 
466  } else {
467 
468  setModelCoords (cmdMediator.document().modelCoords(),
469  cmdMediator.document().modelGeneral(),
471 
472  CallbackUpdateTransform ftor (m_modelCoords,
473  cmdMediator.document().documentAxesPointsRequired());
474 
475  Functor2wRet<const QString &, const Point&, CallbackSearchReturn> ftorWithCallback = functor_ret (ftor,
477  cmdMediator.iterateThroughCurvePointsAxes (ftorWithCallback);
478 
479  if (ftor.transformIsDefined ()) {
480 
481  updateTransformFromMatrices (ftor.matrixScreen(),
482  ftor.matrixGraph());
483  } else {
484 
485  m_transformIsDefined = false;
486 
487  }
488  }
489 }
490 
491 void Transformation::updateTransformFromMatrices (const QTransform &matrixScreen,
492  const QTransform &matrixGraph)
493 {
494  // LOG4CPP_INFO_S is below
495 
496  m_transformIsDefined = true;
497 
498  // Extract points from 3x3 matrices
499  QPointF pointGraphRaw0 (matrixGraph.m11(),
500  matrixGraph.m21());
501  QPointF pointGraphRaw1 (matrixGraph.m12(),
502  matrixGraph.m22());
503  QPointF pointGraphRaw2 (matrixGraph.m13(),
504  matrixGraph.m23());
505 
506  QPointF pointGraphLinearCart0, pointGraphLinearCart1, pointGraphLinearCart2;
508  pointGraphLinearCart0);
510  pointGraphLinearCart1);
512  pointGraphLinearCart2);
513 
514  // Calculate the transform
515  m_transform = calculateTransformFromLinearCartesianPoints (QPointF (matrixScreen.m11(), matrixScreen.m21()),
516  QPointF (matrixScreen.m12(), matrixScreen.m22()),
517  QPointF (matrixScreen.m13(), matrixScreen.m23()),
518  QPointF (pointGraphLinearCart0.x(), pointGraphLinearCart0.y()),
519  QPointF (pointGraphLinearCart1.x(), pointGraphLinearCart1.y()),
520  QPointF (pointGraphLinearCart2.x(), pointGraphLinearCart2.y()));
521 
522  // Logging
523  QTransform matrixGraphLinear (pointGraphLinearCart0.x(),
524  pointGraphLinearCart1.x(),
525  pointGraphLinearCart2.x(),
526  pointGraphLinearCart0.y(),
527  pointGraphLinearCart1.y(),
528  pointGraphLinearCart2.y(),
529  1.0,
530  1.0);
531 
532  QPointF pointScreenRoundTrip0, pointScreenRoundTrip1, pointScreenRoundTrip2;
533  transformRawGraphToScreen (pointGraphRaw0,
534  pointScreenRoundTrip0);
535  transformRawGraphToScreen (pointGraphRaw1,
536  pointScreenRoundTrip1);
537  transformRawGraphToScreen (pointGraphRaw2,
538  pointScreenRoundTrip2);
539 
540  QPointF pointScreen0 (matrixScreen.m11(),
541  matrixScreen.m21());
542  QPointF pointScreen1 (matrixScreen.m12(),
543  matrixScreen.m22());
544  QPointF pointScreen2 (matrixScreen.m13(),
545  matrixScreen.m23());
546 
547  LOG4CPP_INFO_S ((*mainCat)) << "Transformation::updateTransformFromMatrices"
548  << " matrixScreen=\n" << QTransformToString (matrixScreen).toLatin1().data () << " "
549  << " matrixGraphRaw=\n" << QTransformToString (matrixGraph).toLatin1().data() << " "
550  << " matrixGraphLinear=\n" << QTransformToString (matrixGraphLinear).toLatin1().data() << "\n"
551  << " originalScreen0=" << QPointFToString (pointScreen0).toLatin1().data() << "\n"
552  << " originalScreen1=" << QPointFToString (pointScreen1).toLatin1().data() << "\n"
553  << " originalScreen2=" << QPointFToString (pointScreen2).toLatin1().data() << "\n"
554  << " roundTripScreen0=" << QPointFToString (pointScreenRoundTrip0).toLatin1().data() << "\n"
555  << " roundTripScreen1=" << QPointFToString (pointScreenRoundTrip1).toLatin1().data() << "\n"
556  << " roundTripScreen2=" << QPointFToString (pointScreenRoundTrip2).toLatin1().data() << "\n";
557 }
void transformScreenToRawGraph(const QPointF &coordScreen, QPointF &coordGraph) const
Transform from cartesian pixel screen coordinates to cartesian/polar graph coordinates.
void coordTextForStatusBar(QPointF cursorScreen, QString &coordsScreen, QString &coordsGraph, QString &resolutionGraph)
Return string descriptions of cursor coordinates for status bar.
Callback for collecting axis points and then calculating the current transform from those axis points...
Model for DlgSettingsGeneral and CmdSettingsGeneral.
void printStream(QString indentation, QTextStream &str) const
Debugging method that supports print method of this class and printStream method of some other class(...
DocumentAxesPointsRequired documentAxesPointsRequired() const
Get method for DocumentAxesPointsRequired.
Definition: Document.cpp:333
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...
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 transformScreenToLinearCartesianGraph(const QPointF &pointScreen, QPointF &pointLinearCartesian) const
Transform screen coordinates to linear cartesian coordinates.
QTransform transformMatrix() const
Get method for copying only, for the transform matrix.
void transformLinearCartesianGraphToScreen(const QPointF &coordGraph, QPointF &coordScreen) const
Transform from linear cartesian graph coordinates to cartesian pixel screen coordinates.
bool operator!=(const Transformation &other)
Inequality operator. This is marked as defined.
static QPointF cartesianOrPolarFromCartesian(const DocumentModelCoords &modelCoords, const QPointF &posGraphIn)
Output cartesian or polar coordinates from input cartesian coordinates. This is static for easier use...
static double logToLinearRadius(double r, double rCenter)
Convert radius scaling from log to linear. Calling code is responsible for determining if this is nec...
Transformation()
Default constructor. This is marked as undefined until the proper number of axis points are added...
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
double originRadius() const
Get method for origin radius in polar mode.
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition: Document.cpp:665
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:72
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...
static double logToLinearCartesian(double xy)
Convert cartesian scaling from log to linear. Calling code is responsible for determining if this is ...
MainWindowModel modelMainWindow() const
Get method for MainWindowModel.
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Transformation & operator=(const Transformation &other)
Assignment operator.
Affine transformation between screen and graph coordinates, based on digitized axis points...
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
Model for DlgSettingsMainWindow.
CoordsType coordsType() const
Get method for coordinates type.
Model for DlgSettingsCoords and CmdSettingsCoords.
void transformLinearCartesianGraphToRawGraph(const QPointF &coordGraph, QPointF &coordScreen) const
Transform from linear cartesian graph coordinates to cartesian, polar, linear, log coordinates...
Highest-level wrapper around other Formats classes.
bool transformIsDefined() const
Transform is defined when at least three axis points have been digitized.
Command queue stack.
Definition: CmdMediator.h:23
void identity()
Identity transformation.
void update(bool fileIsLoaded, const CmdMediator &cmdMediator, const MainWindowModel &modelMainWindow)
Update transform by iterating through the axis points.
void transformRawGraphToLinearCartesianGraph(const QPointF &pointRaw, QPointF &pointLinearCartesian) const
Convert graph coordinates (linear or log, cartesian or polar) to linear cartesian coordinates...
void iterateThroughCurvePointsAxes(const Functor2wRet< const QString &, const Point &, CallbackSearchReturn > &ftorWithCallback)
See Curve::iterateThroughCurvePoints, for the single axes curve.
Definition: CmdMediator.cpp:87
void transformRawGraphToScreen(const QPointF &pointRaw, QPointF &pointScreen) const
Transform from raw graph coordinates to linear cartesian graph coordinates, then to screen coordinate...
DocumentModelGeneral modelGeneral() const
Get method for DocumentModelGeneral.
Definition: Document.cpp:693
CoordUnitsPolarTheta coordUnitsTheta() const
Get method for theta unit.
DocumentModelGeneral modelGeneral() const
Get method for DocumentModelGeneral.
CallbackSearchReturn callback(const QString &curveName, const Point &point)
Callback method.