labplot  2.8.2
About: LabPlot is an application for plotting and analysis of 2D and 3D functions and data. It is a complete rewrite of LabPlot1 and lacks in the first release a lot of features available in the predecessor. On the other hand, the GUI and the usability is more superior.
  Fossies Dox: labplot-2.8.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

XYDataReductionCurve.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  File : XYDataReductionCurve.cpp
3  Project : LabPlot
4  Description : A xy-curve defined by a data reduction
5  --------------------------------------------------------------------
6  Copyright : (C) 2016 Stefan Gerlach (stefan.gerlach@uni.kn)
7  Copyright : (C) 2017 Alexander Semke (alexander.semke@web.de)
8 
9  ***************************************************************************/
10 
11 /***************************************************************************
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * *
18  * This program is distributed in the hope that it will be useful, *
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
21  * GNU General Public License for more details. *
22  * *
23  * You should have received a copy of the GNU General Public License *
24  * along with this program; if not, write to the Free Software *
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
26  * Boston, MA 02110-1301 USA *
27  * *
28  ***************************************************************************/
29 
30 /*!
31  \class XYDataReductionCurve
32  \brief A xy-curve defined by a data reduction
33 
34  \ingroup worksheet
35 */
36 
37 #include "XYDataReductionCurve.h"
42 #include "backend/lib/macros.h"
43 
44 #include <KLocalizedString>
45 #include <QIcon>
46 #include <QElapsedTimer>
47 #include <QThreadPool>
48 
51 }
52 
55 }
56 
57 //no need to delete the d-pointer here - it inherits from QGraphicsItem
58 //and is deleted during the cleanup in QGraphicsScene
60 
63  d->recalculate();
64 }
65 
66 /*!
67  Returns an icon to be used in the project explorer.
68 */
70  return QIcon::fromTheme("labplot-xy-data-reduction-curve");
71 }
72 
73 //##############################################################################
74 //########################## getter methods ##################################
75 //##############################################################################
77 
78 const XYDataReductionCurve::DataReductionResult& XYDataReductionCurve::dataReductionResult() const {
79  Q_D(const XYDataReductionCurve);
80  return d->dataReductionResult;
81 }
82 
83 //##############################################################################
84 //################# setter methods and undo commands ##########################
85 //##############################################################################
86 STD_SETTER_CMD_IMPL_F_S(XYDataReductionCurve, SetDataReductionData, XYDataReductionCurve::DataReductionData, dataReductionData, recalculate);
87 void XYDataReductionCurve::setDataReductionData(const XYDataReductionCurve::DataReductionData& reductionData) {
89  exec(new XYDataReductionCurveSetDataReductionDataCmd(d, reductionData, ki18n("%1: set options and perform the data reduction")));
90 }
91 
92 //##############################################################################
93 //######################### Private implementation #############################
94 //##############################################################################
96 }
97 
98 //no need to delete xColumn and yColumn, they are deleted
99 //when the parent aspect is removed
101 
103  QElapsedTimer timer;
104  timer.start();
105 
106  //create dataReduction result columns if not available yet, clear them otherwise
107  if (!xColumn) {
110  xVector = static_cast<QVector<double>* >(xColumn->data());
111  yVector = static_cast<QVector<double>* >(yColumn->data());
112 
113  xColumn->setHidden(true);
114  q->addChild(xColumn);
115  yColumn->setHidden(true);
116  q->addChild(yColumn);
117 
118  q->setUndoAware(false);
119  q->setXColumn(xColumn);
120  q->setYColumn(yColumn);
121  q->setUndoAware(true);
122  } else {
123  xVector->clear();
124  yVector->clear();
125  }
126 
127  // clear the previous result
129 
130  //determine the data source columns
131  const AbstractColumn* tmpXDataColumn = nullptr;
132  const AbstractColumn* tmpYDataColumn = nullptr;
134  //spreadsheet columns as data source
135  tmpXDataColumn = xDataColumn;
136  tmpYDataColumn = yDataColumn;
137  } else {
138  //curve columns as data source
139  tmpXDataColumn = dataSourceCurve->xColumn();
140  tmpYDataColumn = dataSourceCurve->yColumn();
141  }
142 
143  if (!tmpXDataColumn || !tmpYDataColumn) {
145  emit q->dataChanged();
147  return;
148  }
149 
150  //copy all valid data point for the data reduction to temporary vectors
151  QVector<double> xdataVector;
152  QVector<double> ydataVector;
153 
154  double xmin;
155  double xmax;
157  xmin = tmpXDataColumn->minimum();
158  xmax = tmpXDataColumn->maximum();
159  } else {
160  xmin = dataReductionData.xRange.first();
161  xmax = dataReductionData.xRange.last();
162  }
163 
164  XYAnalysisCurve::copyData(xdataVector, ydataVector, tmpXDataColumn, tmpYDataColumn, xmin, xmax);
165 
166  //number of data points to use
167  const size_t n = (size_t)xdataVector.size();
168  if (n < 2) {
170  dataReductionResult.valid = false;
171  dataReductionResult.status = i18n("Not enough data points available.");
173  emit q->dataChanged();
175  return;
176  }
177 
178  double* xdata = xdataVector.data();
179  double* ydata = ydataVector.data();
180 
181  // dataReduction settings
183  const double tol = dataReductionData.tolerance;
184  const double tol2 = dataReductionData.tolerance2;
185 
186  DEBUG("n =" << n);
188  DEBUG("tolerance/step:" << tol);
189  DEBUG("tolerance2/repeat/maxtol/region:" << tol2);
190 
191 ///////////////////////////////////////////////////////////
192  emit q->completed(10);
193 
194  size_t npoints = 0;
195  double calcTolerance = 0; // calculated tolerance from Douglas-Peucker variant
196  size_t *index = (size_t *) malloc(n*sizeof(size_t));
197  switch (type) {
198  case nsl_geom_linesim_type_douglas_peucker_variant: // tol used as number of points
199  npoints = tol;
200  calcTolerance = nsl_geom_linesim_douglas_peucker_variant(xdata, ydata, n, npoints, index);
201  break;
203  npoints = nsl_geom_linesim_douglas_peucker(xdata, ydata, n, tol, index);
204  break;
205  case nsl_geom_linesim_type_nthpoint: // tol used as step
206  npoints = nsl_geom_linesim_nthpoint(n, (int)tol, index);
207  break;
209  npoints = nsl_geom_linesim_raddist(xdata, ydata, n, tol, index);
210  break;
211  case nsl_geom_linesim_type_perpdist: // tol2 used as repeat
212  npoints = nsl_geom_linesim_perpdist_repeat(xdata, ydata, n, tol, tol2, index);
213  break;
215  npoints = nsl_geom_linesim_interp(xdata, ydata, n, tol, index);
216  break;
218  npoints = nsl_geom_linesim_visvalingam_whyatt(xdata, ydata, n, tol, index);
219  break;
221  npoints = nsl_geom_linesim_reumann_witkam(xdata, ydata, n, tol, index);
222  break;
224  npoints = nsl_geom_linesim_opheim(xdata, ydata, n, tol, tol2, index);
225  break;
226  case nsl_geom_linesim_type_lang: // tol2 used as region
227  npoints = nsl_geom_linesim_opheim(xdata, ydata, n, tol, tol2, index);
228  break;
229  }
230 
231  DEBUG("npoints =" << npoints);
233  DEBUG("calculated tolerance =" << calcTolerance)
234  else
235  Q_UNUSED(calcTolerance);
236 
237  emit q->completed(80);
238 
239  xVector->resize((int)npoints);
240  yVector->resize((int)npoints);
241  for (int i = 0; i < (int)npoints; i++) {
242  (*xVector)[i] = xdata[index[i]];
243  (*yVector)[i] = ydata[index[i]];
244  }
245 
246  emit q->completed(90);
247 
248  const double posError = nsl_geom_linesim_positional_squared_error(xdata, ydata, n, index);
249  const double areaError = nsl_geom_linesim_area_error(xdata, ydata, n, index);
250 
251  free(index);
252 
253 ///////////////////////////////////////////////////////////
254 
255  //write the result
257  dataReductionResult.valid = true;
258  if (npoints > 0)
259  dataReductionResult.status = QString("OK");
260  else
261  dataReductionResult.status = QString("FAILURE");
262  dataReductionResult.elapsedTime = timer.elapsed();
263  dataReductionResult.npoints = npoints;
264  dataReductionResult.posError = posError;
265  dataReductionResult.areaError = areaError;
266 
267  //redraw the curve
269  emit q->dataChanged();
271 
272  emit q->completed(100);
273 }
274 
275 //##############################################################################
276 //################## Serialization/Deserialization ###########################
277 //##############################################################################
278 //! Save as XML
279 void XYDataReductionCurve::save(QXmlStreamWriter* writer) const{
280  Q_D(const XYDataReductionCurve);
281 
282  writer->writeStartElement("xyDataReductionCurve");
283 
284  //write the base class
285  XYAnalysisCurve::save(writer);
286 
287  //write xy-dataReduction-curve specific information
288  // dataReduction data
289  writer->writeStartElement("dataReductionData");
290  writer->writeAttribute( "autoRange", QString::number(d->dataReductionData.autoRange) );
291  writer->writeAttribute( "xRangeMin", QString::number(d->dataReductionData.xRange.first()) );
292  writer->writeAttribute( "xRangeMax", QString::number(d->dataReductionData.xRange.last()) );
293  writer->writeAttribute( "type", QString::number(d->dataReductionData.type) );
294  writer->writeAttribute( "autoTolerance", QString::number(d->dataReductionData.autoTolerance) );
295  writer->writeAttribute( "tolerance", QString::number(d->dataReductionData.tolerance) );
296  writer->writeAttribute( "autoTolerance2", QString::number(d->dataReductionData.autoTolerance2) );
297  writer->writeAttribute( "tolerance2", QString::number(d->dataReductionData.tolerance2) );
298  writer->writeEndElement();// dataReductionData
299 
300  // dataReduction results (generated columns)
301  writer->writeStartElement("dataReductionResult");
302  writer->writeAttribute( "available", QString::number(d->dataReductionResult.available) );
303  writer->writeAttribute( "valid", QString::number(d->dataReductionResult.valid) );
304  writer->writeAttribute( "status", d->dataReductionResult.status );
305  writer->writeAttribute( "time", QString::number(d->dataReductionResult.elapsedTime) );
306  writer->writeAttribute( "npoints", QString::number(d->dataReductionResult.npoints) );
307  writer->writeAttribute( "posError", QString::number(d->dataReductionResult.posError) );
308  writer->writeAttribute( "areaError", QString::number(d->dataReductionResult.areaError) );
309 
310  //save calculated columns if available
311  if (d->xColumn) {
312  d->xColumn->save(writer);
313  d->yColumn->save(writer);
314  }
315  writer->writeEndElement(); //"dataReductionResult"
316 
317  writer->writeEndElement(); //"xyDataReductionCurve"
318 }
319 
320 //! Load from XML
321 bool XYDataReductionCurve::load(XmlStreamReader* reader, bool preview) {
323 
324  KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used");
325  QXmlStreamAttributes attribs;
326  QString str;
327 
328  while (!reader->atEnd()) {
329  reader->readNext();
330  if (reader->isEndElement() && reader->name() == "xyDataReductionCurve")
331  break;
332 
333  if (!reader->isStartElement())
334  continue;
335 
336  if (reader->name() == "xyAnalysisCurve") {
337  if ( !XYAnalysisCurve::load(reader, preview) )
338  return false;
339  } else if (!preview && reader->name() == "dataReductionData") {
340  attribs = reader->attributes();
341  READ_INT_VALUE("autoRange", dataReductionData.autoRange, bool);
342  READ_DOUBLE_VALUE("xRangeMin", dataReductionData.xRange.first());
343  READ_DOUBLE_VALUE("xRangeMax", dataReductionData.xRange.last());
344  READ_INT_VALUE("type", dataReductionData.type, nsl_geom_linesim_type);
345  READ_INT_VALUE("autoTolerance", dataReductionData.autoTolerance, int);
346  READ_DOUBLE_VALUE("tolerance", dataReductionData.tolerance);
347  READ_INT_VALUE("autoTolerance2", dataReductionData.autoTolerance2, int);
348  READ_DOUBLE_VALUE("tolerance2", dataReductionData.tolerance2);
349  } else if (!preview && reader->name() == "dataReductionResult") {
350  attribs = reader->attributes();
351  READ_INT_VALUE("available", dataReductionResult.available, int);
355  READ_INT_VALUE("npoints", dataReductionResult.npoints, size_t);
358  } else if (reader->name() == "column") {
359  Column* column = new Column(QString(), AbstractColumn::ColumnMode::Numeric);
360  if (!column->load(reader, preview)) {
361  delete column;
362  return false;
363  }
364  if (column->name() == "x")
365  d->xColumn = column;
366  else if (column->name() == "y")
367  d->yColumn = column;
368  }
369  }
370 
371  if (preview)
372  return true;
373 
374  // wait for data to be read before using the pointers
375  QThreadPool::globalInstance()->waitForDone();
376 
377  if (d->xColumn && d->yColumn) {
378  d->xColumn->setHidden(true);
379  addChild(d->xColumn);
380 
381  d->yColumn->setHidden(true);
382  addChild(d->yColumn);
383 
384  d->xVector = static_cast<QVector<double>* >(d->xColumn->data());
385  d->yVector = static_cast<QVector<double>* >(d->yColumn->data());
386 
387  XYCurve::d_ptr->xColumn = d->xColumn;
388  XYCurve::d_ptr->yColumn = d->yColumn;
389 
391  }
392 
393  return true;
394 }
AspectType
STD_SETTER_CMD_IMPL_F_S(XYDataReductionCurve, SetDataReductionData, XYDataReductionCurve::DataReductionData, dataReductionData, recalculate)
void setUndoAware(bool)
void addChild(AbstractAspect *)
Add the given Aspect to my list of children.
QString name() const
void exec(QUndoCommand *)
Execute the given command, pushing it on the undoStack() if available.
AbstractAspectPrivate * d
void setHidden(bool)
Set "hidden" property, i.e. whether to exclude this aspect from being shown in the explorer.
Interface definition for data with column logic.
virtual double maximum(int count=0) const
virtual double minimum(int count=0) const
Aspect that manages a column.
Definition: Column.h:42
void * data() const
Definition: Column.cpp:852
bool load(XmlStreamReader *, bool preview) override
Load the column from XML.
Definition: Column.cpp:1152
XYAnalysisCurve::DataSourceType dataSourceType
const AbstractColumn * yDataColumn
QVector< double > * xVector
const AbstractColumn * xDataColumn
QVector< double > * yVector
Base class for all analysis curves.
static void copyData(QVector< double > &xData, QVector< double > &yData, const AbstractColumn *xDataColumn, const AbstractColumn *yDataColumn, double xMin, double xMax)
void save(QXmlStreamWriter *) const override
Save as XML.
bool load(XmlStreamReader *, bool preview) override
Load from XML.
bool sourceDataChangedSinceLastRecalc
const AbstractColumn * xColumn
void recalcLogicalPoints()
Definition: XYCurve.cpp:1090
const AbstractColumn * yColumn
void dataChanged()
XYCurvePrivate *const d_ptr
Definition: XYCurve.h:186
void recalcLogicalPoints()
Definition: XYCurve.cpp:765
XYDataReductionCurve::DataReductionResult dataReductionResult
XYDataReductionCurvePrivate(XYDataReductionCurve *)
XYDataReductionCurve::DataReductionData dataReductionData
~XYDataReductionCurvePrivate() override
A xy-curve defined by a data reduction.
~XYDataReductionCurve() override
const DataReductionResult & dataReductionResult() const
XYDataReductionCurve(const QString &name)
QIcon icon() const override
void save(QXmlStreamWriter *) const override
Save as XML.
void completed(int)
int ranging from 0 to 100 notifies about the status of the analysis process
bool load(XmlStreamReader *, bool preview) override
Load from XML.
XML stream parser that supports errors as well as warnings. This class also adds line and column numb...
#define READ_DOUBLE_VALUE(name, var)
Definition: macros.h:475
#define DEBUG(x)
Definition: macros.h:50
#define READ_INT_VALUE(name, var, type)
Definition: macros.h:468
#define BASIC_SHARED_D_READER_IMPL(classname, type, method, var)
Definition: macros.h:127
#define READ_STRING_VALUE(name, var)
Definition: macros.h:482
#define i18n(m)
Definition: nsl_common.h:38
double nsl_geom_linesim_positional_squared_error(const double xdata[], const double ydata[], const size_t n, const size_t index[])
size_t nsl_geom_linesim_raddist(const double xdata[], const double ydata[], const size_t n, const double tol, size_t index[])
size_t nsl_geom_linesim_interp(const double xdata[], const double ydata[], const size_t n, const double tol, size_t index[])
size_t nsl_geom_linesim_douglas_peucker(const double xdata[], const double ydata[], const size_t n, const double tol, size_t index[])
size_t nsl_geom_linesim_reumann_witkam(const double xdata[], const double ydata[], const size_t n, const double tol, size_t index[])
size_t nsl_geom_linesim_opheim(const double xdata[], const double ydata[], const size_t n, const double mintol, const double maxtol, size_t index[])
size_t nsl_geom_linesim_nthpoint(const size_t n, const int step, size_t index[])
double nsl_geom_linesim_douglas_peucker_variant(const double xdata[], const double ydata[], const size_t n, const size_t nout, size_t index[])
const char * nsl_geom_linesim_type_name[]
size_t nsl_geom_linesim_visvalingam_whyatt(const double xdata[], const double ydata[], const size_t n, const double tol, size_t index[])
double nsl_geom_linesim_area_error(const double xdata[], const double ydata[], const size_t n, const size_t index[])
size_t nsl_geom_linesim_perpdist_repeat(const double xdata[], const double ydata[], const size_t n, const double tol, const size_t repeat, size_t index[])
nsl_geom_linesim_type
@ nsl_geom_linesim_type_opheim
@ nsl_geom_linesim_type_douglas_peucker_variant
@ nsl_geom_linesim_type_perpdist
@ nsl_geom_linesim_type_lang
@ nsl_geom_linesim_type_interp
@ nsl_geom_linesim_type_visvalingam_whyatt
@ nsl_geom_linesim_type_raddist
@ nsl_geom_linesim_type_nthpoint
@ nsl_geom_linesim_type_douglas_peucker
@ nsl_geom_linesim_type_reumann_witkam