00001
00002
00003
00004
00005
00006
00007 #include "CmdMediator.h"
00008 #include "Curve.h"
00009 #include "CurveConnectAs.h"
00010 #include "CurveStyle.h"
00011 #include "EngaugeAssert.h"
00012 #include "FittingCurveCoefficients.h"
00013 #include "FittingModel.h"
00014 #include "FittingStatistics.h"
00015 #include "FittingWindow.h"
00016 #include "GeometryModel.h"
00017 #include "Logger.h"
00018 #include "MainWindow.h"
00019 #include "MainWindowModel.h"
00020 #include <QApplication>
00021 #include <QClipboard>
00022 #include <QComboBox>
00023 #include <QGridLayout>
00024 #include <QItemSelectionModel>
00025 #include <QLabel>
00026 #include <QLineEdit>
00027 #include <qmath.h>
00028 #include "Transformation.h"
00029 #include "WindowTable.h"
00030
00031 const int COLUMN_COEFFICIENTS = 0;
00032 const int COLUMN_POLYNOMIAL_TERMS = 1;
00033
00034 FittingWindow::FittingWindow (MainWindow *mainWindow) :
00035 WindowAbstractBase (mainWindow),
00036 m_isLogXTheta (false),
00037 m_isLogYRadius (false)
00038 {
00039 setVisible (false);
00040 setAllowedAreas (Qt::AllDockWidgetAreas);
00041 setWindowTitle (tr ("Curve Fitting Window"));
00042 setStatusTip (tr ("Curve Fitting Window"));
00043 setWhatsThis (tr ("Curve Fitting Window\n\n"
00044 "This window applies a curve fit to the currently selected curve.\n\n"
00045 "If drag-and-drop is disabled, a rectangular set of cells may be selected by clicking and dragging. Otherwise, if "
00046 "drag-and-drop is enabled, a rectangular set of cells may be selected using Click then Shift+Click, since click and drag "
00047 "starts the dragging operation. Drag-and-drop mode is set in the Main Window settings"));
00048
00049 m_coefficients.resize (MAX_POLYNOMIAL_ORDER + 1);
00050
00051 createWidgets (mainWindow);
00052 initializeOrder ();
00053 clear ();
00054 }
00055
00056 FittingWindow::~FittingWindow()
00057 {
00058 }
00059
00060 void FittingWindow::calculateCurveFitAndStatistics ()
00061 {
00062 FittingStatistics fittingStatistics;
00063
00064 double mse = 0, rms = 0, rSquared = 0;
00065 fittingStatistics.calculateCurveFitAndStatistics (maxOrder (),
00066 m_pointsConvenient,
00067 m_coefficients,
00068 mse,
00069 rms,
00070 rSquared);
00071
00072 m_lblMeanSquareError->setText (QString::number (mse));
00073 m_lblRootMeanSquare->setText (QString::number (rms));
00074 m_lblRSquared->setText (QString::number (rSquared));
00075
00076
00077 if (m_pointsConvenient.size () > 0) {
00078 int last = m_pointsConvenient.size () - 1;
00079 emit signalCurveFit (m_coefficients,
00080 m_pointsConvenient [0].x(),
00081 m_pointsConvenient [last].x (),
00082 m_isLogXTheta,
00083 m_isLogYRadius);
00084 } else {
00085 emit signalCurveFit (m_coefficients,
00086 0,
00087 0,
00088 false,
00089 false);
00090 }
00091
00092
00093 for (int row = 0, order = m_model->rowCount () - 1; row < m_model->rowCount (); row++, order--) {
00094
00095 QStandardItem *item = new QStandardItem (QString::number (m_coefficients [order]));
00096 m_model->setItem (row, COLUMN_COEFFICIENTS, item);
00097 }
00098 }
00099
00100 void FittingWindow::clear ()
00101 {
00102 m_labelY->setText ("");
00103 m_model->setRowCount (0);
00104 m_lblMeanSquareError->setText ("");
00105 m_lblRootMeanSquare->setText ("");
00106 m_lblRSquared->setText ("");
00107 }
00108
00109 void FittingWindow::closeEvent(QCloseEvent * )
00110 {
00111 LOG4CPP_INFO_S ((*mainCat)) << "FittingWindow::closeEvent";
00112
00113 emit signalFittingWindowClosed();
00114 }
00115
00116 void FittingWindow::createWidgets (MainWindow *mainWindow)
00117 {
00118 QWidget *widget = new QWidget;
00119 setWidget (widget);
00120
00121 QGridLayout *layout = new QGridLayout;
00122 widget->setLayout (layout);
00123 int row = 0;
00124
00125
00126 QLabel *labelOrder = new QLabel (tr ("Order:"));
00127 layout->addWidget (labelOrder, row, 0, 1, 1);
00128
00129 m_cmbOrder = new QComboBox;
00130 for (int order = 0; order <= MAX_POLYNOMIAL_ORDER; order++) {
00131 m_cmbOrder->addItem (QString::number (order), QVariant (order));
00132 }
00133 connect (m_cmbOrder, SIGNAL (currentIndexChanged (int)), this, SLOT (slotCmbOrder (int)));
00134 layout->addWidget (m_cmbOrder, row++, 1, 1, 1);
00135
00136
00137 m_labelY = new QLabel;
00138 layout->addWidget (m_labelY, row++, 0, 1, 1);
00139
00140
00141 m_model = new FittingModel;
00142 m_model->setColumnCount (2);
00143
00144 m_view = new WindowTable (*m_model);
00145 connect (m_view, SIGNAL (signalTableStatusChange ()),
00146 mainWindow, SLOT (slotTableStatusChange ()));
00147
00148 layout->addWidget (m_view, row++, 0, 1, 2);
00149
00150
00151 QLabel *lblMeanSquareError = new QLabel (tr ("Mean square error:"));
00152 layout->addWidget (lblMeanSquareError, row, 0, 1, 1);
00153
00154 m_lblMeanSquareError = new QLineEdit;
00155 m_lblMeanSquareError->setReadOnly (true);
00156 m_lblMeanSquareError->setWhatsThis (tr ("Calculated mean square error statistic"));
00157 layout->addWidget (m_lblMeanSquareError, row++, 1, 1, 1);
00158
00159 QLabel *lblRootMeanSquare = new QLabel (tr ("Root mean square:"));
00160 layout->addWidget (lblRootMeanSquare, row, 0, 1, 1);
00161
00162 m_lblRootMeanSquare = new QLineEdit;
00163 m_lblRootMeanSquare->setReadOnly (true);
00164 m_lblRootMeanSquare->setWhatsThis (tr ("Calculated root mean square statistic. This is calculated as the square root of the mean square error"));
00165 layout->addWidget (m_lblRootMeanSquare, row++, 1, 1, 1);
00166
00167 QLabel *lblRSquared = new QLabel (tr ("R squared:"));
00168 layout->addWidget (lblRSquared, row, 0, 1, 1);
00169
00170 m_lblRSquared = new QLineEdit;
00171 m_lblRSquared->setReadOnly (true);
00172 m_lblRSquared->setWhatsThis (tr ("Calculated R squared statistic"));
00173 layout->addWidget (m_lblRSquared, row++, 1, 1, 1);
00174 }
00175
00176 void FittingWindow::doCopy ()
00177 {
00178 LOG4CPP_INFO_S ((*mainCat)) << "FittingWindow::doCopy";
00179
00180 QString text = m_model->selectionAsText (m_modelExport.delimiter());
00181
00182 if (!text.isEmpty ()) {
00183
00184
00185 QApplication::clipboard ()->setText (text);
00186
00187 }
00188 }
00189
00190 void FittingWindow::initializeOrder ()
00191 {
00192 const int SECOND_ORDER = 2;
00193
00194 int index = m_cmbOrder->findData (QVariant (SECOND_ORDER));
00195 m_cmbOrder->setCurrentIndex (index);
00196 }
00197
00198 int FittingWindow::maxOrder () const
00199 {
00200 return m_cmbOrder->currentData().toInt();
00201 }
00202
00203 void FittingWindow::refreshTable ()
00204 {
00205 int order = m_cmbOrder->currentData().toInt();
00206
00207
00208 resizeTable (order);
00209
00210 calculateCurveFitAndStatistics ();
00211 }
00212
00213 void FittingWindow::resizeTable (int order)
00214 {
00215 LOG4CPP_INFO_S ((*mainCat)) << "FittingWindow::resizeTable";
00216
00217 m_model->setRowCount (order + 1);
00218
00219
00220 QString yTerm = QString ("%1%2%3")
00221 .arg (m_curveSelected)
00222 .arg (m_curveSelected.isEmpty () ?
00223 "" :
00224 ": ")
00225 .arg (m_isLogYRadius ?
00226 tr ("log10(Y)=") :
00227 tr ("Y="));
00228 m_labelY->setText (yTerm);
00229
00230
00231 QString xString = (m_isLogXTheta ?
00232 tr ("log10(X)") :
00233 tr ("X"));
00234 for (int row = 0, term = order; term >= 0; row++, term--) {
00235
00236
00237 QString termString = QString ("%1%2%3%4")
00238 .arg ((term > 0) ? xString : "")
00239 .arg ((term > 1) ? "^" : "")
00240 .arg ((term > 1) ? QString::number (term) : "")
00241 .arg ((term > 0) ? "+" : "");
00242
00243 QStandardItem *item = new QStandardItem (termString);
00244 m_model->setItem (row, COLUMN_POLYNOMIAL_TERMS, item);
00245 }
00246 }
00247
00248 void FittingWindow::slotCmbOrder(int )
00249 {
00250 refreshTable ();
00251 }
00252
00253 void FittingWindow::update (const CmdMediator &cmdMediator,
00254 const MainWindowModel &modelMainWindow,
00255 const QString &curveSelected,
00256 const Transformation &transformation)
00257 {
00258 LOG4CPP_INFO_S ((*mainCat)) << "FittingWindow::update";
00259
00260
00261 m_curveSelected = curveSelected;
00262 m_modelExport = cmdMediator.document().modelExport();
00263 m_model->setDelimiter (m_modelExport.delimiter());
00264 m_isLogXTheta = (cmdMediator.document().modelCoords().coordScaleXTheta() == COORD_SCALE_LOG);
00265 m_isLogYRadius = (cmdMediator.document().modelCoords().coordScaleYRadius() == COORD_SCALE_LOG);
00266 m_view->setDragEnabled (modelMainWindow.dragDropExport());
00267
00268 m_pointsConvenient.clear ();
00269
00270 if (transformation.transformIsDefined()) {
00271
00272
00273 const Curve *curve = cmdMediator.document().curveForCurveName (curveSelected);
00274
00275 ENGAUGE_CHECK_PTR (curve);
00276
00277 if (curve->numPoints() > 0) {
00278
00279
00280 const Points points = curve->points();
00281 Points::const_iterator itr;
00282 for (itr = points.begin (); itr != points.end (); itr++) {
00283
00284 const Point &point = *itr;
00285 QPointF posScreen = point.posScreen ();
00286 QPointF posGraph;
00287 transformation.transformScreenToRawGraph (posScreen,
00288 posGraph);
00289
00290
00291 if (m_isLogXTheta) {
00292 double x = qLn (posGraph.x()) / qLn (10.0);
00293 posGraph.setX (x);
00294 }
00295 if (m_isLogYRadius) {
00296 double y = qLn (posGraph.y()) / qLn (10.0);
00297 posGraph.setY (y);
00298 }
00299
00300 m_pointsConvenient.append (posGraph);
00301 }
00302 }
00303 }
00304
00305 refreshTable ();
00306 }
00307
00308 QTableView *FittingWindow::view () const
00309 {
00310 return dynamic_cast<QTableView*> (m_view);
00311 }