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)  

XYFourierTransformCurve.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  File : XYFourierTransformCurve.cpp
3  Project : LabPlot
4  Description : A xy-curve defined by a Fourier transform
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 XYFourierTransformCurve
32  \brief A xy-curve defined by a Fourier transform
33 
34  \ingroup worksheet
35 */
36 
42 #include "backend/lib/macros.h"
43 #include "backend/gsl/errors.h"
44 
45 extern "C" {
47 }
48 
49 #include <KLocalizedString>
50 #include <QElapsedTimer>
51 #include <QIcon>
52 #include <QThreadPool>
53 #include <QDebug> // qWarning()
54 
57 }
58 
61 }
62 
63 //no need to delete the d-pointer here - it inherits from QGraphicsItem
64 //and is deleted during the cleanup in QGraphicsScene
66 
69  d->recalculate();
70 }
71 
72 /*!
73  Returns an icon to be used in the project explorer.
74 */
76  return QIcon::fromTheme("labplot-xy-fourier-transform-curve");
77 }
78 
79 //##############################################################################
80 //########################## getter methods ##################################
81 //##############################################################################
83 
85  Q_D(const XYFourierTransformCurve);
86  return d->transformResult;
87 }
88 
89 //##############################################################################
90 //################# setter methods and undo commands ##########################
91 //##############################################################################
93 void XYFourierTransformCurve::setTransformData(const XYFourierTransformCurve::TransformData& transformData) {
95  exec(new XYFourierTransformCurveSetTransformDataCmd(d, transformData, ki18n("%1: set transform options and perform the Fourier transform")));
96 }
97 
98 //##############################################################################
99 //######################### Private implementation #############################
100 //##############################################################################
102 }
103 
104 //no need to delete xColumn and yColumn, they are deleted
105 //when the parent aspect is removed
107 
109  QElapsedTimer timer;
110  timer.start();
111 
112  //create transform result columns if not available yet, clear them otherwise
113  if (!xColumn) {
116  xVector = static_cast<QVector<double>* >(xColumn->data());
117  yVector = static_cast<QVector<double>* >(yColumn->data());
118 
119  xColumn->setHidden(true);
120  q->addChild(xColumn);
121  yColumn->setHidden(true);
122  q->addChild(yColumn);
123 
124  q->setUndoAware(false);
125  q->setXColumn(xColumn);
126  q->setYColumn(yColumn);
127  q->setUndoAware(true);
128  } else {
129  xVector->clear();
130  yVector->clear();
131  }
132 
133  // clear the previous result
135 
136  if (!xDataColumn || !yDataColumn) {
138  emit q->dataChanged();
140  return;
141  }
142 
143  //copy all valid data point for the transform to temporary vectors
144  QVector<double> xdataVector;
145  QVector<double> ydataVector;
146  const double xmin = transformData.xRange.first();
147  const double xmax = transformData.xRange.last();
148 
149  int rowCount = qMin(xDataColumn->rowCount(), yDataColumn->rowCount());
150  for (int row = 0; row < rowCount; ++row) {
151  // only copy those data where _all_ values (for x and y, if given) are valid
152  if (std::isnan(xDataColumn->valueAt(row)) || std::isnan(yDataColumn->valueAt(row))
153  || xDataColumn->isMasked(row) || yDataColumn->isMasked(row))
154  continue;
155 
156  // only when inside given range
157  if (xDataColumn->valueAt(row) >= xmin && xDataColumn->valueAt(row) <= xmax) {
158  xdataVector.append(xDataColumn->valueAt(row));
159  ydataVector.append(yDataColumn->valueAt(row));
160  }
161  }
162 
163  //number of data points to transform
164  unsigned int n = (unsigned int)ydataVector.size();
165  if (n == 0) {
166  transformResult.available = true;
167  transformResult.valid = false;
168  transformResult.status = i18n("No data points available.");
170  emit q->dataChanged();
172  return;
173  }
174 
175  double* xdata = xdataVector.data();
176  double* ydata = ydataVector.data();
177 
178  // transform settings
179  const nsl_sf_window_type windowType = transformData.windowType;
181  const bool twoSided = transformData.twoSided;
182  const bool shifted = transformData.shifted;
183  const nsl_dft_xscale xScale = transformData.xScale;
184 
185  DEBUG("n =" << n);
186  DEBUG("window type:" << nsl_sf_window_type_name[windowType]);
187  DEBUG("type:" << nsl_dft_result_type_name[type]);
188  DEBUG("scale:" << nsl_dft_xscale_name[xScale]);
189  DEBUG("two sided:" << twoSided);
190  DEBUG("shifted:" << shifted);
191 #ifndef NDEBUG
192  QDebug out = qDebug();
193  for (unsigned int i = 0; i < n; i++)
194  out<<ydata[i];
195 #endif
196 
197 ///////////////////////////////////////////////////////////
198  // transform with window
199  int status = nsl_dft_transform_window(ydata, 1, n, twoSided, type, windowType);
200 
201  unsigned int N = n;
202  if (twoSided == false)
203  N = n/2;
204 
205  switch (xScale) {
207  for (unsigned int i = 0; i < N; i++) {
208  if (i >= n/2 && shifted)
209  xdata[i] = (n-1)/(xmax-xmin)*(i/(double)n-1.);
210  else
211  xdata[i] = (n-1)*i/(xmax-xmin)/n;
212  }
213  break;
215  for (unsigned int i = 0; i < N; i++) {
216  if (i >= n/2 && shifted)
217  xdata[i] = (int)i-(int) N;
218  else
219  xdata[i] = i;
220  }
221  break;
222  case nsl_dft_xscale_period: {
223  double f0 = (n-1)/(xmax-xmin)/n;
224  for (unsigned int i = 0; i < N; i++) {
225  double f = (n-1)*i/(xmax-xmin)/n;
226  xdata[i] = 1/(f+f0);
227  }
228  break;
229  }
230  }
231 #ifndef NDEBUG
232  out = qDebug();
233  for (unsigned int i = 0; i < N; i++)
234  out << ydata[i] << '(' << xdata[i] << ')';
235 #endif
236 
237  xVector->resize((int)N);
238  yVector->resize((int)N);
239  if (shifted) {
240  memcpy(xVector->data(), &xdata[n/2], n/2*sizeof(double));
241  memcpy(&xVector->data()[n/2], xdata, n/2*sizeof(double));
242  memcpy(yVector->data(), &ydata[n/2], n/2*sizeof(double));
243  memcpy(&yVector->data()[n/2], ydata, n/2*sizeof(double));
244  } else {
245  memcpy(xVector->data(), xdata, N*sizeof(double));
246  memcpy(yVector->data(), ydata, N*sizeof(double));
247  }
248 ///////////////////////////////////////////////////////////
249 
250  //write the result
251  transformResult.available = true;
252  transformResult.valid = true;
253  transformResult.status = gslErrorToString(status);
254  transformResult.elapsedTime = timer.elapsed();
255 
256  //redraw the curve
258  emit q->dataChanged();
260 }
261 
262 //##############################################################################
263 //################## Serialization/Deserialization ###########################
264 //##############################################################################
265 //! Save as XML
266 void XYFourierTransformCurve::save(QXmlStreamWriter* writer) const {
267  Q_D(const XYFourierTransformCurve);
268 
269  writer->writeStartElement("xyFourierTransformCurve");
270 
271  //write the base class
272  XYAnalysisCurve::save(writer);
273 
274  //write xy-fourier_transform-curve specific information
275  //transform data
276  writer->writeStartElement("transformData");
277  writer->writeAttribute( "autoRange", QString::number(d->transformData.autoRange) );
278  writer->writeAttribute( "xRangeMin", QString::number(d->transformData.xRange.first()) );
279  writer->writeAttribute( "xRangeMax", QString::number(d->transformData.xRange.last()) );
280  writer->writeAttribute( "type", QString::number(d->transformData.type) );
281  writer->writeAttribute( "twoSided", QString::number(d->transformData.twoSided) );
282  writer->writeAttribute( "shifted", QString::number(d->transformData.shifted) );
283  writer->writeAttribute( "xScale", QString::number(d->transformData.xScale) );
284  writer->writeAttribute( "windowType", QString::number(d->transformData.windowType) );
285  writer->writeEndElement();// transformData
286 
287  //transform results (generated columns)
288  writer->writeStartElement("transformResult");
289  writer->writeAttribute( "available", QString::number(d->transformResult.available) );
290  writer->writeAttribute( "valid", QString::number(d->transformResult.valid) );
291  writer->writeAttribute( "status", d->transformResult.status );
292  writer->writeAttribute( "time", QString::number(d->transformResult.elapsedTime) );
293 
294  //save calculated columns if available
295  if (d->xColumn && d->yColumn) {
296  d->xColumn->save(writer);
297  d->yColumn->save(writer);
298  }
299  writer->writeEndElement(); //"transformResult"
300  writer->writeEndElement(); //"xyFourierTransformCurve"
301 }
302 
303 //! Load from XML
304 bool XYFourierTransformCurve::load(XmlStreamReader* reader, bool preview) {
306 
307  KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used");
308  QXmlStreamAttributes attribs;
309  QString str;
310 
311  while (!reader->atEnd()) {
312  reader->readNext();
313  if (reader->isEndElement() && reader->name() == "xyFourierTransformCurve")
314  break;
315 
316  if (!reader->isStartElement())
317  continue;
318 
319  if (reader->name() == "xyAnalysisCurve") {
320  if ( !XYAnalysisCurve::load(reader, preview) )
321  return false;
322  } else if (!preview && reader->name() == "transformData") {
323  attribs = reader->attributes();
324  READ_INT_VALUE("autoRange", transformData.autoRange, bool);
325  READ_DOUBLE_VALUE("xRangeMin", transformData.xRange.first());
326  READ_DOUBLE_VALUE("xRangeMax", transformData.xRange.last());
327  READ_INT_VALUE("type", transformData.type, nsl_dft_result_type);
328  READ_INT_VALUE("twoSided", transformData.twoSided, bool);
329  READ_INT_VALUE("shifted", transformData.shifted, bool);
330  READ_INT_VALUE("xScale", transformData.xScale, nsl_dft_xscale);
331  READ_INT_VALUE("windowType", transformData.windowType, nsl_sf_window_type);
332  } else if (!preview && reader->name() == "transformResult") {
333  attribs = reader->attributes();
334  READ_INT_VALUE("available", transformResult.available, int);
335  READ_INT_VALUE("valid", transformResult.valid, int);
338  } else if (reader->name() == "column") {
339  Column* column = new Column(QString(), AbstractColumn::ColumnMode::Numeric);
340  if (!column->load(reader, preview)) {
341  delete column;
342  return false;
343  }
344 
345  if (column->name() == "x")
346  d->xColumn = column;
347  else if (column->name() == "y")
348  d->yColumn = column;
349  }
350  }
351 
352  if (preview)
353  return true;
354 
355  // wait for data to be read before using the pointers
356  QThreadPool::globalInstance()->waitForDone();
357 
358  if (d->xColumn && d->yColumn) {
359  d->xColumn->setHidden(true);
360  addChild(d->xColumn);
361 
362  d->yColumn->setHidden(true);
363  addChild(d->yColumn);
364 
365  d->xVector = static_cast<QVector<double>* >(d->xColumn->data());
366  d->yVector = static_cast<QVector<double>* >(d->yColumn->data());
367 
368  XYCurve::d_ptr->xColumn = d->xColumn;
369  XYCurve::d_ptr->yColumn = d->yColumn;
370 
372  }
373 
374  return true;
375 }
AspectType
STD_SETTER_CMD_IMPL_F_S(XYFourierTransformCurve, SetTransformData, XYFourierTransformCurve::TransformData, transformData, 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.
virtual double valueAt(int row) const
Return the double value in row 'row'.
bool isMasked(int row) const
Return whether a certain row is masked.
virtual int rowCount() const =0
Return the data vector size.
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
const AbstractColumn * yDataColumn
QVector< double > * xVector
const AbstractColumn * xDataColumn
QVector< double > * yVector
Base class for all analysis curves.
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
XYFourierTransformCurvePrivate(XYFourierTransformCurve *)
XYFourierTransformCurve::TransformResult transformResult
XYFourierTransformCurve::TransformData transformData
~XYFourierTransformCurvePrivate() override
A xy-curve defined by a Fourier transform.
~XYFourierTransformCurve() override
XYFourierTransformCurve(const QString &name)
bool load(XmlStreamReader *, bool preview) override
Load from XML.
void save(QXmlStreamWriter *) const override
Save as XML.
const TransformResult & transformResult() const
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
const char * nsl_dft_xscale_name[]
Definition: nsl_dft.c:39
int nsl_dft_transform_window(double data[], size_t stride, size_t n, int two_sided, nsl_dft_result_type type, nsl_sf_window_type window_type)
Definition: nsl_dft.c:41
const char * nsl_dft_result_type_name[]
Definition: nsl_dft.c:37
nsl_dft_result_type
Definition: nsl_dft.h:50
nsl_dft_xscale
Definition: nsl_dft.h:56
@ nsl_dft_xscale_index
Definition: nsl_dft.h:56
@ nsl_dft_xscale_frequency
Definition: nsl_dft.h:56
@ nsl_dft_xscale_period
Definition: nsl_dft.h:56
const char * nsl_sf_window_type_name[]
Definition: nsl_sf_window.c:34
nsl_sf_window_type
Definition: nsl_sf_window.h:35