00001
00002
00003
00004
00005
00006
00007 #include "Curve.h"
00008 #include "CurvesGraphs.h"
00009 #include "CurveStyle.h"
00010 #include "DocumentSerialize.h"
00011 #include "EngaugeAssert.h"
00012 #include "Logger.h"
00013 #include "MigrateToVersion6.h"
00014 #include "Point.h"
00015 #include "PointComparator.h"
00016 #include <QDataStream>
00017 #include <QDebug>
00018 #include <QMultiMap>
00019 #include <QTextStream>
00020 #include <QXmlStreamReader>
00021 #include <QXmlStreamWriter>
00022 #include "Transformation.h"
00023 #include "Xml.h"
00024
00025 const QString AXIS_CURVE_NAME ("Axes");
00026 const QString DEFAULT_GRAPH_CURVE_NAME ("Curve1");
00027 const QString DUMMY_CURVE_NAME ("dummy");
00028 const QString SCALE_CURVE_NAME ("Scale");
00029 const QString TAB_DELIMITER ("\t");
00030
00031
00032
00033 typedef QMultiMap<double, QString> XOrThetaToPointIdentifier;
00034
00035 Curve::Curve(const QString &curveName,
00036 const ColorFilterSettings &colorFilterSettings,
00037 const CurveStyle &curveStyle) :
00038 m_curveName (curveName),
00039 m_colorFilterSettings (colorFilterSettings),
00040 m_curveStyle (curveStyle)
00041 {
00042 }
00043
00044 Curve::Curve (const Curve &curve) :
00045 m_curveName (curve.curveName ()),
00046 m_points (curve.points ()),
00047 m_colorFilterSettings (curve.colorFilterSettings ()),
00048 m_curveStyle (curve.curveStyle ())
00049 {
00050 }
00051
00052 Curve::Curve (QDataStream &str)
00053 {
00054 const int CONVERT_ENUM_TO_RADIUS = 6;
00055 MigrateToVersion6 migrate;
00056
00057 qint32 int32, xScreen, yScreen;
00058 double xGraph, yGraph;
00059
00060 str >> m_curveName;
00061
00062
00063 if (m_curveName == SCALE_CURVE_NAME) {
00064 m_curveName = AXIS_CURVE_NAME;
00065 }
00066
00067 str >> int32;
00068 m_curveStyle.setPointShape(migrate.pointShape (int32));
00069 str >> int32;
00070 m_curveStyle.setPointRadius(int32 + CONVERT_ENUM_TO_RADIUS);
00071 str >> int32;
00072 m_curveStyle.setPointLineWidth (int32);
00073 str >> int32;
00074 m_curveStyle.setPointColor(migrate.colorPalette (int32));
00075 str >> int32;
00076 str >> int32;
00077 m_curveStyle.setLineWidth(int32);
00078 str >> int32;
00079 if (m_curveName == AXIS_CURVE_NAME) {
00080 m_curveStyle.setLineColor(migrate.colorPalette (int32));
00081 } else {
00082 m_curveStyle.setLineColor(COLOR_PALETTE_TRANSPARENT);
00083 }
00084 str >> int32;
00085 m_curveStyle.setLineConnectAs(migrate.curveConnectAs (int32));
00086
00087 str >> int32;
00088 int count = int32;
00089 int ordinal = 0;
00090 for (int i = 0; i < count; i++) {
00091
00092 str >> xScreen;
00093 str >> yScreen;
00094 str >> xGraph;
00095 str >> yGraph;
00096 if (m_curveName == AXIS_CURVE_NAME) {
00097
00098
00099 Point point (m_curveName,
00100 QPointF (xScreen, yScreen),
00101 QPointF (xGraph, yGraph),
00102 ordinal++,
00103 false);
00104
00105 addPoint(point);
00106 } else {
00107
00108
00109 Point point (m_curveName,
00110 QPointF (xScreen, yScreen));
00111 point.setOrdinal (ordinal++);
00112
00113 addPoint(point);
00114 }
00115 }
00116 }
00117
00118 Curve::Curve (QXmlStreamReader &reader)
00119 {
00120 loadXml(reader);
00121 }
00122
00123 Curve &Curve::operator=(const Curve &curve)
00124 {
00125 m_curveName = curve.curveName ();
00126 m_points = curve.points ();
00127 m_colorFilterSettings = curve.colorFilterSettings ();
00128 m_curveStyle = curve.curveStyle ();
00129
00130 return *this;
00131 }
00132
00133 void Curve::addPoint (Point point)
00134 {
00135 m_points.push_back (point);
00136 }
00137
00138 ColorFilterSettings Curve::colorFilterSettings () const
00139 {
00140 return m_colorFilterSettings;
00141 }
00142
00143 QString Curve::curveName () const
00144 {
00145 return m_curveName;
00146 }
00147
00148 CurveStyle Curve::curveStyle() const
00149 {
00150 return m_curveStyle;
00151 }
00152
00153 void Curve::editPointAxis (const QPointF &posGraph,
00154 const QString &identifier)
00155 {
00156
00157 QList<Point>::iterator itr;
00158 for (itr = m_points.begin (); itr != m_points.end (); itr++) {
00159
00160 Point &point = *itr;
00161 if (point.identifier () == identifier) {
00162
00163 point.setPosGraph (posGraph);
00164 break;
00165
00166 }
00167 }
00168 }
00169
00170 void Curve::editPointGraph (bool isX,
00171 bool isY,
00172 double x,
00173 double y,
00174 const QStringList &identifiers,
00175 const Transformation &transformation)
00176 {
00177 LOG4CPP_INFO_S ((*mainCat)) << "Curve::editPointGraph"
00178 << " identifiers=" << identifiers.join(" ").toLatin1().data();
00179
00180 if (transformation.transformIsDefined()) {
00181
00182
00183 QList<Point>::iterator itr;
00184 for (itr = m_points.begin(); itr != m_points.end(); itr++) {
00185
00186 Point &point = *itr;
00187
00188 if (identifiers.contains (point.identifier ())) {
00189
00190
00191
00192
00193
00194
00195 QPointF posScreen = point.posScreen ();
00196 QPointF posGraph;
00197 transformation.transformScreenToRawGraph (posScreen,
00198 posGraph);
00199
00200
00201 if (isX) {
00202 posGraph.setX (x);
00203 }
00204
00205 if (isY) {
00206 posGraph.setY (y);
00207 }
00208
00209
00210 transformation.transformRawGraphToScreen(posGraph,
00211 posScreen);
00212
00213 point.setPosScreen (posScreen);
00214 }
00215 }
00216 }
00217 }
00218
00219 void Curve::exportToClipboard (const QHash<QString, bool> &selectedHash,
00220 const Transformation &transformation,
00221 QTextStream &strCsv,
00222 QTextStream &strHtml,
00223 CurvesGraphs &curvesGraphs) const
00224 {
00225 LOG4CPP_INFO_S ((*mainCat)) << "Curve::exportToClipboard"
00226 << " hashCount=" << selectedHash.count();
00227
00228
00229
00230 bool isFirst = true;
00231 QList<Point>::const_iterator itr;
00232 for (itr = m_points.begin (); itr != m_points.end (); itr++) {
00233
00234 const Point &point = *itr;
00235 if (selectedHash.contains (point.identifier ())) {
00236
00237 if (isFirst) {
00238
00239
00240 isFirst = false;
00241 strCsv << "X" << TAB_DELIMITER << m_curveName << "\n";
00242 strHtml << "<table>\n"
00243 << "<tr><th>X</th><th>" << m_curveName << "</th></tr>\n";
00244 }
00245
00246
00247 CurveStyle curveStyleDefault;
00248 curveStyleDefault.setLineStyle(LineStyle::defaultAxesCurve());
00249 curveStyleDefault.setPointStyle(PointStyle::defaultGraphCurve (curvesGraphs.numCurves ()));
00250
00251
00252 if (curvesGraphs.curveForCurveName (m_curveName) == 0) {
00253 Curve curve(m_curveName,
00254 ColorFilterSettings::defaultFilter (),
00255 curveStyleDefault);
00256 curvesGraphs.addGraphCurveAtEnd(curve);
00257 }
00258
00259
00260 QPointF pos = point.posScreen();
00261 if (transformation.transformIsDefined()) {
00262
00263
00264 QPointF posGraph;
00265 transformation.transformScreenToRawGraph(pos,
00266 posGraph);
00267 pos = posGraph;
00268 }
00269
00270
00271 strCsv << pos.x() << TAB_DELIMITER << pos.y() << "\n";
00272 strHtml << "<tr><td>" << pos.x() << "</td><td>" << pos.y() << "</td></tr>\n";
00273
00274
00275 curvesGraphs.curveForCurveName (m_curveName)->addPoint (point);
00276 }
00277 }
00278
00279 if (!isFirst) {
00280 strHtml << "</table>\n";
00281 }
00282 }
00283
00284 bool Curve::isXOnly(const QString &pointIdentifier) const
00285 {
00286
00287 Points::const_iterator itr;
00288 for (itr = m_points.begin (); itr != m_points.end (); itr++) {
00289 const Point &point = *itr;
00290 if (pointIdentifier == point.identifier ()) {
00291 return point.isXOnly();
00292 break;
00293 }
00294 }
00295
00296 ENGAUGE_ASSERT (false);
00297
00298 return false;
00299 }
00300
00301 void Curve::iterateThroughCurvePoints (const Functor2wRet<const QString &, const Point&, CallbackSearchReturn> &ftorWithCallback) const
00302 {
00303 QList<Point>::const_iterator itr;
00304 for (itr = m_points.begin (); itr != m_points.end (); itr++) {
00305
00306 const Point &point = *itr;
00307
00308 CallbackSearchReturn rtn = ftorWithCallback (m_curveName, point);
00309
00310 if (rtn == CALLBACK_SEARCH_RETURN_INTERRUPT) {
00311 break;
00312 }
00313 }
00314 }
00315
00316 void Curve::iterateThroughCurveSegments (const Functor2wRet<const Point&, const Point&, CallbackSearchReturn> &ftorWithCallback) const
00317 {
00318
00319
00320 QList<Point>::const_iterator itr;
00321 const Point *pointBefore = 0;
00322 for (itr = m_points.begin(); itr != m_points.end(); itr++) {
00323
00324 const Point &point = *itr;
00325
00326 if (pointBefore != 0) {
00327
00328 CallbackSearchReturn rtn = ftorWithCallback (*pointBefore,
00329 point);
00330
00331 if (rtn == CALLBACK_SEARCH_RETURN_INTERRUPT) {
00332 break;
00333 }
00334
00335 }
00336 pointBefore = &point;
00337 }
00338 }
00339
00340 void Curve::loadCurvePoints(QXmlStreamReader &reader)
00341 {
00342 LOG4CPP_INFO_S ((*mainCat)) << "Curve::loadCurvePoints";
00343
00344 bool success = true;
00345
00346 while ((reader.tokenType() != QXmlStreamReader::EndElement) ||
00347 (reader.name() != DOCUMENT_SERIALIZE_CURVE_POINTS)) {
00348
00349 QXmlStreamReader::TokenType tokenType = loadNextFromReader(reader);
00350
00351 if (reader.atEnd()) {
00352 success = false;
00353 break;
00354 }
00355
00356 if (tokenType == QXmlStreamReader::StartElement) {
00357
00358 if (reader.name () == DOCUMENT_SERIALIZE_POINT) {
00359
00360 Point point (reader);
00361 m_points.push_back (point);
00362 }
00363 }
00364 }
00365
00366 if (!success) {
00367 reader.raiseError(QObject::tr ("Cannot read curve data"));
00368 }
00369 }
00370
00371 void Curve::loadXml(QXmlStreamReader &reader)
00372 {
00373 LOG4CPP_INFO_S ((*mainCat)) << "Curve::loadXml";
00374
00375 bool success = true;
00376
00377 QXmlStreamAttributes attributes = reader.attributes();
00378
00379 if (attributes.hasAttribute (DOCUMENT_SERIALIZE_CURVE_NAME)) {
00380
00381 setCurveName (attributes.value (DOCUMENT_SERIALIZE_CURVE_NAME).toString());
00382
00383
00384 while ((reader.tokenType() != QXmlStreamReader::EndElement) ||
00385 (reader.name() != DOCUMENT_SERIALIZE_CURVE)){
00386
00387 QXmlStreamReader::TokenType tokenType = loadNextFromReader(reader);
00388
00389 if (reader.atEnd()) {
00390 success = false;
00391 break;
00392 }
00393
00394 if (tokenType == QXmlStreamReader::StartElement) {
00395
00396 if (reader.name() == DOCUMENT_SERIALIZE_COLOR_FILTER) {
00397 m_colorFilterSettings.loadXml(reader);
00398 } else if (reader.name() == DOCUMENT_SERIALIZE_CURVE_POINTS) {
00399 loadCurvePoints(reader);
00400 } else if (reader.name() == DOCUMENT_SERIALIZE_CURVE_STYLE) {
00401 m_curveStyle.loadXml(reader);
00402 } else {
00403 success = false;
00404 break;
00405 }
00406 }
00407
00408 if (reader.hasError()) {
00409
00410
00411 break;
00412 }
00413 }
00414 } else {
00415 success = false;
00416 }
00417
00418 if (!success) {
00419 reader.raiseError (QObject::tr ("Cannot read curve data"));
00420 }
00421 }
00422
00423 void Curve::movePoint (const QString &pointIdentifier,
00424 const QPointF &deltaScreen)
00425 {
00426 Point *point = pointForPointIdentifier (pointIdentifier);
00427
00428 QPointF posScreen = deltaScreen + point->posScreen ();
00429 point->setPosScreen (posScreen);
00430 }
00431
00432 int Curve::numPoints () const
00433 {
00434 return m_points.count ();
00435 }
00436
00437 Point *Curve::pointForPointIdentifier (const QString pointIdentifier)
00438 {
00439 Points::iterator itr;
00440 for (itr = m_points.begin (); itr != m_points.end (); itr++) {
00441 Point &point = *itr;
00442 if (pointIdentifier == point.identifier ()) {
00443 return &point;
00444 }
00445 }
00446
00447 ENGAUGE_ASSERT (false);
00448 return 0;
00449 }
00450
00451 const Points Curve::points () const
00452 {
00453 return m_points;
00454 }
00455
00456 QPointF Curve::positionGraph (const QString &pointIdentifier) const
00457 {
00458 QPointF posGraph;
00459
00460
00461 Points::const_iterator itr;
00462 for (itr = m_points.begin (); itr != m_points.end (); itr++) {
00463 const Point &point = *itr;
00464 if (pointIdentifier == point.identifier ()) {
00465 posGraph = point.posGraph ();
00466 break;
00467 }
00468 }
00469
00470 return posGraph;
00471 }
00472
00473 QPointF Curve::positionScreen (const QString &pointIdentifier) const
00474 {
00475 QPointF posScreen;
00476
00477
00478 Points::const_iterator itr;
00479 for (itr = m_points.begin (); itr != m_points.end (); itr++) {
00480 const Point &point = *itr;
00481 if (pointIdentifier == point.identifier ()) {
00482 posScreen = point.posScreen ();
00483 break;
00484 }
00485 }
00486
00487 return posScreen;
00488 }
00489
00490 void Curve::printStream (QString indentation,
00491 QTextStream &str) const
00492 {
00493 str << indentation << "Curve=" << m_curveName << "\n";
00494
00495 indentation += INDENTATION_DELTA;
00496
00497 Points::const_iterator itr;
00498 for (itr = m_points.begin (); itr != m_points.end (); itr++) {
00499 const Point &point = *itr;
00500 point.printStream (indentation,
00501 str);
00502 }
00503
00504 m_colorFilterSettings.printStream (indentation,
00505 str);
00506 m_curveStyle.printStream (indentation,
00507 str);
00508 }
00509
00510 void Curve::removePoint (const QString &identifier)
00511 {
00512
00513 Points::iterator itr;
00514 for (itr = m_points.begin (); itr != m_points.end (); itr++) {
00515 Point point = *itr;
00516 if (point.identifier () == identifier) {
00517 m_points.erase (itr);
00518 break;
00519 }
00520 }
00521 }
00522
00523 void Curve::saveXml(QXmlStreamWriter &writer) const
00524 {
00525 LOG4CPP_INFO_S ((*mainCat)) << "Curve::saveXml";
00526
00527 writer.writeStartElement(DOCUMENT_SERIALIZE_CURVE);
00528 writer.writeAttribute(DOCUMENT_SERIALIZE_CURVE_NAME, m_curveName);
00529 m_colorFilterSettings.saveXml (writer,
00530 m_curveName);
00531 m_curveStyle.saveXml (writer,
00532 m_curveName);
00533
00534
00535 writer.writeStartElement(DOCUMENT_SERIALIZE_CURVE_POINTS);
00536 Points::const_iterator itr;
00537 for (itr = m_points.begin (); itr != m_points.end (); itr++) {
00538 const Point &point = *itr;
00539 point.saveXml (writer);
00540 }
00541 writer.writeEndElement();
00542
00543 writer.writeEndElement();
00544 }
00545
00546 void Curve::setColorFilterSettings (const ColorFilterSettings &colorFilterSettings)
00547 {
00548 m_colorFilterSettings = colorFilterSettings;
00549 }
00550
00551 void Curve::setCurveName (const QString &curveName)
00552 {
00553 m_curveName = curveName;
00554
00555
00556 QList<Point>::iterator itr;
00557 for (itr = m_points.begin(); itr != m_points.end(); itr++) {
00558 Point &point = *itr;
00559 point.setCurveName (curveName);
00560 }
00561 }
00562
00563 void Curve::setCurveStyle (const CurveStyle &curveStyle)
00564 {
00565 m_curveStyle = curveStyle;
00566 }
00567
00568 void Curve::updatePointOrdinals (const Transformation &transformation)
00569 {
00570 CurveConnectAs curveConnectAs = m_curveStyle.lineStyle().curveConnectAs();
00571
00572 LOG4CPP_INFO_S ((*mainCat)) << "Curve::updatePointOrdinals"
00573 << " curve=" << m_curveName.toLatin1().data()
00574 << " connectAs=" << curveConnectAsToString(curveConnectAs).toLatin1().data();
00575
00576
00577
00578 if (curveConnectAs == CONNECT_AS_FUNCTION_SMOOTH ||
00579 curveConnectAs == CONNECT_AS_FUNCTION_STRAIGHT) {
00580
00581 updatePointOrdinalsFunctions (transformation);
00582
00583 } else if (curveConnectAs == CONNECT_AS_RELATION_SMOOTH ||
00584 curveConnectAs == CONNECT_AS_RELATION_STRAIGHT) {
00585
00586 updatePointOrdinalsRelations ();
00587
00588 } else {
00589
00590 LOG4CPP_ERROR_S ((*mainCat)) << "Curve::updatePointOrdinals";
00591 ENGAUGE_ASSERT (false);
00592
00593 }
00594
00595 qSort (m_points.begin(),
00596 m_points.end(),
00597 PointComparator());
00598 }
00599
00600 void Curve::updatePointOrdinalsFunctions (const Transformation &transformation)
00601 {
00602 CurveConnectAs curveConnectAs = m_curveStyle.lineStyle().curveConnectAs();
00603
00604 LOG4CPP_INFO_S ((*mainCat)) << "Curve::updatePointOrdinalsFunctions"
00605 << " curve=" << m_curveName.toLatin1().data()
00606 << " connectAs=" << curveConnectAsToString(curveConnectAs).toLatin1().data();
00607
00608
00609
00610
00611 XOrThetaToPointIdentifier xOrThetaToPointIdentifier;
00612 Points::iterator itr;
00613 for (itr = m_points.begin (); itr != m_points.end (); itr++) {
00614 Point &point = *itr;
00615
00616 QPointF posGraph;
00617 if (transformation.transformIsDefined()) {
00618
00619
00620 transformation.transformScreenToRawGraph (point.posScreen (),
00621 posGraph);
00622 } else {
00623
00624
00625
00626 posGraph= point.posScreen();
00627 }
00628
00629 xOrThetaToPointIdentifier.insert (posGraph.x(),
00630 point.identifier());
00631 }
00632
00633
00634
00635 ENGAUGE_ASSERT (xOrThetaToPointIdentifier.count () == m_points.count ());
00636
00637
00638
00639 QMap<QString, double> pointIdentifierToOrdinal;
00640 int ordinal = 0;
00641 XOrThetaToPointIdentifier::const_iterator itrX;
00642 for (itrX = xOrThetaToPointIdentifier.begin(); itrX != xOrThetaToPointIdentifier.end(); itrX++) {
00643
00644 QString pointIdentifier = itrX.value();
00645 pointIdentifierToOrdinal [pointIdentifier] = ordinal++;
00646 }
00647
00648
00649 for (itr = m_points.begin(); itr != m_points.end(); itr++) {
00650 Point &point = *itr;
00651
00652
00653
00654
00655 ENGAUGE_ASSERT (pointIdentifierToOrdinal.contains (point.identifier()));
00656
00657
00658 int ordinalNew = pointIdentifierToOrdinal [point.identifier()];
00659 point.setOrdinal (ordinalNew);
00660 }
00661 }
00662
00663 void Curve::updatePointOrdinalsRelations ()
00664 {
00665 CurveConnectAs curveConnectAs = m_curveStyle.lineStyle().curveConnectAs();
00666
00667 LOG4CPP_INFO_S ((*mainCat)) << "Curve::updatePointOrdinalsRelations"
00668 << " curve=" << m_curveName.toLatin1().data()
00669 << " connectAs=" << curveConnectAsToString(curveConnectAs).toLatin1().data();
00670
00671
00672 Points::iterator itr;
00673 int ordinal = 0;
00674 for (itr = m_points.begin(); itr != m_points.end(); itr++) {
00675 Point &point = *itr;
00676 point.setOrdinal (ordinal++);
00677 }
00678 }