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