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