00001
00002
00003
00004
00005
00006
00007 #include "CallbackGatherXThetaValuesFunctions.h"
00008 #include "CurveConnectAs.h"
00009 #include "Document.h"
00010 #include "DocumentModelGeneral.h"
00011 #include "EngaugeAssert.h"
00012 #include "ExportFileFunctions.h"
00013 #include "ExportLayoutFunctions.h"
00014 #include "ExportOrdinalsSmooth.h"
00015 #include "ExportXThetaValuesMergedFunctions.h"
00016 #include "FormatCoordsUnits.h"
00017 #include "LinearToLog.h"
00018 #include "Logger.h"
00019 #include <QTextStream>
00020 #include <QVector>
00021 #include "Spline.h"
00022 #include "SplinePair.h"
00023 #include "Transformation.h"
00024 #include <vector>
00025
00026 using namespace std;
00027
00028 ExportFileFunctions::ExportFileFunctions()
00029 {
00030 }
00031
00032 void ExportFileFunctions::exportAllPerLineXThetaValuesMerged (const DocumentModelExportFormat &modelExportOverride,
00033 const Document &document,
00034 const MainWindowModel &modelMainWindow,
00035 const QStringList &curvesIncluded,
00036 const ExportValuesXOrY &xThetaValues,
00037 const QString &delimiter,
00038 const Transformation &transformation,
00039 bool isLogXTheta,
00040 bool isLogYRadius,
00041 QTextStream &str,
00042 unsigned int &numWritesSoFar) const
00043 {
00044 LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::exportAllPerLineXThetaValuesMerged";
00045
00046 int curveCount = curvesIncluded.count();
00047 int xThetaCount = xThetaValues.count();
00048 QVector<QVector<QString*> > yRadiusValues (curveCount, QVector<QString*> (xThetaCount));
00049 initializeYRadiusValues (curvesIncluded,
00050 xThetaValues,
00051 yRadiusValues);
00052 loadYRadiusValues (modelExportOverride,
00053 document,
00054 modelMainWindow,
00055 curvesIncluded,
00056 transformation,
00057 isLogXTheta,
00058 isLogYRadius,
00059 xThetaValues,
00060 yRadiusValues);
00061
00062 outputXThetaYRadiusValues (modelExportOverride,
00063 document.modelCoords(),
00064 document.modelGeneral(),
00065 modelMainWindow,
00066 curvesIncluded,
00067 xThetaValues,
00068 transformation,
00069 yRadiusValues,
00070 delimiter,
00071 str,
00072 numWritesSoFar);
00073 destroy2DArray (yRadiusValues);
00074 }
00075
00076 void ExportFileFunctions::exportOnePerLineXThetaValuesMerged (const DocumentModelExportFormat &modelExportOverride,
00077 const Document &document,
00078 const MainWindowModel &modelMainWindow,
00079 const QStringList &curvesIncluded,
00080 const ExportValuesXOrY &xThetaValues,
00081 const QString &delimiter,
00082 const Transformation &transformation,
00083 bool isLogXTheta,
00084 bool isLogYRadius,
00085 QTextStream &str,
00086 unsigned int &numWritesSoFar) const
00087 {
00088 LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::exportOnePerLineXThetaValuesMerged";
00089
00090 QStringList::const_iterator itr;
00091 for (itr = curvesIncluded.begin(); itr != curvesIncluded.end(); itr++) {
00092
00093
00094 const int CURVE_COUNT = 1;
00095 QString curveIncluded = *itr;
00096 QStringList curvesIncluded (curveIncluded);
00097
00098 int xThetaCount = xThetaValues.count();
00099 QVector<QVector<QString*> > yRadiusValues (CURVE_COUNT, QVector<QString*> (xThetaCount));
00100 initializeYRadiusValues (curvesIncluded,
00101 xThetaValues,
00102 yRadiusValues);
00103 loadYRadiusValues (modelExportOverride,
00104 document,
00105 modelMainWindow,
00106 curvesIncluded,
00107 transformation,
00108 isLogXTheta,
00109 isLogYRadius,
00110 xThetaValues,
00111 yRadiusValues);
00112 outputXThetaYRadiusValues (modelExportOverride,
00113 document.modelCoords(),
00114 document.modelGeneral(),
00115 modelMainWindow,
00116 curvesIncluded,
00117 xThetaValues,
00118 transformation,
00119 yRadiusValues,
00120 delimiter,
00121 str,
00122 numWritesSoFar);
00123 destroy2DArray (yRadiusValues);
00124 }
00125 }
00126
00127 void ExportFileFunctions::exportToFile (const DocumentModelExportFormat &modelExportOverride,
00128 const Document &document,
00129 const MainWindowModel &modelMainWindow,
00130 const Transformation &transformation,
00131 QTextStream &str,
00132 unsigned int &numWritesSoFar) const
00133 {
00134 LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::exportToFile";
00135
00136
00137 bool isLogXTheta = (document.modelCoords().coordScaleXTheta() == COORD_SCALE_LOG);
00138 bool isLogYRadius = (document.modelCoords().coordScaleYRadius() == COORD_SCALE_LOG);
00139
00140
00141 QStringList curvesIncluded = curvesToInclude (modelExportOverride,
00142 document,
00143 document.curvesGraphsNames(),
00144 CONNECT_AS_FUNCTION_SMOOTH,
00145 CONNECT_AS_FUNCTION_STRAIGHT);
00146
00147
00148 const QString delimiter = exportDelimiterToText (modelExportOverride.delimiter(),
00149 modelExportOverride.header() == EXPORT_HEADER_GNUPLOT);
00150
00151
00152 CallbackGatherXThetaValuesFunctions ftor (modelExportOverride,
00153 curvesIncluded,
00154 transformation);
00155 Functor2wRet<const QString &, const Point &, CallbackSearchReturn> ftorWithCallback = functor_ret (ftor,
00156 &CallbackGatherXThetaValuesFunctions::callback);
00157 document.iterateThroughCurvesPointsGraphs(ftorWithCallback);
00158
00159 ExportXThetaValuesMergedFunctions exportXTheta (modelExportOverride,
00160 ftor.xThetaValuesRaw(),
00161 transformation);
00162 ExportValuesXOrY xThetaValuesMerged = exportXTheta.xThetaValues ();
00163
00164
00165 if (xThetaValuesMerged.count() > 0) {
00166
00167
00168 if (modelExportOverride.layoutFunctions() == EXPORT_LAYOUT_ALL_PER_LINE) {
00169 exportAllPerLineXThetaValuesMerged (modelExportOverride,
00170 document,
00171 modelMainWindow,
00172 curvesIncluded,
00173 xThetaValuesMerged,
00174 delimiter,
00175 transformation,
00176 isLogXTheta,
00177 isLogYRadius,
00178 str,
00179 numWritesSoFar);
00180 } else {
00181 exportOnePerLineXThetaValuesMerged (modelExportOverride,
00182 document,
00183 modelMainWindow,
00184 curvesIncluded,
00185 xThetaValuesMerged,
00186 delimiter,
00187 transformation,
00188 isLogXTheta,
00189 isLogYRadius,
00190 str,
00191 numWritesSoFar);
00192 }
00193 }
00194 }
00195
00196 void ExportFileFunctions::initializeYRadiusValues (const QStringList &curvesIncluded,
00197 const ExportValuesXOrY &xThetaValuesMerged,
00198 QVector<QVector<QString*> > &yRadiusValues) const
00199 {
00200 LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::initializeYRadiusValues";
00201
00202
00203 int curveCount = curvesIncluded.count();
00204 int xThetaCount = xThetaValuesMerged.count();
00205 for (int row = 0; row < xThetaCount; row++) {
00206 for (int col = 0; col < curveCount; col++) {
00207 yRadiusValues [col] [row] = new QString;
00208 }
00209 }
00210 }
00211
00212 double ExportFileFunctions::linearlyInterpolate (const Points &points,
00213 double xThetaValue,
00214 const Transformation &transformation) const
00215 {
00216
00217
00218
00219
00220 double yRadius = 0;
00221 QPointF posGraphBefore;
00222 bool foundIt = false;
00223 for (int ip = 0; !foundIt && (ip < points.count()); ip++) {
00224
00225 const Point &point = points.at (ip);
00226 QPointF posGraph;
00227 transformation.transformScreenToRawGraph (point.posScreen(),
00228 posGraph);
00229
00230
00231
00232
00233
00234 if (xThetaValue <= posGraph.x() && (ip > 0)) {
00235
00236 foundIt = true;
00237
00238
00239
00240
00241 double s = (xThetaValue - posGraphBefore.x()) / (posGraph.x() - posGraphBefore.x());
00242 yRadius = (1.0 -s) * posGraphBefore.y() + s * posGraph.y();
00243
00244 break;
00245 }
00246
00247 posGraphBefore = posGraph;
00248 }
00249
00250 if (!foundIt) {
00251
00252 if (points.count() > 1) {
00253
00254
00255
00256 int N = points.count();
00257 const Point &pointLast = points.at (N - 1);
00258 const Point &pointBefore = points.at (N - 2);
00259 QPointF posGraphLast;
00260 transformation.transformScreenToRawGraph (pointLast.posScreen(),
00261 posGraphLast);
00262 transformation.transformScreenToRawGraph (pointBefore.posScreen(),
00263 posGraphBefore);
00264 double s = (xThetaValue - posGraphBefore.x()) / (posGraphLast.x() - posGraphBefore.x());
00265 yRadius = (1.0 - s) * posGraphBefore.y() + s * posGraphLast.y();
00266
00267 } else if (points.count() == 1) {
00268
00269
00270 yRadius = posGraphBefore.y();
00271
00272 } else {
00273
00274 ENGAUGE_ASSERT (false);
00275
00276 }
00277 }
00278
00279 return yRadius;
00280 }
00281
00282 void ExportFileFunctions::loadYRadiusValues (const DocumentModelExportFormat &modelExportOverride,
00283 const Document &document,
00284 const MainWindowModel &modelMainWindow,
00285 const QStringList &curvesIncluded,
00286 const Transformation &transformation,
00287 bool isLogXTheta,
00288 bool isLogYRadius,
00289 const ExportValuesXOrY &xThetaValues,
00290 QVector<QVector<QString*> > &yRadiusValues) const
00291 {
00292 LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::loadYRadiusValues";
00293
00294
00295 int curveCount = curvesIncluded.count();
00296 for (int col = 0; col < curveCount; col++) {
00297
00298 const QString curveName = curvesIncluded.at (col);
00299
00300 const Curve *curve = document.curveForCurveName (curveName);
00301 Points points = curve->points ();
00302
00303 if (modelExportOverride.pointsSelectionFunctions() == EXPORT_POINTS_SELECTION_FUNCTIONS_RAW) {
00304
00305
00306 loadYRadiusValuesForCurveRaw (document.modelCoords(),
00307 document.modelGeneral(),
00308 modelMainWindow,
00309 points,
00310 xThetaValues,
00311 transformation,
00312 yRadiusValues [col]);
00313 } else {
00314
00315
00316 if (curve->curveStyle().lineStyle().curveConnectAs() == CONNECT_AS_FUNCTION_SMOOTH) {
00317
00318 loadYRadiusValuesForCurveInterpolatedSmooth (document.modelCoords(),
00319 document.modelGeneral(),
00320 modelMainWindow,
00321 points,
00322 xThetaValues,
00323 transformation,
00324 isLogXTheta,
00325 isLogYRadius,
00326 yRadiusValues [col]);
00327
00328 } else {
00329
00330 loadYRadiusValuesForCurveInterpolatedStraight (document.modelCoords(),
00331 document.modelGeneral(),
00332 modelMainWindow,
00333 points,
00334 xThetaValues,
00335 transformation,
00336 yRadiusValues [col]);
00337 }
00338 }
00339 }
00340 }
00341
00342 void ExportFileFunctions::loadYRadiusValuesForCurveInterpolatedSmooth (const DocumentModelCoords &modelCoords,
00343 const DocumentModelGeneral &modelGeneral,
00344 const MainWindowModel &modelMainWindow,
00345 const Points &points,
00346 const ExportValuesXOrY &xThetaValues,
00347 const Transformation &transformation,
00348 bool isLogXTheta,
00349 bool isLogYRadius,
00350 QVector<QString*> &yRadiusValues) const
00351 {
00352 LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::loadYRadiusValuesForCurveInterpolatedSmooth";
00353
00354
00355 vector<double> t;
00356 vector<SplinePair> xy;
00357 ExportOrdinalsSmooth ordinalsSmooth;
00358
00359 ordinalsSmooth.loadSplinePairsWithTransformation (points,
00360 transformation,
00361 isLogXTheta,
00362 isLogYRadius,
00363 t,
00364 xy);
00365
00366
00367 FormatCoordsUnits format;
00368 QString dummyXThetaOut;
00369
00370 if (points.count() == 0) {
00371
00372
00373 for (int row = 0; row < xThetaValues.count(); row++) {
00374 *(yRadiusValues [row]) = "";
00375 }
00376
00377 } else if (points.count() == 1 ||
00378 points.count() == 2) {
00379
00380
00381 for (int row = 0; row < xThetaValues.count(); row++) {
00382
00383 double xTheta = xThetaValues.at (row);
00384 double yRadius;
00385 if (points.count() == 1) {
00386 yRadius = xy.at (0).y ();
00387 } else {
00388 double x0 = xy.at (0).x ();
00389 double x1 = xy.at (1).x ();
00390 double y0 = xy.at (0).y ();
00391 double y1 = xy.at (1).y ();
00392 if (x0 == x1) {
00393
00394 yRadius = xy.at (0).y ();
00395 } else {
00396 double s = (xTheta - x0) / (x1 - x0);
00397 yRadius = (1.0 - s) * y0 + s * y1;
00398 }
00399 }
00400 format.unformattedToFormatted (xTheta,
00401 yRadius,
00402 modelCoords,
00403 modelGeneral,
00404 modelMainWindow,
00405 dummyXThetaOut,
00406 *(yRadiusValues [row]),
00407 transformation);
00408 }
00409
00410 } else {
00411
00412
00413
00414
00415
00416 const int MAX_ITERATIONS = 32;
00417
00418
00419 if (xy.size() > 0) {
00420
00421
00422 Spline spline (t,
00423 xy);
00424
00425
00426 for (int row = 0; row < xThetaValues.count(); row++) {
00427
00428 double xTheta = xThetaValues.at (row);
00429
00430 LinearToLog linearToLog;
00431
00432 SplinePair splinePairFound = spline.findSplinePairForFunctionX (linearToLog.linearize (xTheta, isLogXTheta),
00433 MAX_ITERATIONS);
00434 double yRadius = linearToLog.delinearize (splinePairFound.y (),
00435 isLogYRadius);
00436
00437
00438 QString dummyXThetaOut;
00439 format.unformattedToFormatted (xTheta,
00440 yRadius,
00441 modelCoords,
00442 modelGeneral,
00443 modelMainWindow,
00444 dummyXThetaOut,
00445 *(yRadiusValues [row]),
00446 transformation);
00447 }
00448 }
00449 }
00450 }
00451
00452 void ExportFileFunctions::loadYRadiusValuesForCurveInterpolatedStraight (const DocumentModelCoords &modelCoords,
00453 const DocumentModelGeneral &modelGeneral,
00454 const MainWindowModel &modelMainWindow,
00455 const Points &points,
00456 const ExportValuesXOrY &xThetaValues,
00457 const Transformation &transformation,
00458 QVector<QString*> &yRadiusValues) const
00459 {
00460 LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::loadYRadiusValuesForCurveInterpolatedStraight";
00461
00462 FormatCoordsUnits format;
00463
00464
00465 for (int row = 0; row < xThetaValues.count(); row++) {
00466
00467 double xThetaValue = xThetaValues.at (row);
00468
00469 double yRadius = linearlyInterpolate (points,
00470 xThetaValue,
00471 transformation);
00472
00473
00474 QString dummyXThetaOut;
00475 format.unformattedToFormatted (xThetaValue,
00476 yRadius,
00477 modelCoords,
00478 modelGeneral,
00479 modelMainWindow,
00480 dummyXThetaOut,
00481 *(yRadiusValues [row]),
00482 transformation);
00483 }
00484 }
00485
00486 void ExportFileFunctions::loadYRadiusValuesForCurveRaw (const DocumentModelCoords &modelCoords,
00487 const DocumentModelGeneral &modelGeneral,
00488 const MainWindowModel &modelMainWindow,
00489 const Points &points,
00490 const ExportValuesXOrY &xThetaValues,
00491 const Transformation &transformation,
00492 QVector<QString*> &yRadiusValues) const
00493 {
00494 LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::loadYRadiusValuesForCurveRaw";
00495
00496 FormatCoordsUnits format;
00497
00498
00499
00500 for (int pt = 0; pt < points.count(); pt++) {
00501
00502 const Point &point = points.at (pt);
00503
00504 QPointF posGraph;
00505 transformation.transformScreenToRawGraph (point.posScreen(),
00506 posGraph);
00507
00508
00509
00510 double closestSeparation = 0.0;
00511 int rowClosest = 0;
00512 for (int row = 0; row < xThetaValues.count(); row++) {
00513
00514 double xThetaValue = xThetaValues.at (row);
00515
00516 double separation = qAbs (posGraph.x() - xThetaValue);
00517
00518 if ((row == 0) ||
00519 (separation < closestSeparation)) {
00520
00521 closestSeparation = separation;
00522 rowClosest = row;
00523
00524 }
00525 }
00526
00527
00528 QString dummyXThetaOut;
00529 format.unformattedToFormatted (posGraph.x(),
00530 posGraph.y(),
00531 modelCoords,
00532 modelGeneral,
00533 modelMainWindow,
00534 dummyXThetaOut,
00535 *(yRadiusValues [rowClosest]),
00536 transformation);
00537 }
00538 }
00539
00540 void ExportFileFunctions::outputXThetaYRadiusValues (const DocumentModelExportFormat &modelExportOverride,
00541 const DocumentModelCoords &modelCoords,
00542 const DocumentModelGeneral &modelGeneral,
00543 const MainWindowModel &modelMainWindow,
00544 const QStringList &curvesIncluded,
00545 const ExportValuesXOrY &xThetaValuesMerged,
00546 const Transformation &transformation,
00547 QVector<QVector<QString*> > &yRadiusValues,
00548 const QString &delimiter,
00549 QTextStream &str,
00550 unsigned int &numWritesSoFar) const
00551 {
00552 LOG4CPP_INFO_S ((*mainCat)) << "ExportFileFunctions::outputXThetaYRadiusValues";
00553
00554
00555 if (modelExportOverride.header() != EXPORT_HEADER_NONE) {
00556 insertLineSeparator (numWritesSoFar == 0,
00557 modelExportOverride.header (),
00558 str);
00559 if (modelExportOverride.header() == EXPORT_HEADER_GNUPLOT) {
00560 str << gnuplotComment();
00561 }
00562 str << modelExportOverride.xLabel();
00563 QStringList::const_iterator itrHeader;
00564 for (itrHeader = curvesIncluded.begin(); itrHeader != curvesIncluded.end(); itrHeader++) {
00565 QString curveName = *itrHeader;
00566 str << delimiter << curveName;
00567 }
00568 str << "\n";
00569 }
00570
00571
00572 FormatCoordsUnits format;
00573 const double DUMMY_Y_RADIUS = 1.0;
00574
00575 for (int row = 0; row < xThetaValuesMerged.count(); row++) {
00576
00577 if (rowHasAtLeastOneYRadiusEntry (yRadiusValues,
00578 row)) {
00579
00580 double xTheta = xThetaValuesMerged.at (row);
00581
00582
00583 QString xThetaString, yRadiusString;
00584 format.unformattedToFormatted (xTheta,
00585 DUMMY_Y_RADIUS,
00586 modelCoords,
00587 modelGeneral,
00588 modelMainWindow,
00589 xThetaString,
00590 yRadiusString,
00591 transformation);
00592 str << wrapInDoubleQuotesIfNeeded (modelExportOverride,
00593 xThetaString);
00594
00595 for (int col = 0; col < yRadiusValues.count(); col++) {
00596
00597 QString yRadiusString = *(yRadiusValues [col] [row]);
00598 str << delimiter << wrapInDoubleQuotesIfNeeded (modelExportOverride,
00599 yRadiusString);
00600 }
00601
00602 str << "\n";
00603 }
00604 }
00605
00606 ++numWritesSoFar;
00607 }
00608
00609 bool ExportFileFunctions::rowHasAtLeastOneYRadiusEntry (const QVector<QVector<QString*> > &yRadiusValues,
00610 int row) const
00611 {
00612 bool hasEntry = false;
00613
00614 for (int col = 0; col < yRadiusValues.count(); col++) {
00615
00616 QString entry = *(yRadiusValues [col] [row]);
00617 if (!entry.isEmpty()) {
00618
00619 hasEntry = true;
00620 break;
00621
00622 }
00623 }
00624
00625 return hasEntry;
00626 }