1 /***************************************************************************
2 File : GriddingDialog.cpp
3 Project : QtiPlot
4 --------------------------------------------------------------------
5 Copyright : (C) 2010 by Ion Vasilief
6 Email (use @ for *) : ion_vasilief*yahoo.fr
7 Description : Gridding options dialog
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 "GriddingDialog.h"
30 #include <ApplicationWindow.h>
31 #include <Table.h>
32 #include <Matrix.h>
33 #include <DoubleSpinBox.h>
34
35 #include <QApplication>
36 #include <QGroupBox>
37 #include <QSpinBox>
38 #include <QMessageBox>
39 #include <QPushButton>
40 #include <QLabel>
41 #include <QComboBox>
42 #include <QLayout>
43
44 #include <idwint.h>
45
GriddingDialog(Table * t,const QString & colName,int nodes,QWidget * parent,Qt::WFlags fl)46 GriddingDialog::GriddingDialog(Table* t, const QString& colName, int nodes, QWidget* parent, Qt::WFlags fl )
47 : QDialog( parent, fl ),
48 d_table(t),
49 d_col_name(colName),
50 d_nodes(nodes)
51 {
52 setObjectName( "GriddingDialog" );
53 setWindowTitle(tr("QtiPlot - Random XYZ Gridding"));
54 setAttribute(Qt::WA_DeleteOnClose);
55 setSizeGripEnabled( true );
56
57 QGroupBox *gb1 = new QGroupBox();
58 QGridLayout *gl1 = new QGridLayout(gb1);
59 gl1->addWidget(new QLabel(tr("Selected Z Dataset")), 0, 0);
60
61 boxName = new QLabel(colName);
62 boxName->setFrameStyle(QFrame::Panel | QFrame::Sunken);
63 gl1->addWidget(boxName, 0, 1);
64
65 QLabel *methodLabel = new QLabel("<a href=\"http://www.alglib.net/interpolation/inversedistanceweighting.php\">" + tr("Gridding Method") + "</a>");
66 methodLabel->setOpenExternalLinks(true);
67 gl1->addWidget(methodLabel, 1, 0);
68 boxMethod = new QComboBox();
69 boxMethod->addItem(tr("Shepard (non-uniform data)"));
70 boxMethod->addItem(tr("Shepard (uniform data)"));
71 boxMethod->addItem(tr("Quick (noisy data)"));
72 gl1->addWidget(boxMethod, 1, 1);
73 gl1->setRowStretch(2, 1);
74
75 ApplicationWindow *app = (ApplicationWindow *)parent;
76 QLocale locale = app->locale();
77
78 gbRadius = new QGroupBox(tr("Parameters"));
79 QGridLayout *glRadius = new QGridLayout(gbRadius);
80
81 glRadius->addWidget(new QLabel(tr("Search Radius")), 0, 0);
82 boxRadius = new DoubleSpinBox();
83 boxRadius->setDecimals(app->d_decimal_digits);
84 boxRadius->setLocale(locale);
85 boxRadius->setValue(2.0);
86 boxRadius->setMinimum(0.1);
87 glRadius->addWidget(boxRadius, 0, 1);
88 glRadius->setRowStretch(1, 1);
89
90 gbModel = new QGroupBox(tr("Parameters"));
91 QGridLayout *glModel = new QGridLayout(gbModel);
92
93 glModel->addWidget(new QLabel(tr("Model")), 0, 0);
94 boxModel = new QComboBox();
95 boxModel->addItem(tr("Linear"));
96 boxModel->addItem(tr("Quadratic"));
97 glModel->addWidget(boxModel, 0, 1);
98
99 glModel->addWidget(new QLabel(tr("N<sub>q</sub>")), 1, 0);
100 boxNQ = new QSpinBox();
101 boxNQ->setMaximum(INT_MAX);
102 boxNQ->setValue(15);
103 glModel->addWidget(boxNQ, 1, 1);
104
105 glModel->addWidget(new QLabel(tr("N<sub>w</sub>")), 2, 0);
106 boxNW = new QSpinBox();
107 boxNW->setMaximum(INT_MAX);
108 boxNW->setValue(25);
109 glModel->addWidget(boxNW, 2, 1);
110 glModel->setRowStretch(3, 1);
111 gbModel->hide();
112
113 QGroupBox *gb2 = new QGroupBox(tr("Matrix Dimensions"));
114 QGridLayout *gl2 = new QGridLayout(gb2);
115
116 gl2->addWidget(new QLabel(tr("Columns")), 0, 0);
117 boxCols = new QSpinBox();
118 boxCols->setRange(2, 1000000);
119 boxCols->setValue(20);
120 gl2->addWidget(boxCols, 0, 1);
121
122 gl2->addWidget(new QLabel(tr("Rows")), 1, 0);
123 boxRows = new QSpinBox();
124 boxRows->setRange(2, 1000000);
125 boxRows->setValue(20);
126 gl2->addWidget(boxRows, 1, 1);
127 gl2->setRowStretch(2, 1);
128
129 QGroupBox *gb3 = new QGroupBox(tr("Matrix Coordinates"));
130 QGridLayout *gl3 = new QGridLayout(gb3);
131
132 gl3->addWidget(new QLabel(tr("X Minimum")), 0, 0);
133 boxXStart = new DoubleSpinBox();
134 boxXStart->setDecimals(app->d_decimal_digits);
135 boxXStart->setLocale(locale);
136 gl3->addWidget(boxXStart, 0, 1);
137
138 gl3->addWidget(new QLabel(tr("X Maximum")), 1, 0);
139 boxXEnd = new DoubleSpinBox();
140 boxXEnd->setDecimals(app->d_decimal_digits);
141 boxXEnd->setLocale(locale);
142 gl3->addWidget(boxXEnd, 1, 1);
143
144 gl3->addWidget(new QLabel(tr("Y Minimum")), 2, 0);
145 boxYStart = new DoubleSpinBox();
146 boxYStart->setDecimals(app->d_decimal_digits);
147 boxYStart->setLocale(locale);
148 gl3->addWidget(boxYStart, 2, 1);
149
150 gl3->addWidget(new QLabel(tr("Y Maximum")), 3, 0);
151 boxYEnd = new DoubleSpinBox();
152 boxYEnd->setDecimals(app->d_decimal_digits);
153 boxYEnd->setLocale(locale);
154 gl3->addWidget(boxYEnd, 3, 1);
155 gl3->setRowStretch(4, 1);
156
157 previewBox = new QGroupBox(tr("&Preview"));
158 previewBox->setCheckable(true);
159 previewBox->setChecked(true);
160
161 QGridLayout *gl4 = new QGridLayout(previewBox);
162 gl4->addWidget(new QLabel(tr("Plot Type")), 0, 0);
163
164 boxPlotStyle = new QComboBox();
165 boxPlotStyle->insertItem(tr("Wireframe"));
166 boxPlotStyle->insertItem(tr("Hidden Line"));
167 gl4->addWidget(boxPlotStyle, 0, 1);
168
169 showPlotBox = new QCheckBox(tr("Crea&te Plot"));
170 showPlotBox->setChecked(true);
171
172 buttonFit = new QPushButton(tr( "&Ok" ));
173 buttonFit->setDefault( true );
174 buttonCancel = new QPushButton(tr( "&Close" ));
175
176 QHBoxLayout *vl = new QHBoxLayout();
177 vl->addWidget(showPlotBox);
178 vl->addStretch();
179 vl->addWidget(buttonFit);
180 vl->addWidget(buttonCancel);
181
182 QVBoxLayout *hb = new QVBoxLayout();
183 hb->addWidget(gb1, 1);
184 hb->addWidget(gbRadius, 1);
185 hb->addWidget(gbModel, 1);
186 hb->addWidget(gb2, 1);
187 hb->addWidget(gb3, 1);
188 hb->addWidget(previewBox);
189 hb->addStretch();
190 hb->addLayout(vl);
191
192 sp = new Plot3D();
193 sp->setRotation(30, 0, 15);
194 sp->setScale(1, 1, 1);
195 sp->setShift(0.15, 0, 0);
196 sp->setZoom(0.9);
197 sp->setOrtho(app->d_3D_orthogonal);
198 sp->setSmoothMesh(app->d_3D_smooth_mesh);
199 sp->setLocale(app->locale());
200 sp->setCoordinateStyle(FRAME);
201 sp->coordinates()->setNumberFont(app->d_3D_numbers_font);
202 for (int i = 0; i < 12; i++)
203 sp->coordinates()->axes[i].setLabelFont(app->d_3D_axes_font);
204
205 resize(QSize(600, 400));
206
207 QHBoxLayout *hb1 = new QHBoxLayout(this);
208 hb1->addLayout(hb);
209 hb1->addWidget(sp, 1);
210
211 loadDataFromTable();
212 preview();
213
214 connect(previewBox, SIGNAL(toggled(bool)), this, SLOT(preview()));
215 connect(boxPlotStyle, SIGNAL(activated(int)), this, SLOT(setPlotStyle(int)));
216 connect(boxMethod, SIGNAL(activated(int)), this, SLOT(showMethodParameters(int)));
217 connect(boxRows, SIGNAL(valueChanged(int)), this, SLOT(preview()));
218 connect(boxCols, SIGNAL(valueChanged(int)), this, SLOT(preview()));
219 connect(boxNQ, SIGNAL(valueChanged(int)), this, SLOT(preview()));
220 connect(boxNW, SIGNAL(valueChanged(int)), this, SLOT(preview()));
221 connect(boxModel, SIGNAL(activated(int)), this, SLOT(preview()));
222 connect(boxRadius, SIGNAL(valueChanged(double)), this, SLOT(preview()));
223 connect(boxXStart, SIGNAL(valueChanged(double)), this, SLOT(preview()));
224 connect(boxXEnd, SIGNAL(valueChanged(double)), this, SLOT(preview()));
225 connect(boxYStart, SIGNAL(valueChanged(double)), this, SLOT(preview()));
226 connect(boxYEnd, SIGNAL(valueChanged(double)), this, SLOT(preview()));
227
228 connect( buttonFit, SIGNAL( clicked() ), this, SLOT( accept() ) );
229 connect( buttonCancel, SIGNAL( clicked() ), this, SLOT( close() ) );
230 }
231
showMethodParameters(int method)232 void GriddingDialog::showMethodParameters(int method)
233 {
234 if (method){
235 gbRadius->hide();
236 gbModel->show();
237 } else {
238 gbRadius->show();
239 gbModel->hide();
240 }
241 preview();
242 }
243
loadDataFromTable()244 void GriddingDialog::loadDataFromTable()
245 {
246 if (!d_table)
247 return;
248
249 ApplicationWindow *app = qobject_cast<ApplicationWindow *>(this->parent());
250 if (!app)
251 return;
252
253 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
254
255 QLocale locale = app->locale();
256 Q3TableSelection sel = d_table->getSelection();
257
258 int startRow = sel.topRow();
259 int endRow = sel.bottomRow();
260 int zcol = d_table->colIndex(d_col_name);
261 if (zcol < 0 || zcol >= d_table->numCols())
262 return;
263
264 int ycol = d_table->colY(zcol);
265 int xcol = d_table->colX(ycol);
266
267 xy.setlength(d_nodes, 3);
268
269 Curve *data_curve = new Curve(sp);
270 sp->addCurve(data_curve);
271
272 data_curve->setSmoothMesh(app->d_3D_smooth_mesh);
273 data_curve->setDataProjection(false);
274 data_curve->setProjection(BASE);
275 data_curve->setProjection(FACE, false);
276 data_curve->setProjection(SIDE, false);
277
278 Dot dot = Dot(5, true);
279 data_curve->setPlotStyle(dot);
280
281 Qwt3D::TripleField data;
282 Qwt3D::CellField cells;
283
284 int row = 0;
285 for (int i = startRow; i <= endRow; i++){
286 QString xs = d_table->text(i, xcol);
287 QString ys = d_table->text(i, ycol);
288 QString zs = d_table->text(i, zcol);
289 if (xs.isEmpty() || ys.isEmpty() || zs.isEmpty())
290 continue;
291
292 double x = locale.toDouble(xs);
293 double y = locale.toDouble(ys);
294 double z = locale.toDouble(zs);
295
296 xy(row, 0) = x;
297 xy(row, 1) = y;
298 xy(row, 2) = z;
299
300 data.push_back (Triple(x, y, z));
301 Qwt3D::Cell cell;
302 cell.push_back(row);
303 if (row > 0)
304 cell.push_back(row - 1);
305 cells.push_back (cell);
306
307 row++;
308 }
309
310 sp->makeCurrent();
311 data_curve->loadFromData (data, cells);
312 sp->updateData();
313
314 findBestLayout();
315
316 sp->updateGL();
317
318 data.clear();
319 cells.clear();
320
321 double xmin = xy(0, 0);
322 double xmax = xy(0, 0);
323 double ymin = xy(0, 1);
324 double ymax = xy(0, 1);
325 for (int i = 1; i < d_nodes; i++){
326 double x = xy(i, 0);
327 double y = xy(i, 1);
328
329 if (x < xmin)
330 xmin = x;
331 if (y < ymin)
332 ymin = y;
333
334 if (x > xmax)
335 xmax = x;
336 if (y > ymax)
337 ymax = y;
338 }
339
340 boxXStart->setValue(floor(xmin));
341 boxXEnd->setValue(ceil(xmax));
342 boxYStart->setValue(floor(ymin));
343 boxYEnd->setValue(ceil(ymax));
344
345 QApplication::restoreOverrideCursor();
346 }
347
accept()348 void GriddingDialog::accept()
349 {
350 ApplicationWindow *app = qobject_cast<ApplicationWindow *>(this->parent());
351 if (!app)
352 return;
353
354 double xmin = this->boxXStart->value();
355 double xmax = this->boxXEnd->value();
356 double ymin = this->boxYStart->value();
357 double ymax = this->boxYEnd->value();
358
359 int rows = boxRows->value();
360 int cols = boxCols->value();
361
362 double xstep = fabs(xmax - xmin)/(cols - 1);
363 double ystep = fabs(ymax - ymin)/(rows - 1);
364
365 Matrix* m = app->newMatrix(rows, cols);
366 m->setCoordinates(xmin, xmax, ymin, ymax);
367
368 idwinterpolant z;
369 switch (boxMethod->currentIndex()){
370 case 0:
371 idwbuildmodifiedshepardr(xy, d_nodes, 2, boxRadius->value(), z);
372 break;
373 case 1:
374 idwbuildmodifiedshepard(xy, d_nodes, 2, boxModel->currentIndex() + 1, boxNQ->value(), boxNW->value(), z);
375 break;
376 case 2:
377 idwbuildnoisy(xy, d_nodes, 2, boxModel->currentIndex() + 1, boxNQ->value(), boxNW->value(), z);
378 break;
379 }
380
381 ap::real_1d_array p;
382 p.setlength(2);
383 for (int i = 0; i < rows; i++){
384 p(1) = ymin + i*ystep;
385 for (int j = 0; j < cols; j++){
386 p(0) = xmin + j*xstep;
387 m->setCell(i, j, idwcalc(z, p));
388 }
389 }
390
391 if (showPlotBox->isChecked())
392 app->plot3DMatrix(m, 0);
393
394 close();
395 }
396
preview()397 void GriddingDialog::preview()
398 {
399 sp->setVisible(previewBox->isChecked());
400 if (!previewBox->isChecked())
401 return;
402
403 ApplicationWindow *app = qobject_cast<ApplicationWindow *>(this->parent());
404 if (!app)
405 return;
406
407 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
408
409 Curve *d_preview_curve = 0;
410 if (sp->curveList().size() == 1){
411 d_preview_curve = new Curve(sp);
412 sp->addCurve(d_preview_curve);
413
414 d_preview_curve->setSmoothMesh(app->d_3D_smooth_mesh);
415 d_preview_curve->setDataProjection(false);
416 d_preview_curve->setProjection(BASE);
417 d_preview_curve->setProjection(FACE, false);
418 d_preview_curve->setProjection(SIDE, false);
419 } else
420 d_preview_curve = sp->curve();
421
422 if (boxPlotStyle->currentIndex() == 0)
423 d_preview_curve->setPlotStyle(WIREFRAME);
424 else
425 d_preview_curve->setPlotStyle(HIDDENLINE);
426
427 double xmin = this->boxXStart->value();
428 double xmax = this->boxXEnd->value();
429 double ymin = this->boxYStart->value();
430 double ymax = this->boxYEnd->value();
431
432 int rows = boxRows->value();
433 int cols = boxCols->value();
434
435 double xstep = fabs(xmax - xmin)/(cols - 1);
436 double ystep = fabs(ymax - ymin)/(rows - 1);
437
438 idwinterpolant z;
439 switch (boxMethod->currentIndex()){
440 case 0:
441 idwbuildmodifiedshepardr(xy, d_nodes, 2, boxRadius->value(), z);
442 break;
443 case 1:
444 idwbuildmodifiedshepard(xy, d_nodes, 2, boxModel->currentIndex() + 1, boxNQ->value(), boxNW->value(), z);
445 break;
446 case 2:
447 idwbuildnoisy(xy, d_nodes, 2, boxModel->currentIndex() + 1, boxNQ->value(), boxNW->value(), z);
448 break;
449 }
450
451 ap::real_1d_array p;
452 p.setlength(2);
453
454 double **data_matrix = Matrix::allocateMatrixData(cols, rows);
455 for (int i = 0; i < rows; i++){
456 p(1) = ymin + i*ystep;
457 for (int j = 0; j < cols; j++){
458 p(0) = xmin + j*xstep;
459 data_matrix[j][i] = idwcalc(z, p);
460 }
461 }
462
463 sp->makeCurrent();
464 d_preview_curve->loadFromData(data_matrix, cols, rows, xmin, xmax, ymin, ymax);
465 resetAxesLabels();
466 Matrix::freeMatrixData(data_matrix, cols);
467
468 QApplication::restoreOverrideCursor();
469 }
470
setPlotStyle(int style)471 void GriddingDialog::setPlotStyle(int style)
472 {
473 Curve *d_preview_curve = 0;
474 if (sp->curveList().size() == 2)
475 d_preview_curve = sp->curve();
476 else
477 return;
478
479 sp->makeCurrent();
480 if (style == 0)
481 d_preview_curve->setPlotStyle(WIREFRAME);
482 else
483 d_preview_curve->setPlotStyle(HIDDENLINE);
484 sp->updateGL();
485 }
486
resetAxesLabels()487 void GriddingDialog::resetAxesLabels()
488 {
489 QString s = tr("X axis");
490 sp->coordinates()->axes[X1].setLabelString(s);
491 sp->coordinates()->axes[X2].setLabelString(s);
492 sp->coordinates()->axes[X3].setLabelString(s);
493 sp->coordinates()->axes[X4].setLabelString(s);
494
495 s = tr("Y axis");
496 sp->coordinates()->axes[Y1].setLabelString(s);
497 sp->coordinates()->axes[Y2].setLabelString(s);
498 sp->coordinates()->axes[Y3].setLabelString(s);
499 sp->coordinates()->axes[Y4].setLabelString(s);
500 }
501
findBestLayout()502 void GriddingDialog::findBestLayout()
503 {
504 double start, end;
505 sp->coordinates()->axes[X1].limits (start, end);
506 double xScale = 1/fabs(end - start);
507
508 sp->coordinates()->axes[Y1].limits (start, end);
509 double yScale = 1/fabs(end - start);
510
511 sp->coordinates()->axes[Z1].limits (start, end);
512 double zScale = 1/fabs(end - start);
513
514 double d = (sp->hull().maxVertex - sp->hull().minVertex).length();
515 sp->setScale(xScale, yScale, zScale);
516
517 sp->setZoom(d/sqrt(3.));
518
519 sp->setShift(0, 0, 0);
520
521 double majl = 0.1/yScale;
522 double minl = 0.6*majl;
523
524 sp->coordinates()->axes[X1].setTicLength (majl, minl);
525 sp->coordinates()->axes[X2].setTicLength (majl, minl);
526 sp->coordinates()->axes[X3].setTicLength (majl, minl);
527 sp->coordinates()->axes[X4].setTicLength (majl, minl);
528
529 majl = 0.1/xScale;
530 minl = 0.6*majl;
531
532 sp->coordinates()->axes[Y1].setTicLength (majl, minl);
533 sp->coordinates()->axes[Y2].setTicLength (majl, minl);
534 sp->coordinates()->axes[Y3].setTicLength (majl, minl);
535 sp->coordinates()->axes[Y4].setTicLength (majl, minl);
536 sp->coordinates()->axes[Z1].setTicLength (majl, minl);
537 sp->coordinates()->axes[Z2].setTicLength (majl, minl);
538 sp->coordinates()->axes[Z3].setTicLength (majl, minl);
539 sp->coordinates()->axes[Z4].setTicLength (majl, minl);
540
541 }
542
~GriddingDialog()543 GriddingDialog::~GriddingDialog()
544 {
545 delete sp;
546 }
547