1 /***************************************************************************
2 File : MultiPeakFitTool.cpp
3 Project : QtiPlot
4 --------------------------------------------------------------------
5 Copyright : (C) 2006,2007 by Ion Vasilief, Knut Franke
6 Email (use @ for *) : ion_vasilief*yahoo.fr, knut.franke*gmx.de
7 Description : Plot tool for doing multi-peak fitting.
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 #include "MultiPeakFitTool.h"
30 #include "RangeSelectorTool.h"
31 #include <ApplicationWindow.h>
32 #include "DataPickerTool.h"
33
34 #include <qwt_plot_curve.h>
35 #include <qwt_plot_marker.h>
36 #include <QApplication>
37
38 #include <gsl/gsl_statistics.h>
39
MultiPeakFitTool(Graph * graph,ApplicationWindow * app,MultiPeakFit::PeakProfile profile,int num_peaks,const QObject * status_target,const char * status_slot)40 MultiPeakFitTool::MultiPeakFitTool(Graph *graph, ApplicationWindow *app, MultiPeakFit::PeakProfile profile, int num_peaks, const QObject *status_target, const char *status_slot)
41 : PlotToolInterface(graph)
42 {
43 d_selected_peaks = 0;
44 d_curve = 0;
45
46 d_fit = new MultiPeakFit(app, graph, profile, num_peaks);
47 d_fit->enablePeakCurves(app->generatePeakCurves);
48 d_fit->setPeakCurvesColor(app->peakCurvesColor);
49 d_fit->generateFunction(app->generateUniformFitPoints, app->fitPoints);
50
51 if (status_target)
52 connect(this, SIGNAL(statusText(const QString&)), status_target, status_slot);
53 d_picker_tool = new DataPickerTool(d_graph, app, DataPickerTool::Display, this, SIGNAL(statusText(const QString&)));
54 d_graph->canvas()->setCursor(QCursor(QPixmap(":/cursor.png"), -1, -1));
55
56 QString msg = tr("Move cursor and click to select a point and double-click/press 'Enter' to set the position of a peak!");
57 if (app->d_multi_peak_messages)
58 QMessageBox::information(app, app->objectName(), msg);
59 emit statusText(msg);
60
61 connect(d_picker_tool, SIGNAL(selected(QwtPlotCurve*,int)), this, SLOT(selectPeak(QwtPlotCurve*,int)));
62 d_graph->canvas()->grabMouse();
63 }
64
~MultiPeakFitTool()65 MultiPeakFitTool::~MultiPeakFitTool()
66 {
67 d_graph->canvas()->releaseMouse();
68
69 foreach(QwtPlotMarker *m, d_lines)
70 m->detach();//remove peak line markers
71 d_lines.clear();
72
73 if (d_picker_tool)
74 delete d_picker_tool;
75 if (d_fit)
76 delete d_fit;
77 }
78
selectPeak(QwtPlotCurve * curve,int point_index)79 void MultiPeakFitTool::selectPeak(QwtPlotCurve *curve, int point_index)
80 {
81 if (!curve || (d_curve && d_curve != curve))
82 return;
83 d_curve = curve;
84
85 QwtPlotMarker *m = new QwtPlotMarker();
86 m->setXAxis(curve->xAxis());
87 m->setLinePen(QPen(Qt::green, 2, Qt::DashLine));
88
89 if (curve->curveType() == QwtPlotCurve::Xfy){
90 m->setLineStyle(QwtPlotMarker::HLine);
91 d_fit->setInitialGuess(3*d_selected_peaks, curve->x(point_index));
92 d_fit->setInitialGuess(3*d_selected_peaks+1, curve->y(point_index));
93 } else {
94 m->setLineStyle(QwtPlotMarker::VLine);
95 d_fit->setInitialGuess(3*d_selected_peaks, curve->y(point_index));
96 d_fit->setInitialGuess(3*d_selected_peaks+1, curve->x(point_index));
97 }
98
99 m->setValue(curve->x(point_index), curve->y(point_index));
100 d_graph->insertMarker(m);
101 d_lines.append(m);
102 d_graph->replot();
103
104 d_selected_peaks++;
105 if (d_selected_peaks == d_fit->peaks())
106 finalize();
107 else {
108 QString msg = tr("Peak %1 selected! Click to select a point and double-click/press 'Enter' to set the position of the next peak!").arg(QString::number(d_selected_peaks));
109 ApplicationWindow *app = d_picker_tool->applicationWindow();
110 if (app && app->d_multi_peak_messages){
111 d_graph->canvas()->releaseMouse();
112 QMessageBox::information(app, app->objectName(), msg);
113 d_graph->canvas()->grabMouse();
114 }
115 emit statusText(msg);
116 }
117 }
118
finalize()119 void MultiPeakFitTool::finalize()
120 {
121 delete d_picker_tool; d_picker_tool = NULL;
122 d_graph->canvas()->releaseMouse();
123
124 if (d_fit->setDataFromCurve(d_curve->title().text())){
125 QApplication::setOverrideCursor(Qt::WaitCursor);
126
127 double *y = d_fit->y();
128 int n = d_fit->dataSize();
129
130 size_t imin, imax;
131 gsl_stats_minmax_index(&imin, &imax, y, 1, n);
132 #ifdef Q_CC_MSVC
133 QVarLengthArray<double> temp(n);
134 #else
135 double temp[n];
136 #endif
137 for (int i = 0; i < n; i++)
138 temp[i] = fabs(y[i]);
139 #ifdef Q_CC_MSVC
140 size_t imax_temp = gsl_stats_max_index(temp.data(), 1, n);
141 #else
142 size_t imax_temp = gsl_stats_max_index(temp, 1, n);
143 #endif
144 double offset = 0.0;
145 if (imax_temp == imax)
146 offset = y[imin];
147 else
148 offset = y[imax];
149 d_fit->setInitialGuess(3*d_selected_peaks, offset);
150
151 double w = 2*gsl_stats_sd(d_fit->x(), 1, n)/(double)d_selected_peaks;
152 for (int i = 0; i < d_selected_peaks; i++){
153 int aux = 3*i;
154 d_fit->setInitialGuess(aux + 2, w);
155 double yc = d_fit->initialGuess(aux);
156 if (d_fit->profile() == MultiPeakFit::Lorentz)
157 d_fit->setInitialGuess(aux, (yc - offset)*M_PI_2*w);
158 else
159 d_fit->setInitialGuess(aux, (yc - offset)*sqrt(M_PI_2)*w);
160 }
161
162 d_fit->fit();
163 delete d_fit; d_fit = NULL;
164 QApplication::restoreOverrideCursor();
165 }
166
167 //remove peak line markers
168 foreach(QwtPlotMarker *m, d_lines)
169 m->detach();
170 d_lines.clear();
171
172 d_graph->replot();
173 if (d_graph->activeTool() && d_graph->activeTool()->rtti() == PlotToolInterface::Rtti_RangeSelector){
174 ((RangeSelectorTool *)d_graph->activeTool())->setEnabled();
175 } else
176 d_graph->canvas()->unsetCursor();
177
178 d_graph->setActiveTool(NULL);
179 }
180