Engauge Digitizer  2
ExportFileFunctions.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 
9 #include "CurveConnectAs.h"
10 #include "Document.h"
11 #include "DocumentModelGeneral.h"
12 #include "EngaugeAssert.h"
13 #include "ExportFileFunctions.h"
14 #include "ExportLayoutFunctions.h"
15 #include "ExportOrdinalsSmooth.h"
17 #include "FormatCoordsUnits.h"
18 #include "GridLineLimiter.h"
19 #include "LinearToLog.h"
20 #include "Logger.h"
21 #include <qmath.h>
22 #include <QTextStream>
23 #include <QVector>
24 #include "Spline.h"
25 #include "SplinePair.h"
26 #include "Transformation.h"
27 #include <vector>
28 
29 using namespace std;
30 
32 {
33 }
34 
35 void ExportFileFunctions::exportAllPerLineXThetaValuesMerged (const DocumentModelExportFormat &modelExportOverride,
36  const Document &document,
37  const MainWindowModel &modelMainWindow,
38  const QStringList &curvesIncluded,
39  const ExportValuesXOrY &xThetaValues,
40  const QString &delimiter,
41  const Transformation &transformation,
42  bool isLogXTheta,
43  bool isLogYRadius,
44  const CurveLimits curveLimitsMin,
45  const CurveLimits curveLimitsMax,
46  QTextStream &str,
47  unsigned int &numWritesSoFar) const
48 {
49  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::exportAllPerLineXThetaValuesMerged";
50 
51  int curveCount = curvesIncluded.count();
52  int xThetaCount = xThetaValues.count();
53  QVector<QVector<QString*> > yRadiusValues (curveCount, QVector<QString*> (xThetaCount));
54  initializeYRadiusValues (curvesIncluded,
55  xThetaValues,
56  yRadiusValues);
57  loadYRadiusValues (modelExportOverride,
58  document,
59  modelMainWindow,
60  curvesIncluded,
61  transformation,
62  isLogXTheta,
63  isLogYRadius,
64  xThetaValues,
65  curveLimitsMin,
66  curveLimitsMax,
67  yRadiusValues);
68 
69  outputXThetaYRadiusValues (modelExportOverride,
70  document.modelCoords(),
71  document.modelGeneral(),
72  modelMainWindow,
73  curvesIncluded,
74  xThetaValues,
75  transformation,
76  yRadiusValues,
77  delimiter,
78  str,
79  numWritesSoFar);
80  destroy2DArray (yRadiusValues);
81 }
82 
83 void ExportFileFunctions::exportOnePerLineXThetaValuesMerged (const DocumentModelExportFormat &modelExportOverride,
84  const Document &document,
85  const MainWindowModel &modelMainWindow,
86  const QStringList &curvesIncluded,
87  const ExportValuesXOrY &xThetaValues,
88  const QString &delimiter,
89  const Transformation &transformation,
90  bool isLogXTheta,
91  bool isLogYRadius,
92  const CurveLimits curveLimitsMin,
93  const CurveLimits curveLimitsMax,
94  QTextStream &str,
95  unsigned int &numWritesSoFar) const
96 {
97  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::exportOnePerLineXThetaValuesMerged";
98 
99  QStringList::const_iterator itr;
100  for (itr = curvesIncluded.begin(); itr != curvesIncluded.end(); itr++) {
101 
102  // This curve
103  const int CURVE_COUNT = 1;
104  QString curveIncluded = *itr;
105  QStringList curvesIncludedIter (curveIncluded);
106 
107  int xThetaCount = xThetaValues.count();
108  QVector<QVector<QString*> > yRadiusValues (CURVE_COUNT, QVector<QString*> (xThetaCount));
109  initializeYRadiusValues (curvesIncludedIter,
110  xThetaValues,
111  yRadiusValues);
112  loadYRadiusValues (modelExportOverride,
113  document,
114  modelMainWindow,
115  curvesIncludedIter,
116  transformation,
117  isLogXTheta,
118  isLogYRadius,
119  xThetaValues,
120  curveLimitsMin,
121  curveLimitsMax,
122  yRadiusValues);
123  outputXThetaYRadiusValues (modelExportOverride,
124  document.modelCoords(),
125  document.modelGeneral(),
126  modelMainWindow,
127  curvesIncludedIter,
128  xThetaValues,
129  transformation,
130  yRadiusValues,
131  delimiter,
132  str,
133  numWritesSoFar);
134  destroy2DArray (yRadiusValues);
135  }
136 }
137 
139  const Document &document,
140  const MainWindowModel &modelMainWindow,
141  const Transformation &transformation,
142  QTextStream &str,
143  unsigned int &numWritesSoFar) const
144 {
145  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::exportToFile";
146 
147  // Log coordinates must be temporarily transformed to linear coordinates
148  bool isLogXTheta = (document.modelCoords().coordScaleXTheta() == COORD_SCALE_LOG);
149  bool isLogYRadius = (document.modelCoords().coordScaleYRadius() == COORD_SCALE_LOG);
150 
151  // Identify curves to be included
152  QStringList curvesIncluded = curvesToInclude (modelExportOverride,
153  document,
154  document.curvesGraphsNames(),
157 
158  // Delimiter
159  const QString delimiter = exportDelimiterToText (modelExportOverride.delimiter(),
160  modelExportOverride.header() == EXPORT_HEADER_GNUPLOT);
161 
162  // Get x/theta values to be used. Also get the endpoint limits, if any
163  CurveLimits curveLimitsMin, curveLimitsMax;
164  ValuesVectorXOrY valuesVector;
166  CallbackGatherXThetasInGridLines ftor (modelMainWindow,
167  modelExportOverride,
168  curvesIncluded,
169  transformation,
170  document);
171  Functor2wRet<const QString &, const Point &, CallbackSearchReturn> ftorWithCallback = functor_ret (ftor,
173  document.iterateThroughCurvesPointsGraphs(ftorWithCallback);
174  valuesVector = ftor.xThetaValuesRaw();
175  curveLimitsMin = ftor.curveLimitsMin();
176  curveLimitsMax = ftor.curveLimitsMax();
177  } else {
178  CallbackGatherXThetasInCurves ftor (modelExportOverride,
179  curvesIncluded,
180  transformation);
181  Functor2wRet<const QString &, const Point &, CallbackSearchReturn> ftorWithCallback = functor_ret (ftor,
183  document.iterateThroughCurvesPointsGraphs(ftorWithCallback);
184  valuesVector = ftor.xThetaValuesRaw();
185  curveLimitsMin = ftor.curveLimitsMin();
186  curveLimitsMax = ftor.curveLimitsMax();
187  }
188 
189  ExportXThetaValuesMergedFunctions exportXTheta (modelExportOverride,
190  valuesVector,
191  transformation);
192 
193  ExportValuesXOrY xThetaValuesMerged = exportXTheta.xThetaValues ();
194 
195  // Skip if every curve was a relation
196  if (xThetaValuesMerged.count() > 0) {
197 
198  // Export in one of two layouts
199  if (modelExportOverride.layoutFunctions() == EXPORT_LAYOUT_ALL_PER_LINE) {
200  exportAllPerLineXThetaValuesMerged (modelExportOverride,
201  document,
202  modelMainWindow,
203  curvesIncluded,
204  xThetaValuesMerged,
205  delimiter,
206  transformation,
207  isLogXTheta,
208  isLogYRadius,
209  curveLimitsMin,
210  curveLimitsMax,
211  str,
212  numWritesSoFar);
213  } else {
214  exportOnePerLineXThetaValuesMerged (modelExportOverride,
215  document,
216  modelMainWindow,
217  curvesIncluded,
218  xThetaValuesMerged,
219  delimiter,
220  transformation,
221  isLogXTheta,
222  isLogYRadius,
223  curveLimitsMin,
224  curveLimitsMax,
225  str,
226  numWritesSoFar);
227  }
228  }
229 }
230 
231 void ExportFileFunctions::initializeYRadiusValues (const QStringList &curvesIncluded,
232  const ExportValuesXOrY &xThetaValuesMerged,
233  QVector<QVector<QString*> > &yRadiusValues) const
234 {
235  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::initializeYRadiusValues";
236 
237  // Initialize every entry with empty string
238  int curveCount = curvesIncluded.count();
239  int xThetaCount = xThetaValuesMerged.count();
240  for (int row = 0; row < xThetaCount; row++) {
241  for (int col = 0; col < curveCount; col++) {
242  yRadiusValues [col] [row] = new QString;
243  }
244  }
245 }
246 
247 double ExportFileFunctions::linearlyInterpolate (const Points &points,
248  double xThetaValue,
249  const Transformation &transformation) const
250 {
251  // LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::linearlyInterpolate";
252 
253  // If point is within the range of the function points then interpolation will be used, otherwise
254  // extrapolation will be used
255  double yRadius = 0;
256  QPointF posGraphBefore; // Not set until ip=1
257  bool foundIt = false;
258  for (int ip = 0; !foundIt && (ip < points.count()); ip++) {
259 
260  const Point &point = points.at (ip);
261  QPointF posGraph;
262  transformation.transformScreenToRawGraph (point.posScreen(),
263  posGraph);
264 
265  // Cases where we have found it at this point in the code
266  // (1) interpolation case where (xBefore < xThetaValue < xAfter)
267  // (2) extrapolation case where (xThetaValue < xBefore < xAfter and ip=0) for which we delay finding it until ip=1 so we have
268  // two points for extrapolating. This case is why we have the subtle test for ip>0 in the next line
269  if (xThetaValue <= posGraph.x() && (ip > 0)) {
270 
271  foundIt = true;
272 
273  // Case 1 comments: xThetaValue is between posGraphBefore and posGraph. Note that if posGraph.x()=posGraphBefore.x() then
274  // previous iteration of loop would have been used for interpolation, and then the loop was exited. Range of s is 0<s<1
275  // Case 2 comments: Range of s is s<0
276  yRadius = linearlyInterpolateYRadiusFromTwoPoints (xThetaValue,
277  transformation.modelCoords(),
278  posGraphBefore,
279  posGraph);
280 
281  break;
282  }
283 
284  posGraphBefore = posGraph;
285  }
286 
287  if (!foundIt) {
288 
289  if (points.count() > 1) {
290 
291  // Extrapolation will be used since point is out of the range of the function points. Specifically, it is greater than the
292  // last x value in the function. Range of s is 1<s
293  int N = points.count();
294  const Point &pointLast = points.at (N - 1);
295  const Point &pointBefore = points.at (N - 2);
296  QPointF posGraphLast;
297  transformation.transformScreenToRawGraph (pointLast.posScreen(),
298  posGraphLast);
299  transformation.transformScreenToRawGraph (pointBefore.posScreen(),
300  posGraphBefore);
301  yRadius = linearlyInterpolateYRadiusFromTwoPoints (xThetaValue,
302  transformation.modelCoords(),
303  posGraphBefore,
304  posGraphLast);
305 
306  } else if (points.count() == 1) {
307 
308  // Just use the single point
309  yRadius = posGraphBefore.y();
310 
311  } else {
312 
313  ENGAUGE_ASSERT (false);
314 
315  }
316  }
317 
318  return yRadius;
319 }
320 
321 void ExportFileFunctions::loadYRadiusValues (const DocumentModelExportFormat &modelExportOverride,
322  const Document &document,
323  const MainWindowModel &modelMainWindow,
324  const QStringList &curvesIncluded,
325  const Transformation &transformation,
326  bool isLogXTheta,
327  bool isLogYRadius,
328  const ExportValuesXOrY &xThetaValues,
329  const CurveLimits &curveLimitsMin,
330  const CurveLimits &curveLimitsMax,
331  QVector<QVector<QString*> > &yRadiusValues) const
332 {
333  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::loadYRadiusValues";
334 
335  // Loop through curves
336  int curveCount = curvesIncluded.count();
337  for (int col = 0; col < curveCount; col++) {
338 
339  const QString curveName = curvesIncluded.at (col);
340 
341  const Curve *curve = document.curveForCurveName (curveName);
342  Points points = curve->points (); // These points will be linearized below if either coordinate is log
343 
345 
346  // No interpolation. Raw points
347  loadYRadiusValuesForCurveRaw (document.modelCoords(),
348  document.modelGeneral(),
349  modelMainWindow,
350  points,
351  xThetaValues,
352  transformation,
353  curveName,
354  curveLimitsMin,
355  curveLimitsMax,
356  yRadiusValues [col]);
357  } else {
358 
359  // Interpolation
361 
362  loadYRadiusValuesForCurveInterpolatedSmooth (document.modelCoords(),
363  document.modelGeneral(),
364  modelMainWindow,
365  points,
366  xThetaValues,
367  transformation,
368  isLogXTheta,
369  isLogYRadius,
370  curveName,
371  curveLimitsMin,
372  curveLimitsMax,
373  yRadiusValues [col]);
374 
375  } else {
376 
377  loadYRadiusValuesForCurveInterpolatedStraight (document.modelCoords(),
378  document.modelGeneral(),
379  modelMainWindow,
380  points,
381  xThetaValues,
382  transformation,
383  curveName,
384  curveLimitsMin,
385  curveLimitsMax,
386  yRadiusValues [col]);
387  }
388  }
389  }
390 }
391 
392 void ExportFileFunctions::loadYRadiusValuesForCurveInterpolatedSmooth (const DocumentModelCoords &modelCoords,
393  const DocumentModelGeneral &modelGeneral,
394  const MainWindowModel &modelMainWindow,
395  const Points &points,
396  const ExportValuesXOrY &xThetaValues,
397  const Transformation &transformation,
398  bool isLogXTheta,
399  bool isLogYRadius,
400  const QString &curveName,
401  const CurveLimits &curveLimitsMin,
402  const CurveLimits &curveLimitsMax,
403  QVector<QString*> &yRadiusValues) const
404 {
405  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::loadYRadiusValuesForCurveInterpolatedSmooth";
406 
407  // Convert screen coordinates to graph coordinates, in vectors suitable for spline fitting
408  vector<double> t;
409  vector<SplinePair> xy;
410  ExportOrdinalsSmooth ordinalsSmooth;
411 
412  ordinalsSmooth.loadSplinePairsWithTransformation (points,
413  transformation,
414  isLogXTheta,
415  isLogYRadius,
416  t,
417  xy);
418 
419  // Formatting
420  FormatCoordsUnits format;
421  QString dummyXThetaOut;
422 
423  if (points.count() == 0) {
424 
425  // Since there are no values, leave the field empty
426  for (int row = 0; row < xThetaValues.count(); row++) {
427  *(yRadiusValues [row]) = "";
428  }
429 
430  } else if (points.count() == 1 ||
431  points.count() == 2) {
432 
433  // Apply the single value everywhere (N=1) or do linear interpolation (N=2)
434  for (int row = 0; row < xThetaValues.count(); row++) {
435 
436  double xTheta = xThetaValues.at (row);
437  double yRadius;
438  if (points.count() == 1) {
439  yRadius = xy.at (0).y ();
440  } else {
441  double x0 = xy.at (0).x ();
442  double x1 = xy.at (1).x ();
443  double y0 = xy.at (0).y ();
444  double y1 = xy.at (1).y ();
445  double numerator = (xTheta - x0);
446  double denominator = (x1 - x0);
447  if (qAbs (denominator) < qAbs (numerator) / 1.0e6) {
448  // Cannot do linear interpolation using two points at the same x value
449  yRadius = xy.at (0).y ();
450  } else {
451  double s = numerator / denominator;
452  yRadius = (1.0 - s) * y0 + s * y1;
453  }
454  }
455  if (xThetaIsNotOutOfBounds (xTheta,
456  curveName,
457  curveLimitsMin,
458  curveLimitsMax)) {
459  format.unformattedToFormatted (xTheta,
460  yRadius,
461  modelCoords,
462  modelGeneral,
463  modelMainWindow,
464  dummyXThetaOut,
465  *(yRadiusValues [row]),
466  transformation);
467  } else {
468  *(yRadiusValues [row]) = "";
469  }
470  }
471 
472  } else {
473 
474  // Iteration accuracy versus number of iterations 8->256, 10->1024, 12->4096. Single pixel accuracy out of
475  // typical image size of 1024x1024 means around 10 iterations gives decent accuracy for numbers much bigger
476  // than 1. A value of 12 gave some differences in the least significant figures of numbers like 10^-3 in
477  // the regression tests. Toggling between 30 and 32 made no difference in the regression tests.
478  const int MAX_ITERATIONS = 32;
479 
480  // Spline class requires at least one point
481  if (xy.size() > 0) {
482 
483  // Fit a spline
484  Spline spline (t,
485  xy);
486 
487  // Get value at desired points
488  for (int row = 0; row < xThetaValues.count(); row++) {
489 
490  double xTheta = xThetaValues.at (row);
491 
492  LinearToLog linearToLog;
493 
494  SplinePair splinePairFound = spline.findSplinePairForFunctionX (linearToLog.linearize (xTheta, isLogXTheta),
495  MAX_ITERATIONS);
496  double yRadius = linearToLog.delinearize (splinePairFound.y (),
497  isLogYRadius);
498 
499  // Save y/radius value for this row into yRadiusValues, after appropriate formatting
500  if (xThetaIsNotOutOfBounds (xTheta,
501  curveName,
502  curveLimitsMin,
503  curveLimitsMax)) {
504  format.unformattedToFormatted (xTheta,
505  yRadius,
506  modelCoords,
507  modelGeneral,
508  modelMainWindow,
509  dummyXThetaOut,
510  *(yRadiusValues [row]),
511  transformation);
512  } else {
513  *(yRadiusValues [row]) = "";
514  }
515  }
516  }
517  }
518 }
519 
520 void ExportFileFunctions::loadYRadiusValuesForCurveInterpolatedStraight (const DocumentModelCoords &modelCoords,
521  const DocumentModelGeneral &modelGeneral,
522  const MainWindowModel &modelMainWindow,
523  const Points &points,
524  const ExportValuesXOrY &xThetaValues,
525  const Transformation &transformation,
526  const QString &curveName,
527  const CurveLimits &curveLimitsMin,
528  const CurveLimits &curveLimitsMax,
529  QVector<QString*> &yRadiusValues) const
530 {
531  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::loadYRadiusValuesForCurveInterpolatedStraight";
532 
533  FormatCoordsUnits format;
534 
535  // Get value at desired points
536  QString dummyXThetaOut;
537  for (int row = 0; row < xThetaValues.count(); row++) {
538 
539  double xTheta = xThetaValues.at (row);
540 
541  // Interpolation on curve with no points will trigger an assert so check the point count
542  *(yRadiusValues [row]) = "";
543  if (points.count () > 0) {
544 
545  double yRadius = linearlyInterpolate (points,
546  xTheta,
547  transformation);
548 
549  // Save y/radius value for this row into yRadiusValues, after appropriate formatting
550  if (xThetaIsNotOutOfBounds (xTheta,
551  curveName,
552  curveLimitsMin,
553  curveLimitsMax)) {
554  format.unformattedToFormatted (xTheta,
555  yRadius,
556  modelCoords,
557  modelGeneral,
558  modelMainWindow,
559  dummyXThetaOut,
560  *(yRadiusValues [row]),
561  transformation);
562  }
563  }
564  }
565 }
566 
567 void ExportFileFunctions::loadYRadiusValuesForCurveRaw (const DocumentModelCoords &modelCoords,
568  const DocumentModelGeneral &modelGeneral,
569  const MainWindowModel &modelMainWindow,
570  const Points &points,
571  const ExportValuesXOrY &xThetaValues,
572  const Transformation &transformation,
573  const QString &curveName,
574  const CurveLimits &curveLimitsMin,
575  const CurveLimits &curveLimitsMax,
576  QVector<QString*> &yRadiusValues) const
577 {
578  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::loadYRadiusValuesForCurveRaw";
579 
580  FormatCoordsUnits format;
581 
582  // Since the curve points may be a subset of xThetaValues (in which case the non-applicable xThetaValues will have
583  // blanks for the yRadiusValues), we iterate over the smaller set
584  for (int pt = 0; pt < points.count(); pt++) {
585 
586  const Point &point = points.at (pt);
587 
588  QPointF posGraph;
589  transformation.transformScreenToRawGraph (point.posScreen(),
590  posGraph);
591 
592  // Find the closest point in xThetaValues. This is probably an N-squared algorithm, which is less than optimial,
593  // but the delay should be insignificant with normal-sized export files
594  double closestSeparation = 0.0;
595  int rowClosest = 0;
596  for (int row = 0; row < xThetaValues.count(); row++) {
597 
598  double xTheta = xThetaValues.at (row);
599 
600  double separation = qAbs (posGraph.x() - xTheta);
601 
602  if ((row == 0) ||
603  (separation < closestSeparation)) {
604 
605  closestSeparation = separation;
606  rowClosest = row;
607 
608  }
609  }
610 
611  // Save y/radius value for this row into yRadiusValues, after appropriate formatting
612  if (xThetaIsNotOutOfBounds (posGraph.x(),
613  curveName,
614  curveLimitsMin,
615  curveLimitsMax)) {
616  QString dummyXThetaOut;
617  format.unformattedToFormatted (posGraph.x(),
618  posGraph.y(),
619  modelCoords,
620  modelGeneral,
621  modelMainWindow,
622  dummyXThetaOut,
623  *(yRadiusValues [rowClosest]),
624  transformation);
625  } else {
626  *(yRadiusValues [rowClosest]) = "";
627  }
628  }
629 }
630 
631 void ExportFileFunctions::outputXThetaYRadiusValues (const DocumentModelExportFormat &modelExportOverride,
632  const DocumentModelCoords &modelCoords,
633  const DocumentModelGeneral &modelGeneral,
634  const MainWindowModel &modelMainWindow,
635  const QStringList &curvesIncluded,
636  const ExportValuesXOrY &xThetaValuesMerged,
637  const Transformation &transformation,
638  QVector<QVector<QString*> > &yRadiusValues,
639  const QString &delimiter,
640  QTextStream &str,
641  unsigned int &numWritesSoFar) const
642 {
643  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::outputXThetaYRadiusValues";
644 
645  // Header
646  if (modelExportOverride.header() != EXPORT_HEADER_NONE) {
647  insertLineSeparator (numWritesSoFar == 0,
648  modelExportOverride.header (),
649  str);
650  if (modelExportOverride.header() == EXPORT_HEADER_GNUPLOT) {
651  str << gnuplotComment();
652  }
653  str << modelExportOverride.xLabel();
654  QStringList::const_iterator itrHeader;
655  for (itrHeader = curvesIncluded.begin(); itrHeader != curvesIncluded.end(); itrHeader++) {
656  QString curveName = *itrHeader;
657  str << delimiter << curveName;
658  }
659  str << "\n";
660  }
661 
662  // Table body
663  FormatCoordsUnits format;
664  const double DUMMY_Y_RADIUS = 1.0;
665 
666  for (int row = 0; row < xThetaValuesMerged.count(); row++) {
667 
668  if (rowHasAtLeastOneYRadiusEntry (yRadiusValues,
669  row)) {
670 
671  double xTheta = xThetaValuesMerged.at (row);
672 
673  // Output x/theta value for this row
674  QString xThetaString, yRadiusString;
675  format.unformattedToFormatted (xTheta,
676  DUMMY_Y_RADIUS,
677  modelCoords,
678  modelGeneral,
679  modelMainWindow,
680  xThetaString,
681  yRadiusString,
682  transformation);
683  str << wrapInDoubleQuotesIfNeeded (modelExportOverride,
684  xThetaString);
685 
686  for (int col = 0; col < yRadiusValues.count(); col++) {
687 
688  QString yRadiusString = *(yRadiusValues [col] [row]);
689  str << delimiter << wrapInDoubleQuotesIfNeeded (modelExportOverride,
690  yRadiusString);
691  }
692 
693  str << "\n";
694  }
695  }
696 
697  ++numWritesSoFar;
698 }
699 
700 bool ExportFileFunctions::rowHasAtLeastOneYRadiusEntry (const QVector<QVector<QString*> > &yRadiusValues,
701  int row) const
702 {
703  bool hasEntry = false;
704 
705  for (int col = 0; col < yRadiusValues.count(); col++) {
706 
707  QString entry = *(yRadiusValues [col] [row]);
708  if (!entry.isEmpty()) {
709 
710  hasEntry = true;
711  break;
712 
713  }
714  }
715 
716  return hasEntry;
717 }
718 
719 bool ExportFileFunctions::xThetaIsNotOutOfBounds (double xTheta,
720  const QString &curveName,
721  const CurveLimits &curveLimitsMin,
722  const CurveLimits &curveLimitsMax) const
723 {
724  bool ok = true;
725 
726  if (curveLimitsMin.contains (curveName)) {
727  ok = ok && (curveLimitsMin [curveName] <= xTheta);
728  }
729 
730  if (curveLimitsMax.contains (curveName)) {
731  ok = ok && (xTheta <= curveLimitsMax [curveName]);
732  }
733 
734  return ok;
735 }
LinearToLog::linearize
double linearize(double value, bool isLog) const
Convert log coordinates to linear. This is a noop if the input is already linear.
Definition: LinearToLog.cpp:25
ExportXThetaValuesMergedFunctions::xThetaValues
ExportValuesXOrY xThetaValues() const
Resulting x/theta values for all included functions.
Definition: ExportXThetaValuesMergedFunctions.cpp:262
DocumentModelExportFormat::pointsSelectionFunctions
ExportPointsSelectionFunctions pointsSelectionFunctions() const
Get method for point selection for functions.
Definition: DocumentModelExportFormat.cpp:253
COORD_SCALE_LOG
Definition: CoordScale.h:16
EXPORT_POINTS_SELECTION_FUNCTIONS_RAW
Definition: ExportPointsSelectionFunctions.h:18
exportDelimiterToText
QString exportDelimiterToText(ExportDelimiter exportDelimiter, bool isGnuplotDelimiter)
Definition: ExportDelimiter.cpp:35
Spline
Cubic interpolation given independent and dependent value vectors.
Definition: Spline.h:28
Document::modelGeneral
DocumentModelGeneral modelGeneral() const
Get method for DocumentModelGeneral.
Definition: Document.cpp:723
DocumentModelGeneral.h
CallbackGatherXThetasInCurves::callback
virtual CallbackSearchReturn callback(const QString &curveName, const Point &point)
Callback method.
Definition: CallbackGatherXThetasInCurves.cpp:25
CONNECT_AS_FUNCTION_SMOOTH
Definition: CurveConnectAs.h:15
ExportOrdinalsSmooth::loadSplinePairsWithTransformation
void loadSplinePairsWithTransformation(const Points &points, const Transformation &transformation, bool isLogXTheta, bool isLogYRadius, std::vector< double > &t, std::vector< SplinePair > &xy) const
Load t (=ordinal) and xy (=screen position) spline pairs, converting screen coordinates to graph coor...
Definition: ExportOrdinalsSmooth.cpp:38
CallbackGatherXThetasAbstractBase::curveLimitsMax
CurveLimits curveLimitsMax() const
Endpoint maxima for each curve, if extrapolation has been disabled.
Definition: CallbackGatherXThetasAbstractBase.cpp:50
Points
QList< Point > Points
Definition: Points.h:12
SplinePair
Single X/Y pair for cubic spline interpolation initialization and calculations.
Definition: SplinePair.h:12
LinearToLog
Warps log coordinates to make them linear before passing them to code that accepts only linear coordi...
Definition: LinearToLog.h:12
CurveStyle::lineStyle
LineStyle lineStyle() const
Get method for LineStyle.
Definition: CurveStyle.cpp:25
CallbackGatherXThetasAbstractBase::xThetaValuesRaw
ValuesVectorXOrY xThetaValuesRaw() const
Resulting x/theta values for all included functions.
Definition: CallbackGatherXThetasAbstractBase.cpp:102
Document::curveForCurveName
const Curve * curveForCurveName(const QString &curveName) const
See CurvesGraphs::curveForCurveNames, although this also works for AXIS_CURVE_NAME.
Definition: Document.cpp:335
Transformation::modelCoords
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition: Transformation.cpp:262
Document
Storage of one imported image and the data attached to that image.
Definition: Document.h:40
Transformation
Affine transformation between screen and graph coordinates, based on digitized axis points.
Definition: Transformation.h:30
Document.h
EngaugeAssert.h
Curve::points
const Points points() const
Return a shallow copy of the Points.
Definition: Curve.cpp:451
CallbackGatherXThetasInGridLines
Callback for collecting X/Theta independent variables, for functions, in preparation for exporting,...
Definition: CallbackGatherXThetasInGridLines.h:27
Curve
Container for one set of digitized Points.
Definition: Curve.h:32
ExportXThetaValuesMergedFunctions
Creates the set of merged x/theta values for exporting functions, using interpolation.
Definition: ExportXThetaValuesMergedFunctions.h:18
MainWindowModel
Model for DlgSettingsMainWindow.
Definition: MainWindowModel.h:29
LinearToLog::delinearize
double delinearize(double value, bool isLog) const
Convert linear coordinates to log. This is a noop if the output is supposed to be linear.
Definition: LinearToLog.cpp:14
ExportFileFunctions.h
ExportLayoutFunctions.h
CONNECT_AS_FUNCTION_STRAIGHT
Definition: CurveConnectAs.h:16
Transformation.h
DocumentModelExportFormat::layoutFunctions
ExportLayoutFunctions layoutFunctions() const
Get method for functions layout.
Definition: DocumentModelExportFormat.cpp:134
DocumentModelGeneral
Model for DlgSettingsGeneral and CmdSettingsGeneral.
Definition: DocumentModelGeneral.h:15
CurveLimits
QHash< QString, double > CurveLimits
Definition: CurveLimits.h:13
ExportFileFunctions::exportToFile
void exportToFile(const DocumentModelExportFormat &modelExportOverride, const Document &document, const MainWindowModel &modelMainWindow, const Transformation &transformation, QTextStream &str, unsigned int &numWritesSoFar) const
Export Document points according to the settings.
Definition: ExportFileFunctions.cpp:138
Point::posScreen
QPointF posScreen() const
Accessor for screen position.
Definition: Point.cpp:404
Logger.h
FormatCoordsUnits::unformattedToFormatted
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...
Definition: FormatCoordsUnits.cpp:63
FormatCoordsUnits.h
CallbackGatherXThetasInCurves.h
ExportValuesXOrY
QList< double > ExportValuesXOrY
Definition: ExportValuesXOrY.h:11
LOG4CPP_INFO_S
#define LOG4CPP_INFO_S(logger)
Definition: convenience.h:18
EXPORT_LAYOUT_ALL_PER_LINE
Definition: ExportLayoutFunctions.h:7
DocumentModelCoords::coordScaleYRadius
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
Definition: DocumentModelCoords.cpp:89
CallbackGatherXThetasInCurves
Callback for collecting X/Theta independent variables, for functions, in preparation for exporting,...
Definition: CallbackGatherXThetasInCurves.h:24
DocumentModelExportFormat
Model for DlgSettingsExportFormat and CmdSettingsExportFormat.
Definition: DocumentModelExportFormat.h:22
ExportFileFunctions::ExportFileFunctions
ExportFileFunctions()
Single constructor.
Definition: ExportFileFunctions.cpp:31
DocumentModelExportFormat::xLabel
QString xLabel() const
Get method for x label.
Definition: DocumentModelExportFormat.cpp:402
CallbackGatherXThetasInGridLines::callback
virtual CallbackSearchReturn callback(const QString &curveName, const Point &point)
Callback method.
Definition: CallbackGatherXThetasInGridLines.cpp:73
ExportOrdinalsSmooth.h
EXPORT_HEADER_GNUPLOT
Definition: ExportHeader.h:17
mainCat
log4cpp::Category * mainCat
Definition: Logger.cpp:14
Document::iterateThroughCurvesPointsGraphs
void iterateThroughCurvesPointsGraphs(const Functor2wRet< const QString &, const Point &, CallbackSearchReturn > &ftorWithCallback)
See Curve::iterateThroughCurvePoints, for all the graphs curves.
Definition: Document.cpp:472
EXPORT_HEADER_NONE
Definition: ExportHeader.h:15
Transformation::transformScreenToRawGraph
void transformScreenToRawGraph(const QPointF &coordScreen, QPointF &coordGraph) const
Transform from cartesian pixel screen coordinates to cartesian/polar graph coordinates.
Definition: Transformation.cpp:453
DocumentModelCoords::coordScaleXTheta
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
Definition: DocumentModelCoords.cpp:84
DocumentModelExportFormat::delimiter
ExportDelimiter delimiter() const
Get method for delimiter.
Definition: DocumentModelExportFormat.cpp:119
FormatCoordsUnits
Highest-level wrapper around other Formats classes.
Definition: FormatCoordsUnits.h:16
CallbackGatherXThetasInGridLines.h
CurveConnectAs.h
SplinePair::y
double y() const
Get method for y.
Definition: SplinePair.cpp:87
Document::modelCoords
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition: Document.cpp:695
Point
Class that represents one digitized point. The screen-to-graph coordinate transformation is always ex...
Definition: Point.h:24
CallbackGatherXThetasAbstractBase::curveLimitsMin
CurveLimits curveLimitsMin() const
Endpoint minima for each curve, if extrapolation has been disabled.
Definition: CallbackGatherXThetasAbstractBase.cpp:55
LinearToLog.h
DocumentModelExportFormat::header
ExportHeader header() const
Get method for header.
Definition: DocumentModelExportFormat.cpp:129
Document::curvesGraphsNames
QStringList curvesGraphsNames() const
See CurvesGraphs::curvesGraphsNames.
Definition: Document.cpp:349
SplinePair.h
LineStyle::curveConnectAs
CurveConnectAs curveConnectAs() const
Get method for connect type.
Definition: LineStyle.cpp:63
DocumentModelCoords
Model for DlgSettingsCoords and CmdSettingsCoords.
Definition: DocumentModelCoords.h:19
Curve::curveStyle
CurveStyle curveStyle() const
Return the curve style.
Definition: Curve.cpp:149
EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_GRID_LINES
Definition: ExportPointsSelectionFunctions.h:19
ENGAUGE_ASSERT
#define ENGAUGE_ASSERT(cond)
Drop in replacement for Q_ASSERT if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS) define ENGAUGE...
Definition: EngaugeAssert.h:19
ExportOrdinalsSmooth
Utility class to interpolate points spaced evenly along a piecewise defined curve with fitted spline.
Definition: ExportOrdinalsSmooth.h:19
ExportXThetaValuesMergedFunctions.h
ValuesVectorXOrY
QMap< double, bool > ValuesVectorXOrY
Definition: ValuesVectorXOrY.h:13
Spline.h
GridLineLimiter.h