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