File indexing completed on 2025-01-26 03:34:18
0001 /* 0002 File : XYDifferentiationCurve.cpp 0003 Project : LabPlot 0004 Description : A xy-curve defined by an differentiation 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2016-2022 Stefan Gerlach <stefan.gerlach@uni.kn> 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 /*! 0011 \class XYDifferentiationCurve 0012 \brief A xy-curve defined by an differentiation 0013 0014 \ingroup worksheet 0015 */ 0016 0017 #include "XYDifferentiationCurve.h" 0018 #include "CartesianCoordinateSystem.h" 0019 #include "XYDifferentiationCurvePrivate.h" 0020 #include "backend/core/column/Column.h" 0021 #include "backend/lib/XmlStreamReader.h" 0022 #include "backend/lib/commandtemplates.h" 0023 #include "backend/lib/macros.h" 0024 0025 #include <KLocalizedString> 0026 #include <QElapsedTimer> 0027 #include <QIcon> 0028 #include <QThreadPool> 0029 0030 XYDifferentiationCurve::XYDifferentiationCurve(const QString& name) 0031 : XYAnalysisCurve(name, new XYDifferentiationCurvePrivate(this), AspectType::XYDifferentiationCurve) { 0032 } 0033 0034 XYDifferentiationCurve::XYDifferentiationCurve(const QString& name, XYDifferentiationCurvePrivate* dd) 0035 : XYAnalysisCurve(name, dd, AspectType::XYDifferentiationCurve) { 0036 } 0037 0038 // no need to delete the d-pointer here - it inherits from QGraphicsItem 0039 // and is deleted during the cleanup in QGraphicsScene 0040 XYDifferentiationCurve::~XYDifferentiationCurve() = default; 0041 0042 void XYDifferentiationCurve::recalculate() { 0043 Q_D(XYDifferentiationCurve); 0044 d->recalculate(); 0045 } 0046 0047 const XYAnalysisCurve::Result& XYDifferentiationCurve::result() const { 0048 return differentiationResult(); 0049 } 0050 0051 /*! 0052 Returns an icon to be used in the project explorer. 0053 */ 0054 QIcon XYDifferentiationCurve::icon() const { 0055 return QIcon::fromTheme(QStringLiteral("labplot-xy-curve")); 0056 } 0057 0058 // ############################################################################## 0059 // ########################## getter methods ################################## 0060 // ############################################################################## 0061 BASIC_SHARED_D_READER_IMPL(XYDifferentiationCurve, XYDifferentiationCurve::DifferentiationData, differentiationData, differentiationData) 0062 0063 const XYDifferentiationCurve::DifferentiationResult& XYDifferentiationCurve::differentiationResult() const { 0064 Q_D(const XYDifferentiationCurve); 0065 return d->differentiationResult; 0066 } 0067 0068 // ############################################################################## 0069 // ################# setter methods and undo commands ########################## 0070 // ############################################################################## 0071 STD_SETTER_CMD_IMPL_F_S(XYDifferentiationCurve, SetDifferentiationData, XYDifferentiationCurve::DifferentiationData, differentiationData, recalculate) 0072 void XYDifferentiationCurve::setDifferentiationData(const XYDifferentiationCurve::DifferentiationData& differentiationData) { 0073 Q_D(XYDifferentiationCurve); 0074 exec(new XYDifferentiationCurveSetDifferentiationDataCmd(d, differentiationData, ki18n("%1: set options and perform the differentiation"))); 0075 } 0076 0077 // ############################################################################## 0078 // ######################### Private implementation ############################# 0079 // ############################################################################## 0080 XYDifferentiationCurvePrivate::XYDifferentiationCurvePrivate(XYDifferentiationCurve* owner) 0081 : XYAnalysisCurvePrivate(owner) 0082 , q(owner) { 0083 } 0084 0085 // no need to delete xColumn and yColumn, they are deleted 0086 // when the parent aspect is removed 0087 XYDifferentiationCurvePrivate::~XYDifferentiationCurvePrivate() = default; 0088 0089 void XYDifferentiationCurvePrivate::resetResults() { 0090 differentiationResult = XYDifferentiationCurve::DifferentiationResult(); 0091 } 0092 0093 // ... 0094 // see XYFitCurvePrivate 0095 bool XYDifferentiationCurvePrivate::recalculateSpecific(const AbstractColumn* tmpXDataColumn, const AbstractColumn* tmpYDataColumn) { 0096 QElapsedTimer timer; 0097 timer.start(); 0098 0099 // copy all valid data point for the differentiation to temporary vectors 0100 QVector<double> xdataVector; 0101 QVector<double> ydataVector; 0102 0103 double xmin; 0104 double xmax; 0105 if (differentiationData.autoRange) { 0106 xmin = tmpXDataColumn->minimum(); 0107 xmax = tmpXDataColumn->maximum(); 0108 } else { 0109 xmin = differentiationData.xRange.first(); 0110 xmax = differentiationData.xRange.last(); 0111 } 0112 0113 XYAnalysisCurve::copyData(xdataVector, ydataVector, tmpXDataColumn, tmpYDataColumn, xmin, xmax, true); 0114 0115 // number of data points to differentiate 0116 const size_t n = (size_t)xdataVector.size(); 0117 if (n < 3) { 0118 differentiationResult.available = true; 0119 differentiationResult.valid = false; 0120 differentiationResult.status = i18n("Not enough data points available."); 0121 return true; 0122 } 0123 0124 double* xdata = xdataVector.data(); 0125 double* ydata = ydataVector.data(); 0126 0127 // differentiation settings 0128 const nsl_diff_deriv_order_type derivOrder = differentiationData.derivOrder; 0129 const int accOrder = differentiationData.accOrder; 0130 0131 DEBUG(nsl_diff_deriv_order_name[derivOrder] << " derivative"); 0132 DEBUG("accuracy order: " << accOrder); 0133 // WARN("DATA:") 0134 // for (int i = 0; i < n; i++) 0135 // WARN(xdata[i] << "," << ydata[i]) 0136 0137 /////////////////////////////////////////////////////////// 0138 int status = 0; 0139 0140 switch (derivOrder) { 0141 case nsl_diff_deriv_order_first: 0142 status = nsl_diff_first_deriv(xdata, ydata, n, accOrder); 0143 break; 0144 case nsl_diff_deriv_order_second: 0145 status = nsl_diff_second_deriv(xdata, ydata, n, accOrder); 0146 break; 0147 case nsl_diff_deriv_order_third: 0148 status = nsl_diff_third_deriv(xdata, ydata, n, accOrder); 0149 break; 0150 case nsl_diff_deriv_order_fourth: 0151 status = nsl_diff_fourth_deriv(xdata, ydata, n, accOrder); 0152 break; 0153 case nsl_diff_deriv_order_fifth: 0154 status = nsl_diff_fifth_deriv(xdata, ydata, n, accOrder); 0155 break; 0156 case nsl_diff_deriv_order_sixth: 0157 status = nsl_diff_sixth_deriv(xdata, ydata, n, accOrder); 0158 break; 0159 } 0160 0161 xVector->resize((int)n); 0162 yVector->resize((int)n); 0163 memcpy(xVector->data(), xdata, n * sizeof(double)); 0164 memcpy(yVector->data(), ydata, n * sizeof(double)); 0165 /////////////////////////////////////////////////////////// 0166 // WARN("RESULT:") 0167 // for (int i = 0; i < n; i++) 0168 // WARN(xdata[i] << "," << ydata[i]) 0169 0170 // write the result 0171 differentiationResult.available = true; 0172 differentiationResult.valid = (status == 0); 0173 differentiationResult.status = QString::number(status); 0174 differentiationResult.elapsedTime = timer.elapsed(); 0175 0176 return true; 0177 } 0178 0179 // ############################################################################## 0180 // ################## Serialization/Deserialization ########################### 0181 // ############################################################################## 0182 //! Save as XML 0183 void XYDifferentiationCurve::save(QXmlStreamWriter* writer) const { 0184 Q_D(const XYDifferentiationCurve); 0185 0186 writer->writeStartElement(QStringLiteral("xyDifferentiationCurve")); 0187 0188 // write the base class 0189 XYAnalysisCurve::save(writer); 0190 0191 // write xy-differentiation-curve specific information 0192 // differentiation data 0193 writer->writeStartElement(QStringLiteral("differentiationData")); 0194 writer->writeAttribute(QStringLiteral("derivOrder"), QString::number(d->differentiationData.derivOrder)); 0195 writer->writeAttribute(QStringLiteral("accOrder"), QString::number(d->differentiationData.accOrder)); 0196 writer->writeAttribute(QStringLiteral("autoRange"), QString::number(d->differentiationData.autoRange)); 0197 writer->writeAttribute(QStringLiteral("xRangeMin"), QString::number(d->differentiationData.xRange.first())); 0198 writer->writeAttribute(QStringLiteral("xRangeMax"), QString::number(d->differentiationData.xRange.last())); 0199 writer->writeEndElement(); // differentiationData 0200 0201 // differentiation results (generated columns) 0202 writer->writeStartElement(QStringLiteral("differentiationResult")); 0203 writer->writeAttribute(QStringLiteral("available"), QString::number(d->differentiationResult.available)); 0204 writer->writeAttribute(QStringLiteral("valid"), QString::number(d->differentiationResult.valid)); 0205 writer->writeAttribute(QStringLiteral("status"), d->differentiationResult.status); 0206 writer->writeAttribute(QStringLiteral("time"), QString::number(d->differentiationResult.elapsedTime)); 0207 0208 // save calculated columns if available 0209 if (saveCalculations() && d->xColumn) { 0210 d->xColumn->save(writer); 0211 d->yColumn->save(writer); 0212 } 0213 writer->writeEndElement(); //"differentiationResult" 0214 0215 writer->writeEndElement(); //"xyDifferentiationCurve" 0216 } 0217 0218 //! Load from XML 0219 bool XYDifferentiationCurve::load(XmlStreamReader* reader, bool preview) { 0220 Q_D(XYDifferentiationCurve); 0221 0222 QXmlStreamAttributes attribs; 0223 QString str; 0224 0225 while (!reader->atEnd()) { 0226 reader->readNext(); 0227 if (reader->isEndElement() && reader->name() == QLatin1String("xyDifferentiationCurve")) 0228 break; 0229 0230 if (!reader->isStartElement()) 0231 continue; 0232 0233 if (reader->name() == QLatin1String("xyAnalysisCurve")) { 0234 if (!XYAnalysisCurve::load(reader, preview)) 0235 return false; 0236 } else if (!preview && reader->name() == QLatin1String("differentiationData")) { 0237 attribs = reader->attributes(); 0238 READ_INT_VALUE("autoRange", differentiationData.autoRange, bool); 0239 READ_DOUBLE_VALUE("xRangeMin", differentiationData.xRange.first()); 0240 READ_DOUBLE_VALUE("xRangeMax", differentiationData.xRange.last()); 0241 READ_INT_VALUE("derivOrder", differentiationData.derivOrder, nsl_diff_deriv_order_type); 0242 READ_INT_VALUE("accOrder", differentiationData.accOrder, int); 0243 } else if (!preview && reader->name() == QLatin1String("differentiationResult")) { 0244 attribs = reader->attributes(); 0245 READ_INT_VALUE("available", differentiationResult.available, int); 0246 READ_INT_VALUE("valid", differentiationResult.valid, int); 0247 READ_STRING_VALUE("status", differentiationResult.status); 0248 READ_INT_VALUE("time", differentiationResult.elapsedTime, int); 0249 } else if (reader->name() == QLatin1String("column")) { 0250 Column* column = new Column(QString(), AbstractColumn::ColumnMode::Double); 0251 if (!column->load(reader, preview)) { 0252 delete column; 0253 return false; 0254 } 0255 if (column->name() == QLatin1String("x")) 0256 d->xColumn = column; 0257 else if (column->name() == QLatin1String("y")) 0258 d->yColumn = column; 0259 } else { // unknown element 0260 reader->raiseUnknownElementWarning(); 0261 if (!reader->skipToEndElement()) 0262 return false; 0263 } 0264 } 0265 0266 if (preview) 0267 return true; 0268 0269 // wait for data to be read before using the pointers 0270 QThreadPool::globalInstance()->waitForDone(); 0271 0272 if (d->xColumn && d->yColumn) { 0273 d->xColumn->setHidden(true); 0274 addChild(d->xColumn); 0275 0276 d->yColumn->setHidden(true); 0277 addChild(d->yColumn); 0278 0279 d->xVector = static_cast<QVector<double>*>(d->xColumn->data()); 0280 d->yVector = static_cast<QVector<double>*>(d->yColumn->data()); 0281 0282 static_cast<XYCurvePrivate*>(d_ptr)->xColumn = d->xColumn; 0283 static_cast<XYCurvePrivate*>(d_ptr)->yColumn = d->yColumn; 0284 0285 recalcLogicalPoints(); 0286 } 0287 0288 return true; 0289 }