Engauge Digitizer 2
Loading...
Searching...
No Matches
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"
12#include "EngaugeAssert.h"
13#include "ExportFileFunctions.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
29using namespace std;
30
32{
33}
34
35void 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
83void 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
231void 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
247double 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
321void 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
392void 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
520void 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
567void 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
631void 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
700bool 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
719bool 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}
@ COORD_SCALE_LOG
Definition: CoordScale.h:14
@ CONNECT_AS_FUNCTION_STRAIGHT
@ CONNECT_AS_FUNCTION_SMOOTH
QHash< QString, double > CurveLimits
Definition: CurveLimits.h:14
#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
QString exportDelimiterToText(ExportDelimiter exportDelimiter, bool isGnuplotDelimiter)
@ EXPORT_HEADER_NONE
Definition: ExportHeader.h:13
@ EXPORT_HEADER_GNUPLOT
Definition: ExportHeader.h:15
@ EXPORT_LAYOUT_ALL_PER_LINE
@ EXPORT_POINTS_SELECTION_FUNCTIONS_RAW
@ EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_GRID_LINES
QList< double > ExportValuesXOrY
log4cpp::Category * mainCat
Definition: Logger.cpp:14
QList< Point > Points
Definition: Points.h:13
QMap< double, bool > ValuesVectorXOrY
CurveLimits curveLimitsMax() const
Endpoint maxima for each curve, if extrapolation has been disabled.
ValuesVectorXOrY xThetaValuesRaw() const
Resulting x/theta values for all included functions.
CurveLimits curveLimitsMin() const
Endpoint minima for each curve, if extrapolation has been disabled.
Callback for collecting X/Theta independent variables, for functions, in preparation for exporting,...
virtual CallbackSearchReturn callback(const QString &curveName, const Point &point)
Callback method.
Callback for collecting X/Theta independent variables, for functions, in preparation for exporting,...
virtual CallbackSearchReturn callback(const QString &curveName, const Point &point)
Callback method.
LineStyle lineStyle() const
Get method for LineStyle.
Definition: CurveStyle.cpp:26
Container for one set of digitized Points.
Definition: Curve.h:34
CurveStyle curveStyle() const
Return the curve style.
Definition: Curve.cpp:149
const Points points() const
Return a shallow copy of the Points.
Definition: Curve.cpp:451
Model for DlgSettingsCoords and CmdSettingsCoords.
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
Model for DlgSettingsExportFormat and CmdSettingsExportFormat.
ExportHeader header() const
Get method for header.
QString xLabel() const
Get method for x label.
ExportPointsSelectionFunctions pointsSelectionFunctions() const
Get method for point selection for functions.
ExportDelimiter delimiter() const
Get method for delimiter.
ExportLayoutFunctions layoutFunctions() const
Get method for functions layout.
Model for DlgSettingsGeneral and CmdSettingsGeneral.
Storage of one imported image and the data attached to that image.
Definition: Document.h:42
DocumentModelGeneral modelGeneral() const
Get method for DocumentModelGeneral.
Definition: Document.cpp:723
void iterateThroughCurvesPointsGraphs(const Functor2wRet< const QString &, const Point &, CallbackSearchReturn > &ftorWithCallback)
See Curve::iterateThroughCurvePoints, for all the graphs curves.
Definition: Document.cpp:472
QStringList curvesGraphsNames() const
See CurvesGraphs::curvesGraphsNames.
Definition: Document.cpp:349
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition: Document.cpp:695
const Curve * curveForCurveName(const QString &curveName) const
See CurvesGraphs::curveForCurveNames, although this also works for AXIS_CURVE_NAME.
Definition: Document.cpp:335
void destroy2DArray(QVector< QVector< QString * > > &array) const
Deallocate memory for array.
double linearlyInterpolateYRadiusFromTwoPoints(double xThetaValue, const DocumentModelCoords &modelCoords, const QPointF &posGraphBefore, const QPointF &posGraph) const
Interpolate (if xThetaValue is between posGraphBefore.x() and posGraph.x()) or extrapolate (if xTheta...
QString wrapInDoubleQuotesIfNeeded(const DocumentModelExportFormat &modelExportOverride, const QString &valueString) const
RFC 4180 says if values are delimited by a comma AND a value has commas in it (for locale like Englis...
QString gnuplotComment() const
Gnuplot comment delimiter.
QStringList curvesToInclude(const DocumentModelExportFormat &modelExportOverride, const Document &document, const QStringList &curvesGraphsNames, CurveConnectAs curveConnectAs1, CurveConnectAs curveConnectAs2) const
Identify curves to include in export. The specified DocumentModelExportFormat overrides same data in ...
void insertLineSeparator(bool isFirst, ExportHeader exportHeader, QTextStream &str) const
Insert line(s) between successive sets of curves.
ExportFileFunctions()
Single constructor.
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.
Utility class to interpolate points spaced evenly along a piecewise defined curve with fitted spline.
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...
Creates the set of merged x/theta values for exporting functions, using interpolation.
ExportValuesXOrY xThetaValues() const
Resulting x/theta values for all included functions.
Highest-level wrapper around other Formats classes.
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...
CurveConnectAs curveConnectAs() const
Get method for connect type.
Definition: LineStyle.cpp:63
Warps log coordinates to make them linear before passing them to code that accepts only linear coordi...
Definition: LinearToLog.h:14
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
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
Model for DlgSettingsMainWindow.
Class that represents one digitized point. The screen-to-graph coordinate transformation is always ex...
Definition: Point.h:26
QPointF posScreen() const
Accessor for screen position.
Definition: Point.cpp:404
Single X/Y pair for cubic spline interpolation initialization and calculations.
Definition: SplinePair.h:14
double y() const
Get method for y.
Definition: SplinePair.cpp:88
Cubic interpolation given independent and dependent value vectors.
Definition: Spline.h:30
Affine transformation between screen and graph coordinates, based on digitized axis points.
void transformScreenToRawGraph(const QPointF &coordScreen, QPointF &coordGraph) const
Transform from cartesian pixel screen coordinates to cartesian/polar graph coordinates.
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
#define LOG4CPP_INFO_S(logger)
Definition: convenience.h:18