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 <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 {
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  if (cursorScreen.x() < 0 ||
177  cursorScreen.y() < 0) {
178 
179  // Out of bounds, so return empty text
180  coordsScreen = "";
181  coordsGraph = "";
182  resolutionsGraph = "";
183 
184  } else {
185 
186  coordsScreen = QString("(%1, %2)")
187  .arg (cursorScreen.x ())
188  .arg (cursorScreen.y ());
189 
190  if (m_transformIsDefined) {
191 
192  // For resolution we compute graph coords for cursorScreen, and then for cursorScreen plus a delta
193  QPointF cursorScreenDelta (cursorScreen.x () + X_DELTA_PIXELS,
194  cursorScreen.y () + Y_DELTA_PIXELS);
195 
196  // Convert to graph coordinates
197  QPointF pointGraph, pointGraphDelta;
198  transformScreenToRawGraph (cursorScreen,
199  pointGraph);
200  transformScreenToRawGraph (cursorScreenDelta,
201  pointGraphDelta);
202 
203  // Compute graph resolutions at cursor
204  double resolutionXGraph = qAbs ((pointGraphDelta.x () - pointGraph.x ()) / X_DELTA_PIXELS);
205  double resolutionYGraph = qAbs ((pointGraphDelta.y () - pointGraph.y ()) / Y_DELTA_PIXELS);
206 
207  // Formatting for date/time and degrees/minutes/seconds is only done on coordinates, and not on resolution
208  FormatCoordsUnits format;
209  QString xThetaFormatted, yRadiusFormatted;
210  format.unformattedToFormatted (pointGraph.x(),
211  pointGraph.y(),
212  m_modelCoords,
213  m_modelGeneral,
214  m_modelMainWindow,
215  xThetaFormatted,
216  yRadiusFormatted,
217  *this);
218 
219  coordsGraph = QString ("(%1, %2)")
220  .arg (xThetaFormatted)
221  .arg (yRadiusFormatted);
222 
223  resolutionsGraph = QString ("(%1, %2)")
224  .arg (resolutionXGraph, UNCONSTRAINED_FIELD_WIDTH, FORMAT, PRECISION_DIGITS)
225  .arg (resolutionYGraph, UNCONSTRAINED_FIELD_WIDTH, FORMAT, PRECISION_DIGITS);
226 
227  } else {
228 
229  coordsGraph = QString ("<font color=\"red\">%1</font>")
230  .arg (QObject::tr ("Need more axis points"));
231  resolutionsGraph = coordsGraph;
232 
233  }
234  }
235 }
236 
238 {
239  // Initialize assuming points (0,0) (1,0) (0,1)
240  m_transformIsDefined = true;
241 
242  QTransform ident;
243  m_transform = ident;
244 }
245 
247 {
248  return qLn (xy);
249 }
250 
252  double rCenter)
253 {
254  return qLn (r) - qLn (rCenter);
255 }
256 
258 {
259  return m_modelCoords;
260 }
261 
263 {
264  return m_modelGeneral;
265 }
266 
268 {
269  return m_modelMainWindow;
270 }
271 
272 ostringstream &operator<<(ostringstream &strOuter,
273  const Transformation &transformation)
274 {
275  QString text;
276  QTextStream strInner (&text);
277  transformation.printStream ("", strInner);
278 
279  strOuter << text.toLatin1().data ();
280 
281  return strOuter;
282 }
283 
284 void Transformation::printStream (QString indentation,
285  QTextStream &str) const
286 {
287  str << "Transformation\n";
288 
289  indentation += INDENTATION_DELTA;
290 
291  if (m_transformIsDefined) {
292 
293  str << indentation << "affine=" << (m_transform.isAffine() ? "yes" : "no") << " matrix=("
294  << m_transform.m11() << ", " << m_transform.m12() << ", " << m_transform.m13() << ", "
295  << m_transform.m21() << ", " << m_transform.m22() << ", " << m_transform.m23() << ", "
296  << m_transform.m31() << ", " << m_transform.m32() << ", " << m_transform.m33() << ")";
297 
298  } else {
299 
300  str << indentation << "undefined";
301 
302  }
303 }
304 
306 {
307  LOG4CPP_INFO_S ((*mainCat)) << "Transformation::resetOnLoad";
308 
309  m_transformIsDefined = false;
310 }
311 
312 double Transformation::roundOffSmallValues (double value, double range)
313 {
314  if (qAbs (value) < range / qPow (10.0, PRECISION_DIGITS)) {
315  value = 0.0;
316  }
317 
318  return value;
319 }
320 
321 void Transformation::setModelCoords (const DocumentModelCoords &modelCoords,
322  const DocumentModelGeneral &modelGeneral,
323  const MainWindowModel &modelMainWindow)
324 {
325  m_modelCoords = modelCoords;
326  m_modelGeneral = modelGeneral;
327  m_modelMainWindow = modelMainWindow;
328 }
329 
331 {
332  return m_transformIsDefined;
333 }
334 
335 void Transformation::transformLinearCartesianGraphToRawGraph (const QPointF &pointLinearCartesianGraph,
336  QPointF &pointRawGraph) const
337 {
338  // WARNING - the code in this method must mirror the code in transformRawGraphToLinearCartesianGraph. In
339  // other words, making a change here without a corresponding change there will produce a bug
340 
341  pointRawGraph = pointLinearCartesianGraph;
342 
343  // Apply polar coordinates if appropriate
344  if (m_modelCoords.coordsType() == COORDS_TYPE_POLAR) {
345  pointRawGraph = cartesianOrPolarFromCartesian (m_modelCoords,
346  pointRawGraph);
347  }
348 
349  // Apply linear offset to radius if appropriate
350  if ((m_modelCoords.coordsType() == COORDS_TYPE_POLAR) &&
351  (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR)) {
352  pointRawGraph.setY (pointRawGraph.y() + m_modelCoords.originRadius());
353  }
354 
355  // Apply log scaling if appropriate
356  if (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LOG) {
357  pointRawGraph.setX (qExp (pointRawGraph.x()));
358  }
359 
360  if (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG) {
361  double offset;
362  if (m_modelCoords.coordsType() == COORDS_TYPE_CARTESIAN) {
363  // Cartesian
364  offset = ZERO_OFFSET_AFTER_LOG;
365  } else {
366  // Polar radius
367  offset = m_modelCoords.originRadius();
368  }
369 
370  pointRawGraph.setY (qExp (pointRawGraph.y() + qLn (offset)));
371  }
372 }
373 
375  QPointF &coordScreen) const
376 {
377  ENGAUGE_ASSERT (m_transformIsDefined);
378 
379  coordScreen = m_transform.inverted ().transposed ().map (coordGraph);
380 }
381 
383 {
384  return m_transform;
385 }
386 
388  QPointF &pointLinearCartesian) const
389 {
390  // WARNING - the code in this method must mirror the code in transformLinearCartesianGraphToRawGraph. In
391  // other words, making a change here without a corresponding change there will produce a bug
392 
393  double x = pointRaw.x();
394  double y = pointRaw.y();
395 
396  // Apply linear offset to radius if appropriate
397  if ((m_modelCoords.coordsType() == COORDS_TYPE_POLAR) &&
398  (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR)) {
399  y -= m_modelCoords.originRadius();
400  }
401 
402  // Apply log scaling if appropriate
403  if (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LOG) {
404  x = logToLinearCartesian (x);
405  }
406 
407  if (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG) {
408  if (m_modelCoords.coordsType() == COORDS_TYPE_POLAR) {
409  y = logToLinearRadius (y,
410  m_modelCoords.originRadius());
411  } else {
412  y = logToLinearRadius (y,
413  ZERO_OFFSET_AFTER_LOG);
414  }
415  }
416 
417  // Apply polar coordinates if appropriate. Note range coordinate has just been transformed if it has log scaling
418  if (m_modelCoords.coordsType() == COORDS_TYPE_POLAR) {
419  QPointF pointCart = cartesianFromCartesianOrPolar (m_modelCoords,
420  QPointF (x, y));
421  x = pointCart.x();
422  y = pointCart.y();
423  }
424 
425  pointLinearCartesian.setX (x);
426  pointLinearCartesian.setY (y);
427 }
428 
429 void Transformation::transformRawGraphToScreen (const QPointF &pointRaw,
430  QPointF &pointScreen) const
431 {
432  QPointF pointLinearCartesianGraph;
433 
435  pointLinearCartesianGraph);
436  transformLinearCartesianGraphToScreen (pointLinearCartesianGraph,
437  pointScreen);
438 }
439 
441  QPointF &coordGraph) const
442 {
443  ENGAUGE_ASSERT (m_transformIsDefined);
444 
445  coordGraph = m_transform.transposed ().map (coordScreen);
446 }
447 
448 void Transformation::transformScreenToRawGraph (const QPointF &coordScreen,
449  QPointF &coordGraph) const
450 {
451  QPointF pointLinearCartesianGraph;
453  pointLinearCartesianGraph);
454  transformLinearCartesianGraphToRawGraph (pointLinearCartesianGraph,
455  coordGraph);
456 }
457 
458 void Transformation::update (bool fileIsLoaded,
459  const CmdMediator &cmdMediator,
460  const MainWindowModel &modelMainWindow)
461 {
462  LOG4CPP_DEBUG_S ((*mainCat)) << "Transformation::update";
463 
464  if (!fileIsLoaded) {
465 
466  m_transformIsDefined = false;
467 
468  } else {
469 
470  setModelCoords (cmdMediator.document().modelCoords(),
471  cmdMediator.document().modelGeneral(),
473 
474  CallbackUpdateTransform ftor (m_modelCoords,
475  cmdMediator.document().documentAxesPointsRequired());
476 
477  Functor2wRet<const QString &, const Point&, CallbackSearchReturn> ftorWithCallback = functor_ret (ftor,
479  cmdMediator.iterateThroughCurvePointsAxes (ftorWithCallback);
480 
481  if (ftor.transformIsDefined ()) {
482 
483  updateTransformFromMatrices (ftor.matrixScreen(),
484  ftor.matrixGraph());
485  } else {
486 
487  m_transformIsDefined = false;
488 
489  }
490  }
491 }
492 
493 void Transformation::updateTransformFromMatrices (const QTransform &matrixScreen,
494  const QTransform &matrixGraph)
495 {
496  // LOG4CPP_INFO_S is below
497 
498  m_transformIsDefined = true;
499 
500  // Extract points from 3x3 matrices
501  QPointF pointGraphRaw0 (matrixGraph.m11(),
502  matrixGraph.m21());
503  QPointF pointGraphRaw1 (matrixGraph.m12(),
504  matrixGraph.m22());
505  QPointF pointGraphRaw2 (matrixGraph.m13(),
506  matrixGraph.m23());
507 
508  QPointF pointGraphLinearCart0, pointGraphLinearCart1, pointGraphLinearCart2;
510  pointGraphLinearCart0);
512  pointGraphLinearCart1);
514  pointGraphLinearCart2);
515 
516  // Calculate the transform
517  m_transform = calculateTransformFromLinearCartesianPoints (QPointF (matrixScreen.m11(), matrixScreen.m21()),
518  QPointF (matrixScreen.m12(), matrixScreen.m22()),
519  QPointF (matrixScreen.m13(), matrixScreen.m23()),
520  QPointF (pointGraphLinearCart0.x(), pointGraphLinearCart0.y()),
521  QPointF (pointGraphLinearCart1.x(), pointGraphLinearCart1.y()),
522  QPointF (pointGraphLinearCart2.x(), pointGraphLinearCart2.y()));
523 
524  // Logging
525  QTransform matrixGraphLinear (pointGraphLinearCart0.x(),
526  pointGraphLinearCart1.x(),
527  pointGraphLinearCart2.x(),
528  pointGraphLinearCart0.y(),
529  pointGraphLinearCart1.y(),
530  pointGraphLinearCart2.y(),
531  1.0,
532  1.0);
533 
534  QPointF pointScreenRoundTrip0, pointScreenRoundTrip1, pointScreenRoundTrip2;
535  transformRawGraphToScreen (pointGraphRaw0,
536  pointScreenRoundTrip0);
537  transformRawGraphToScreen (pointGraphRaw1,
538  pointScreenRoundTrip1);
539  transformRawGraphToScreen (pointGraphRaw2,
540  pointScreenRoundTrip2);
541 
542  QPointF pointScreen0 (matrixScreen.m11(),
543  matrixScreen.m21());
544  QPointF pointScreen1 (matrixScreen.m12(),
545  matrixScreen.m22());
546  QPointF pointScreen2 (matrixScreen.m13(),
547  matrixScreen.m23());
548 
549  LOG4CPP_INFO_S ((*mainCat)) << "Transformation::updateTransformFromMatrices"
550  << " matrixScreen=\n" << QTransformToString (matrixScreen).toLatin1().data () << " "
551  << " matrixGraphRaw=\n" << QTransformToString (matrixGraph).toLatin1().data() << " "
552  << " matrixGraphLinear=\n" << QTransformToString (matrixGraphLinear).toLatin1().data() << "\n"
553  << " originalScreen0=" << QPointFToString (pointScreen0).toLatin1().data() << "\n"
554  << " originalScreen1=" << QPointFToString (pointScreen1).toLatin1().data() << "\n"
555  << " originalScreen2=" << QPointFToString (pointScreen2).toLatin1().data() << "\n"
556  << " roundTripScreen0=" << QPointFToString (pointScreenRoundTrip0).toLatin1().data() << "\n"
557  << " roundTripScreen1=" << QPointFToString (pointScreenRoundTrip1).toLatin1().data() << "\n"
558  << " roundTripScreen2=" << QPointFToString (pointScreenRoundTrip2).toLatin1().data() << "\n";
559 }
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.