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