Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
671 | werner | 1 | /******************************************************************************************** |
2 | ** iLand - an individual based forest landscape and disturbance model |
||
3 | ** http://iland.boku.ac.at |
||
4 | ** Copyright (C) 2009- Werner Rammer, Rupert Seidl |
||
5 | ** |
||
6 | ** This program is free software: you can redistribute it and/or modify |
||
7 | ** it under the terms of the GNU General Public License as published by |
||
8 | ** the Free Software Foundation, either version 3 of the License, or |
||
9 | ** (at your option) any later version. |
||
10 | ** |
||
11 | ** This program is distributed in the hope that it will be useful, |
||
12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
14 | ** GNU General Public License for more details. |
||
15 | ** |
||
16 | ** You should have received a copy of the GNU General Public License |
||
17 | ** along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
18 | ********************************************************************************************/ |
||
19 | |||
142 | Werner | 20 | #include <QtCore> |
780 | werner | 21 | #include <QtWidgets> |
145 | Werner | 22 | #include <QtXml> |
879 | werner | 23 | #include <QQuickView> |
24 | #include <QQmlEngine> |
||
25 | #include <QQmlContext> |
||
3 | Werner | 26 | |
452 | werner | 27 | #include <signal.h> |
28 | |||
216 | werner | 29 | #include "global.h" |
30 | #include "mainwindow.h" |
||
31 | #include "ui_mainwindow.h" |
||
323 | werner | 32 | #include "aboutdialog.h" |
216 | werner | 33 | |
104 | Werner | 34 | #include "model.h" |
106 | Werner | 35 | #include "standloader.h" |
105 | Werner | 36 | #include "stampcontainer.h" |
189 | iland | 37 | #include "resourceunit.h" |
105 | Werner | 38 | #include "speciesset.h" |
85 | Werner | 39 | #include "tree.h" |
493 | werner | 40 | #include "species.h" |
1179 | werner | 41 | #include "seeddispersal.h" |
1117 | werner | 42 | #include "saplings.h" |
1078 | werner | 43 | #include "climate.h" |
3 | Werner | 44 | |
105 | Werner | 45 | #include "exception.h" |
808 | werner | 46 | #include "helper.h" |
877 | werner | 47 | #include "colors.h" |
808 | werner | 48 | #include "debugtimer.h" |
49 | #include "statdata.h" |
||
105 | Werner | 50 | |
39 | Werner | 51 | #include "paintarea.h" |
52 | |||
142 | Werner | 53 | #include "expression.h" |
54 | #include "expressionwrapper.h" |
||
216 | werner | 55 | #include "management.h" |
229 | werner | 56 | #include "outputmanager.h" |
104 | Werner | 57 | |
157 | werner | 58 | #include "tests.h" |
596 | werner | 59 | #include "mapgrid.h" |
647 | werner | 60 | #include "layeredgrid.h" |
1009 | werner | 61 | #include "dem.h" |
202 | werner | 62 | |
896 | werner | 63 | #include "forestmanagementengine.h" // ABE |
64 | |||
9 | Werner | 65 | // global settings |
1157 | werner | 66 | static QDomDocument xmldoc; |
67 | static QDomNode xmlparams; |
||
20 | Werner | 68 | |
698 | werner | 69 | /** @class MainWindow |
70 | @ingroup GUI |
||
71 | The main window of the iLand viewer. |
||
72 | |||
73 | |||
74 | */ |
||
75 | |||
20 | Werner | 76 | |
40 | Werner | 77 | double distance(const QPointF &a, const QPointF &b) |
78 | { |
||
79 | return sqrt( (a.x()-b.x())*(a.x()-b.x()) + (a.y()-b.y())*(a.y()-b.y()) ); |
||
80 | } |
||
39 | Werner | 81 | |
30 | Werner | 82 | |
6 | Werner | 83 | double nrandom(const float& p1, const float& p2) |
84 | { |
||
85 | return p1 + (p2-p1)*(rand()/float(RAND_MAX)); |
||
86 | } |
||
87 | |||
1157 | werner | 88 | static bool showDebugMessages=true; |
89 | static QStringList bufferedMessages; |
||
90 | static bool doBufferMessages = false; |
||
91 | static bool doLogToWindow = false; |
||
360 | werner | 92 | void logToWindow(bool mode) |
93 | { |
||
94 | doLogToWindow = mode; |
||
95 | } |
||
96 | class LogToWindow |
||
97 | { |
||
98 | public: |
||
99 | LogToWindow() { logToWindow(true);} |
||
100 | ~LogToWindow() { logToWindow(false);} |
||
101 | }; |
||
267 | werner | 102 | |
359 | werner | 103 | |
1157 | werner | 104 | static QMutex qdebug_mutex; |
611 | werner | 105 | void dumpMessages(); |
780 | werner | 106 | void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) |
7 | Werner | 107 | { |
138 | Werner | 108 | |
780 | werner | 109 | Q_UNUSED(context); |
374 | werner | 110 | QMutexLocker m(&qdebug_mutex); |
780 | werner | 111 | //QByteArray localMsg = msg.toLocal8Bit(); |
138 | Werner | 112 | switch (type) { |
1053 | werner | 113 | case QtDebugMsg: |
194 | werner | 114 | if (showDebugMessages) { |
884 | werner | 115 | if (qstrcmp(context.category, "default")!=0) |
116 | bufferedMessages.append(QString("%1: %2").arg(context.category).arg(msg)); |
||
117 | else |
||
118 | bufferedMessages.append(QString(msg)); |
||
194 | werner | 119 | } |
120 | |||
1053 | werner | 121 | break; |
122 | case QtWarningMsg: |
||
1054 | werner | 123 | //case QtInfoMsg: |
1053 | werner | 124 | //MainWindow::logSpace()->appendPlainText(QString("WARNING: %1").arg(msg)); |
125 | //MainWindow::logSpace()->ensureCursorVisible(); |
||
126 | bufferedMessages.append(msg); |
||
127 | break; |
||
128 | case QtCriticalMsg: { |
||
780 | werner | 129 | QByteArray localMsg = msg.toLocal8Bit(); |
1053 | werner | 130 | fprintf(stderr, "Critical: %s\n", localMsg.constData()); |
131 | break; } |
||
132 | case QtFatalMsg: { |
||
780 | werner | 133 | QByteArray localMsg = msg.toLocal8Bit(); |
1053 | werner | 134 | fprintf(stderr, "Fatal: %s\n", localMsg.constData()); |
135 | bufferedMessages.append(msg); |
||
265 | werner | 136 | |
1053 | werner | 137 | QString file_name = GlobalSettings::instance()->path("fatallog.txt","log"); |
138 | Helper::msg(QString("Fatal message encountered:\n%1\nFatal-Log-File: %2").arg(msg, file_name)); |
||
139 | dumpMessages(); |
||
140 | Helper::saveToTextFile(file_name, MainWindow::logSpace()->toPlainText() + bufferedMessages.join("\n")); |
||
141 | } |
||
142 | } |
||
362 | werner | 143 | if (!doBufferMessages || bufferedMessages.count()>5000) |
267 | werner | 144 | dumpMessages(); |
145 | } |
||
7 | Werner | 146 | |
1157 | werner | 147 | static QMutex dump_message_mutex; |
611 | werner | 148 | void dumpMessages() |
149 | { |
||
150 | QMutexLocker m(&dump_message_mutex); // serialize access |
||
151 | // 2011-03-08: encountered "strange" crashes |
||
152 | // when a warning within Qt lead to a infinite loop/deadlock (also caused by mutex locking) |
||
153 | // now we prevent this by installing temporarily a 0-handler |
||
780 | werner | 154 | qInstallMessageHandler(0); |
611 | werner | 155 | |
156 | if (MainWindow::logStream() && !doLogToWindow) { |
||
157 | foreach(const QString &s, bufferedMessages) |
||
158 | *MainWindow::logStream() << s << endl; |
||
734 | werner | 159 | MainWindow::logStream()->flush(); |
611 | werner | 160 | |
161 | } else { |
||
162 | foreach(const QString &s, bufferedMessages) |
||
163 | MainWindow::logSpace()->appendPlainText(s); |
||
164 | |||
165 | // it does *not* work to just MainWindow::logSpace()->textCursor().movePosition()! |
||
166 | // you have to "setTextCursor()". |
||
167 | QTextCursor cursor = MainWindow::logSpace()->textCursor(); |
||
168 | cursor.movePosition(QTextCursor::End); |
||
169 | MainWindow::logSpace()->setTextCursor(cursor); |
||
170 | MainWindow::logSpace()->ensureCursorVisible(); |
||
171 | } |
||
172 | |||
173 | bufferedMessages.clear(); |
||
780 | werner | 174 | qInstallMessageHandler(myMessageOutput); |
611 | werner | 175 | } |
176 | |||
177 | |||
452 | werner | 178 | // handle signal... |
179 | // source: http://cplusplus.com/forum/unices/13455/ |
||
180 | void handle_signal( int signo ) { |
||
508 | werner | 181 | Helper::msg(QString("Received Signal:\n%1").arg(signo)); |
452 | werner | 182 | qDebug() << "*** Received signal "<< signo << "****"; |
183 | dumpMessages(); |
||
184 | |||
185 | } |
||
186 | |||
267 | werner | 187 | void MainWindow::bufferedLog(bool bufferLog) |
188 | { |
||
359 | werner | 189 | doBufferMessages = bufferLog; |
362 | werner | 190 | if (bufferLog==false) |
191 | dumpMessages(); |
||
267 | werner | 192 | } |
40 | Werner | 193 | |
360 | werner | 194 | void MainWindow::setupFileLogging(const bool do_start) |
195 | { |
||
196 | if (mLogStream) { |
||
197 | if (mLogStream->device()) |
||
198 | delete mLogStream->device(); |
||
199 | delete mLogStream; |
||
200 | mLogStream = NULL; |
||
201 | } |
||
202 | if (!do_start) |
||
203 | return; |
||
204 | |||
205 | if (GlobalSettings::instance()->settings().value("system.logging.logTarget", "console") == "file") { |
||
206 | QString fname = GlobalSettings::instance()->settings().value("system.logging.logFile", "logfile.txt"); |
||
207 | QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss"); |
||
208 | fname.replace("$date$", timestamp); |
||
362 | werner | 209 | fname = GlobalSettings::instance()->path(fname, "log"); |
210 | QFile *file = new QFile(fname); |
||
360 | werner | 211 | |
212 | if (!file->open(QIODevice::WriteOnly)) { |
||
213 | qDebug() << "cannot open logfile" << fname; |
||
214 | } else { |
||
215 | qDebug() << "Log output is redirected to logfile" << fname; |
||
216 | mLogStream = new QTextStream(file); |
||
217 | } |
||
218 | } |
||
219 | |||
220 | } |
||
221 | |||
222 | |||
7 | Werner | 223 | QPlainTextEdit *MainWindow::mLogSpace=NULL; |
359 | werner | 224 | QTextStream *MainWindow::mLogStream=NULL; |
7 | Werner | 225 | |
226 | |||
3 | Werner | 227 | MainWindow::MainWindow(QWidget *parent) |
228 | : QMainWindow(parent), ui(new Ui::MainWindowClass) |
||
229 | { |
||
230 | ui->setupUi(this); |
||
127 | Werner | 231 | |
3 | Werner | 232 | connect( ui->PaintWidget, SIGNAL(needsPainting(QPainter&)), |
233 | this, SLOT(repaintArea(QPainter&)) ); |
||
6 | Werner | 234 | connect (ui->PaintWidget, SIGNAL(mouseClick(QPoint)), |
235 | this, SLOT(mouseClick(const QPoint&))); |
||
113 | Werner | 236 | connect(ui->PaintWidget, SIGNAL(mouseDrag(QPoint,QPoint,Qt::MouseButton)), |
237 | this, SLOT(mouseDrag(const QPoint&, const QPoint &, const Qt::MouseButton))); |
||
49 | Werner | 238 | connect(ui->PaintWidget, SIGNAL(mouseMove(QPoint)), |
239 | this, SLOT(mouseMove(const QPoint&))); |
||
113 | Werner | 240 | connect(ui->PaintWidget, SIGNAL(mouseWheel(QPoint, int)), |
241 | this, SLOT(mouseWheel(const QPoint&, int))); |
||
40 | Werner | 242 | |
129 | Werner | 243 | // dock windows |
244 | ui->menuView->addAction( ui->dockEditor->toggleViewAction() ); |
||
245 | ui->menuView->addAction( ui->dockLogviewer->toggleViewAction() ); |
||
246 | ui->menuView->addAction( ui->dockWidget->toggleViewAction() ); |
||
150 | iland | 247 | ui->menuView->addAction( ui->dockModelDrill->toggleViewAction() ); |
113 | Werner | 248 | |
67 | Werner | 249 | ui->pbResults->setMenu(ui->menuOutput_menu); |
250 | |||
7 | Werner | 251 | mLogSpace = ui->logOutput; |
816 | werner | 252 | mLogSpace->setMaximumBlockCount(1000000); // set a maximum for the in-GUI size of messages. // removed in Qt5 (because it works ;) ) |
780 | werner | 253 | qInstallMessageHandler(myMessageOutput); |
452 | werner | 254 | // install signal handler |
255 | signal( SIGSEGV, handle_signal ); |
||
127 | Werner | 256 | |
716 | werner | 257 | readSettings(); |
258 | |||
767 | werner | 259 | // create global scripting context |
260 | GlobalSettings::instance()->resetScriptEngine(); |
||
261 | |||
320 | werner | 262 | // load xml file: use either a command-line argument (if present), or load the content of a small text file.... |
119 | Werner | 263 | QString argText = QApplication::arguments().last(); |
320 | werner | 264 | if (QApplication::arguments().count()>1 && !argText.isEmpty()) { |
119 | Werner | 265 | ui->initFileName->setText(argText); |
320 | werner | 266 | } else { |
716 | werner | 267 | QString lastXml = QSettings().value("project/lastxmlfile").toString(); |
268 | //QString lastXml = Helper::loadTextFile( QCoreApplication::applicationDirPath()+ "/lastxmlfile.txt" ); |
||
320 | werner | 269 | if (!lastXml.isEmpty() && QFile::exists(lastXml)) |
270 | ui->initFileName->setText(lastXml); |
||
271 | } |
||
19 | Werner | 272 | QString xmlFile = Helper::loadTextFile(ui->initFileName->text()); |
3 | Werner | 273 | |
65 | Werner | 274 | if (!xmlFile.isEmpty()) { |
275 | ui->iniEdit->setPlainText(xmlFile); |
||
189 | iland | 276 | QString errMsg; |
277 | int errLine, errCol; |
||
278 | if (!xmldoc.setContent(xmlFile, &errMsg, &errLine, &errCol)) { |
||
279 | QMessageBox::information(this, "title text", QString("Cannot set content of XML file %1. \nat line %2 col %3: %4 ") |
||
280 | .arg(ui->initFileName->text()).arg(errLine).arg(errCol).arg(errMsg)); |
||
1053 | werner | 281 | //return; |
65 | Werner | 282 | } |
19 | Werner | 283 | } |
284 | |||
20 | Werner | 285 | on_actionEdit_XML_settings_triggered(); |
19 | Werner | 286 | |
118 | Werner | 287 | qDebug() << "threadcount: " << QThread::idealThreadCount(); |
151 | iland | 288 | |
289 | // load window settings |
||
290 | QString fileName = QDir::current().filePath("gui.txt"); |
||
291 | if (QFile::exists(fileName)) { |
||
292 | |||
293 | QByteArray state = Helper::loadFile(fileName); |
||
294 | restoreState(state); |
||
295 | } |
||
129 | Werner | 296 | checkModelState(); |
220 | werner | 297 | ui->statusBar->addPermanentWidget(ui->modelRunProgress); |
221 | werner | 298 | ui->modelRunProgress->setValue(0); |
493 | werner | 299 | mStatusLabel = new QLabel(this); |
300 | labelMessage("no model created."); |
||
301 | ui->statusBar->addWidget(mStatusLabel); |
||
222 | werner | 302 | // remote control of model |
303 | connect(&mRemoteControl, SIGNAL(year(int)),this,SLOT(yearSimulated(int))); |
||
304 | connect(&mRemoteControl, SIGNAL(finished(QString)), this, SLOT(modelFinished(QString))); |
||
776 | werner | 305 | connect(&mRemoteControl, SIGNAL(stateChanged()), this, SLOT(checkModelState())); |
503 | werner | 306 | |
307 | // log levels |
||
308 | ui->actionDebug->setProperty("logLevel", QVariant(0)); |
||
309 | ui->actionInfo->setProperty("logLevel", QVariant(1)); |
||
310 | ui->actionWarning->setProperty("logLevel", QVariant(2)); |
||
311 | ui->actionError->setProperty("logLevel", QVariant(3)); |
||
312 | |||
514 | werner | 313 | // species filter |
314 | connect( ui->speciesFilterBox, SIGNAL(currentIndexChanged(int)), SLOT(repaint())); |
||
643 | werner | 315 | connect( ui->paintGridBox, SIGNAL(currentIndexChanged(int)), SLOT(repaint())); |
316 | updatePaintGridList(); |
||
514 | werner | 317 | |
590 | werner | 318 | // model controller |
319 | mRemoteControl.setMainWindow( this ); |
||
320 | mRemoteControl.connectSignals(); |
||
321 | GlobalSettings::instance()->setModelController( &mRemoteControl ); |
||
322 | |||
657 | werner | 323 | // automatic run |
324 | if (QApplication::arguments().contains("run")) { |
||
325 | QTimer::singleShot(3000, this, SLOT(automaticRun())); |
||
326 | } |
||
327 | |||
965 | werner | 328 | // to silence some warnings during startup - maybe not required (anymore): |
329 | qRegisterMetaType<QTextBlock>("QTextBlock"); |
||
330 | qRegisterMetaType<QTextCursor>("QTextCursor"); |
||
1046 | werner | 331 | |
332 | ui->iniEdit->setVisible(false); |
||
333 | ui->editStack->setTabEnabled(3,false); // the "other" tab |
||
879 | werner | 334 | // qml setup |
335 | QQuickView *view = new QQuickView(); |
||
336 | mRuler = view; |
||
337 | QWidget *container = QWidget::createWindowContainer(view, this); |
||
880 | werner | 338 | mRulerColors = new Colors(); |
339 | view->engine()->rootContext()->setContextProperty("rulercolors", mRulerColors); |
||
340 | view->setResizeMode(QQuickView::SizeRootObjectToView); |
||
1042 | werner | 341 | ui->pbReloadQml->setVisible(false); // enable for debug... |
342 | //view->setSource(QUrl::fromLocalFile("E:/dev/iland_port_qt5_64bit/src/iland/qml/ruler.qml")); |
||
343 | view->setSource(QUrl("qrc:/qml/ruler.qml")); |
||
879 | werner | 344 | //view->show(); |
345 | ui->qmlRulerLayout->addWidget(container); |
||
1046 | werner | 346 | ui->qmlRulerLayout->addWidget(container); |
880 | werner | 347 | // QDir d(":/qml"); |
348 | // qDebug() << d.entryList(); |
||
879 | werner | 349 | |
3 | Werner | 350 | } |
351 | |||
265 | werner | 352 | |
3 | Werner | 353 | MainWindow::~MainWindow() |
354 | { |
||
901 | werner | 355 | mRemoteControl.destroy(); // delete model and free resources. |
3 | Werner | 356 | delete ui; |
357 | } |
||
657 | werner | 358 | |
359 | void MainWindow::batchLog(const QString s) |
||
360 | { |
||
361 | QFile outfile(QCoreApplication::applicationDirPath()+ "/batchlog.txt"); |
||
362 | if (outfile.open(QIODevice::Append | QIODevice::Text)) { |
||
363 | QTextStream str(&outfile); |
||
364 | str << s << endl; |
||
365 | } |
||
366 | } |
||
367 | |||
368 | /// automatically start a simulation... |
||
369 | void MainWindow::automaticRun() |
||
370 | { |
||
371 | // start a simulation |
||
372 | setWindowTitle("iLand viewer --- batch mode"); |
||
373 | batchLog("*** iland batch mode ***"); |
||
374 | batchLog(QString("%1 Loading project %2").arg(QDateTime::currentDateTime().toString(Qt::ISODate), |
||
375 | ui->initFileName->text())); |
||
376 | batchLog(QString("%1 Loading the model...").arg(QDateTime::currentDateTime().toString(Qt::ISODate))); |
||
377 | setupModel(); |
||
378 | |||
379 | int count = QCoreApplication::arguments()[QCoreApplication::arguments().count()-2].toInt(); |
||
380 | if (count==0) { |
||
381 | qDebug() << "invalid number of years...."; |
||
382 | return; |
||
383 | } |
||
384 | ui->modelRunProgress->setMaximum(count-1); |
||
385 | batchLog(QString("%1 Running the model (%2 years)...").arg(QDateTime::currentDateTime().toString(Qt::ISODate)).arg(count)); |
||
658 | werner | 386 | // note the "+1": this is similar to the normal way of starting |
387 | // "1" means in Globals.year that we are in the 1st year. |
||
388 | // the simulation stops when reaching the count+1 year. |
||
389 | mRemoteControl.run(count + 1); |
||
657 | werner | 390 | |
661 | werner | 391 | // see the finsished() slot |
657 | werner | 392 | } |
393 | |||
200 | werner | 394 | // simply command an update of the painting area |
395 | void MainWindow::repaint() |
||
396 | { |
||
397 | ui->PaintWidget->update(); |
||
655 | werner | 398 | QCoreApplication::processEvents(); |
200 | werner | 399 | } |
3 | Werner | 400 | |
129 | Werner | 401 | // control GUI actions |
402 | void MainWindow::checkModelState() |
||
403 | { |
||
776 | werner | 404 | ui->actionModelCreate->setEnabled(mRemoteControl.canCreate()&& !mRemoteControl.isRunning()); |
405 | ui->actionModelDestroy->setEnabled(mRemoteControl.canDestroy() && !mRemoteControl.isRunning()); |
||
964 | werner | 406 | ui->actionModelRun->setEnabled(mRemoteControl.canRun() && !mRemoteControl.isPaused() && !mRemoteControl.isRunning()); |
776 | werner | 407 | ui->actionRun_one_year->setEnabled(mRemoteControl.canRun() && !mRemoteControl.isPaused()&& !mRemoteControl.isRunning()); |
964 | werner | 408 | ui->actionReload->setEnabled(mRemoteControl.canDestroy() && !mRemoteControl.isRunning()); |
225 | werner | 409 | ui->actionStop->setEnabled(mRemoteControl.isRunning()); |
410 | ui->actionPause->setEnabled(mRemoteControl.isRunning()); |
||
776 | werner | 411 | ui->actionPause->setText(mRemoteControl.isPaused()?"Continue":"Pause"); |
265 | werner | 412 | dumpMessages(); |
129 | Werner | 413 | } |
105 | Werner | 414 | |
415 | |||
3 | Werner | 416 | |
417 | |||
105 | Werner | 418 | void MainWindow::readwriteCycle() |
419 | { |
||
420 | |||
128 | Werner | 421 | if (!mRemoteControl.canRun()) |
105 | Werner | 422 | return; |
128 | Werner | 423 | |
403 | werner | 424 | Model *model = mRemoteControl.model(); |
425 | model->onlyApplyLightPattern(); |
||
105 | Werner | 426 | } |
427 | |||
72 | Werner | 428 | |
429 | |||
430 | |||
67 | Werner | 431 | QString MainWindow::dumpTreelist() |
432 | { |
||
128 | Werner | 433 | if (!mRemoteControl.isRunning()) |
105 | Werner | 434 | return ""; |
128 | Werner | 435 | |
436 | Model *model = mRemoteControl.model(); |
||
144 | Werner | 437 | |
438 | AllTreeIterator at(model); |
||
439 | DebugList treelist; |
||
440 | QString line; |
||
67 | Werner | 441 | QStringList result; |
144 | Werner | 442 | result << "id;species;dbh;height;x;y;RU#;LRI;mWoody;mRoot;mFoliage;LA"; |
443 | while (Tree *tree = at.next()) { |
||
444 | treelist.clear(); |
||
445 | tree->dumpList(treelist); |
||
446 | line = ""; |
||
447 | foreach(QVariant value, treelist) |
||
448 | line+=value.toString() + ";"; |
||
449 | result << line; |
||
67 | Werner | 450 | } |
451 | QString resStr = result.join("\n"); |
||
452 | return resStr; |
||
453 | } |
||
66 | Werner | 454 | |
643 | werner | 455 | void MainWindow::updatePaintGridList() |
456 | { |
||
457 | ui->paintGridBox->clear(); |
||
458 | ui->paintGridBox->addItem("<none>", ""); |
||
1047 | werner | 459 | QMap<QString, PaintObject>::const_iterator i = mPaintList.begin(); |
643 | werner | 460 | while (i!=mPaintList.constEnd()) { |
461 | ui->paintGridBox->addItem(i.key(),i.key()); |
||
462 | ++i; |
||
463 | } |
||
464 | } |
||
67 | Werner | 465 | |
647 | werner | 466 | void MainWindow::addLayers(const LayeredGridBase *layer, const QString &name) |
467 | { |
||
1014 | werner | 468 | const QVector<LayeredGridBase::LayerElement> &names = const_cast<LayeredGridBase*>(layer)->names(); |
647 | werner | 469 | int layer_id = 0; |
1062 | werner | 470 | QString current_layer = mPaintNext.name; |
877 | werner | 471 | foreach (const LayeredGridBase::LayerElement &layername, names) { |
472 | QString comb_name = QString("%1 - %2").arg(name, layername.name); |
||
647 | werner | 473 | PaintObject po; |
474 | po.what = PaintObject::PaintLayers; |
||
877 | werner | 475 | po.view_type = layername.view_type; |
647 | werner | 476 | po.layered = layer; |
477 | po.layer_id = layer_id++; |
||
899 | werner | 478 | po.name = layername.name; |
647 | werner | 479 | po.auto_range = true; |
480 | mPaintList[comb_name] = po; |
||
1062 | werner | 481 | if (current_layer == po.name) |
482 | mPaintNext.what = PaintObject::PaintHeightGrid; |
||
647 | werner | 483 | } |
484 | updatePaintGridList(); |
||
485 | } |
||
486 | |||
893 | werner | 487 | void MainWindow::removeLayers(const LayeredGridBase *layer) |
488 | { |
||
1047 | werner | 489 | QMap<QString, PaintObject>::iterator it=mPaintList.begin(); |
893 | werner | 490 | while(it!=mPaintList.end()) |
491 | if (it->layered == layer) |
||
492 | it = mPaintList.erase(it); |
||
493 | else |
||
494 | ++it; |
||
495 | if (mPaintNext.layered == layer) |
||
496 | mPaintNext.what = PaintObject::PaintHeightGrid; |
||
497 | } |
||
647 | werner | 498 | |
893 | werner | 499 | |
643 | werner | 500 | void MainWindow::paintGrid(MapGrid *map_grid, const QString &name, |
501 | const GridViewType view_type, |
||
502 | double min_val, double max_val) |
||
503 | { |
||
504 | if (map_grid==0 && !name.isEmpty()) { |
||
505 | // remove the grid from the list |
||
506 | mPaintList.remove(name); |
||
507 | updatePaintGridList(); |
||
508 | return; |
||
509 | } |
||
510 | mPaintNext.what=PaintObject::PaintMapGrid; |
||
511 | mPaintNext.min_value=min_val; mPaintNext.max_value=max_val; |
||
512 | mPaintNext.map_grid = map_grid; mPaintNext.view_type = view_type; |
||
513 | if (!name.isEmpty()) { |
||
514 | updatePaintGridList(); |
||
515 | mPaintList[name] = mPaintNext; |
||
516 | } |
||
732 | werner | 517 | ui->visOtherGrid->setChecked(true); |
643 | werner | 518 | repaint(); |
519 | } |
||
520 | |||
521 | void MainWindow::paintGrid(const FloatGrid *grid, const QString &name, |
||
522 | const GridViewType view_type, |
||
523 | double min_val, double max_val) |
||
524 | { |
||
525 | if (grid==0 && !name.isEmpty()) { |
||
526 | // remove the grid from the list |
||
527 | mPaintList.remove(name); |
||
528 | updatePaintGridList(); |
||
529 | return; |
||
530 | } |
||
531 | mPaintNext.what=PaintObject::PaintFloatGrid; |
||
532 | mPaintNext.min_value=min_val; |
||
533 | mPaintNext.max_value=max_val; |
||
534 | mPaintNext.float_grid = grid; |
||
535 | mPaintNext.view_type = view_type; |
||
881 | werner | 536 | mPaintNext.name = name; |
643 | werner | 537 | if (!name.isEmpty()) { |
538 | mPaintList[name] = mPaintNext; |
||
539 | updatePaintGridList(); |
||
540 | } |
||
732 | werner | 541 | ui->visOtherGrid->setChecked(true); |
643 | werner | 542 | repaint(); |
543 | } |
||
544 | |||
20 | Werner | 545 | void MainWindow::paintFON(QPainter &painter, QRect rect) |
3 | Werner | 546 | { |
105 | Werner | 547 | DebugTimer drawtimer("painting"); |
274 | werner | 548 | drawtimer.setSilent(); |
121 | Werner | 549 | |
128 | Werner | 550 | if (!mRemoteControl.canRun()) |
105 | Werner | 551 | return; |
128 | Werner | 552 | Model *model = mRemoteControl.model(); |
107 | Werner | 553 | |
128 | Werner | 554 | FloatGrid *grid = model->grid(); |
151 | iland | 555 | HeightGrid *domGrid = model->heightGrid(); |
3 | Werner | 556 | // do the actual painting |
127 | Werner | 557 | if (!grid) |
3 | Werner | 558 | return; |
48 | Werner | 559 | bool auto_scale_color = ui->visAutoScale->isChecked(); |
560 | bool show_fon = ui->visFon->isChecked(); |
||
561 | bool show_dom = ui->visDomGrid->isChecked(); |
||
291 | werner | 562 | bool show_trees = ui->visImpact->isChecked(); |
493 | werner | 563 | bool species_color = ui->visSpeciesColor->isChecked(); |
291 | werner | 564 | bool show_ru = ui->visResourceUnits->isChecked(); |
453 | werner | 565 | bool show_regeneration = ui->visRegeneration->isChecked(); |
1179 | werner | 566 | bool show_seedmaps = ui->visSeeds->isChecked(); |
732 | werner | 567 | bool other_grid = ui->visOtherGrid->isChecked(); |
48 | Werner | 568 | |
732 | werner | 569 | if (other_grid) { |
733 | werner | 570 | // return; // TODO TEST |
732 | werner | 571 | if (ui->paintGridBox->currentIndex()>-1) { |
572 | QString name = ui->paintGridBox->itemData(ui->paintGridBox->currentIndex()).toString(); |
||
573 | if (!name.isEmpty()) |
||
574 | mPaintNext = mPaintList[name]; |
||
575 | } |
||
643 | werner | 576 | |
732 | werner | 577 | if (mPaintNext.what != PaintObject::PaintNothing) { |
881 | werner | 578 | if (mPaintNext.what == PaintObject::PaintMapGrid) { |
579 | mRulerColors->setCaption(mPaintNext.name); |
||
732 | werner | 580 | paintMapGrid(painter, mPaintNext.map_grid, 0, mPaintNext.view_type, mPaintNext.min_value, mPaintNext.max_value); |
881 | werner | 581 | } |
596 | werner | 582 | |
881 | werner | 583 | if (mPaintNext.what == PaintObject::PaintFloatGrid) { |
584 | mRulerColors->setCaption(mPaintNext.name); |
||
732 | werner | 585 | paintMapGrid(painter, 0, mPaintNext.float_grid, mPaintNext.view_type, mPaintNext.min_value, mPaintNext.max_value); |
881 | werner | 586 | } |
642 | werner | 587 | |
732 | werner | 588 | if (mPaintNext.what == PaintObject::PaintLayers) |
589 | paintGrid(painter, mPaintNext); |
||
647 | werner | 590 | |
732 | werner | 591 | return; |
592 | } |
||
596 | werner | 593 | } |
594 | |||
647 | werner | 595 | |
596 | // clear background |
||
597 | painter.fillRect(ui->PaintWidget->rect(), Qt::white); |
||
598 | // draw rectangle around the grid |
||
599 | QRectF r = grid->metricRect(); |
||
600 | QRect rs = vp.toScreen(r); |
||
1064 | werner | 601 | painter.setPen(Qt::darkGray); |
647 | werner | 602 | painter.drawRect(rs); |
822 | werner | 603 | //qDebug() << rs; |
647 | werner | 604 | |
605 | // what to paint?? |
||
606 | |||
48 | Werner | 607 | float maxval=1.f; // default maximum |
1041 | werner | 608 | float minval=0.f; |
48 | Werner | 609 | if (!auto_scale_color) |
127 | Werner | 610 | maxval =grid->max(); |
3 | Werner | 611 | if (maxval==0.) |
612 | return; |
||
514 | werner | 613 | QString species; |
614 | if (ui->speciesFilterBox->currentIndex()>-1) |
||
615 | species = ui->speciesFilterBox->itemData(ui->speciesFilterBox->currentIndex()).toString(); |
||
616 | |||
3 | Werner | 617 | int ix,iy; |
618 | QColor fill_color; |
||
619 | float value; |
||
70 | Werner | 620 | |
291 | werner | 621 | if (show_fon ) { |
622 | |||
105 | Werner | 623 | // start from each pixel and query value in grid for the pixel |
880 | werner | 624 | mRulerColors->setCaption("Light Influence Field", "value of the LIF at 2m resolution."); |
1064 | werner | 625 | mRulerColors->setPalette(GridViewRainbowReverse,0., maxval); // ruler |
1041 | werner | 626 | if (!mRulerColors->autoScale()) { |
1157 | werner | 627 | maxval = static_cast<float>( mRulerColors->maxValue()); |
628 | minval = static_cast<float>( mRulerColors->minValue() ); |
||
1041 | werner | 629 | } |
105 | Werner | 630 | int x,y; |
631 | int sizex = rect.width(); |
||
632 | int sizey = rect.height(); |
||
633 | QPointF world; |
||
634 | QRgb col; |
||
635 | QImage &img = ui->PaintWidget->drawImage(); |
||
636 | for (x=0;x<sizex;x++) |
||
637 | for (y=0;y<sizey;y++) { |
||
643 | werner | 638 | world = vp.toWorld(QPoint(x,y)); |
639 | if (grid->coordValid(world)) { |
||
640 | value = grid->valueAt(world); |
||
1064 | werner | 641 | col = Colors::colorFromValue(value, minval, maxval,true).rgb(); |
643 | werner | 642 | img.setPixel(x,y,col); |
643 | } |
||
291 | werner | 644 | } |
70 | Werner | 645 | |
291 | werner | 646 | } |
41 | Werner | 647 | |
1179 | werner | 648 | if (show_seedmaps) { |
649 | if (species.isEmpty()) { |
||
650 | qDebug() << "Please select a species!"; |
||
651 | return; |
||
652 | } |
||
653 | int x,y; |
||
654 | mRulerColors->setCaption("Seed availability", QString("seed availability of species %1").arg(species)); |
||
655 | mRulerColors->setPalette(GridViewRainbow,0., 1.); // ruler |
||
656 | int sizex = rect.width(); |
||
657 | int sizey = rect.height(); |
||
658 | QPointF world; |
||
659 | QRgb col; |
||
660 | QImage &img = ui->PaintWidget->drawImage(); |
||
661 | const Grid<float> &grid = GlobalSettings::instance()->model()->speciesSet()->species(species)->seedDispersal()->seedMap(); |
||
662 | QRgb gray_bg = QColor(100,100,100).rgb(); |
||
663 | |||
664 | for (x=0;x<sizex;x++) |
||
665 | for (y=0;y<sizey;y++) { |
||
666 | world = vp.toWorld(QPoint(x,y)); |
||
667 | if (grid.coordValid(world)) { |
||
668 | value = grid.constValueAt(world); |
||
669 | col = value>0.f ? Colors::colorFromValue(value, 0., 1., false).rgb() : gray_bg; |
||
670 | img.setPixel(x,y,col); |
||
671 | } |
||
672 | } |
||
673 | |||
674 | } |
||
675 | |||
453 | werner | 676 | if (show_regeneration ) { |
677 | |||
678 | if (mRegenerationGrid.isEmpty()) |
||
679 | mRegenerationGrid.setup(*model->grid()); // copy |
||
1117 | werner | 680 | if (!GlobalSettings::instance()->model()->saplings()) |
681 | return; |
||
453 | werner | 682 | static int last_year=0; |
514 | werner | 683 | static QString last_species=""; |
1178 | werner | 684 | static bool last_regen_mode=false; |
685 | if (last_year!=GlobalSettings::instance()->currentYear() || species!=last_species || ui->visRegenNew->isChecked()!=last_regen_mode) { |
||
453 | werner | 686 | last_year=GlobalSettings::instance()->currentYear(); |
514 | werner | 687 | last_species=species; |
1178 | werner | 688 | bool draw_established = ui->visRegenNew->isChecked(); |
689 | last_regen_mode = draw_established; |
||
453 | werner | 690 | // fill grid... |
691 | DebugTimer t("create regeneration map..."); |
||
692 | mRegenerationGrid.wipe(0.f); |
||
1117 | werner | 693 | if (species.isEmpty()) { |
694 | // hmax of all species |
||
1159 | werner | 695 | for (float *rg=mRegenerationGrid.begin();rg!=mRegenerationGrid.end(); ++rg) { |
696 | SaplingCell *sc=GlobalSettings::instance()->model()->saplings()->cell(mRegenerationGrid.indexOf(rg)); |
||
1178 | werner | 697 | if (sc) { |
698 | if (draw_established) |
||
699 | *rg = sc->has_new_saplings() ? 1.f : 0.f; |
||
700 | else |
||
701 | *rg = sc->max_height(); |
||
702 | } |
||
703 | |||
453 | werner | 704 | } |
1117 | werner | 705 | } else { |
706 | // filter a specific species |
||
707 | int sidx = GlobalSettings::instance()->model()->speciesSet()->species(species)->index(); |
||
1159 | werner | 708 | for (float *rg=mRegenerationGrid.begin(); rg!=mRegenerationGrid.end(); ++rg) { |
709 | SaplingCell *sc=GlobalSettings::instance()->model()->saplings()->cell(mRegenerationGrid.indexOf(rg)); |
||
710 | if (sc) { |
||
711 | SaplingTree *st=sc->sapling(sidx); |
||
1178 | werner | 712 | if (st) { |
713 | if (draw_established) |
||
714 | *rg = st->is_occupied() && st->age<2 ? 1.f : 0.f; |
||
715 | else |
||
716 | *rg = st ? st->height : 0.f; |
||
717 | } |
||
1159 | werner | 718 | } |
1117 | werner | 719 | } |
453 | werner | 720 | } |
721 | } |
||
722 | // start from each pixel and query value in grid for the pixel |
||
723 | int x,y; |
||
880 | werner | 724 | mRulerColors->setCaption("Regeneration Layer", "max. tree height of regeneration layer (blue=0m, red=4m)"); |
725 | mRulerColors->setPalette(GridViewRainbow,0., 4.); // ruler |
||
453 | werner | 726 | int sizex = rect.width(); |
727 | int sizey = rect.height(); |
||
728 | QPointF world; |
||
729 | QRgb col; |
||
730 | QImage &img = ui->PaintWidget->drawImage(); |
||
1064 | werner | 731 | |
453 | werner | 732 | for (x=0;x<sizex;x++) |
733 | for (y=0;y<sizey;y++) { |
||
643 | werner | 734 | world = vp.toWorld(QPoint(x,y)); |
735 | if (mRegenerationGrid.coordValid(world)) { |
||
736 | value = mRegenerationGrid.valueAt(world); |
||
877 | werner | 737 | col = Colors::colorFromValue(value, 0., 4., false).rgb(); // 0..4m |
643 | werner | 738 | img.setPixel(x,y,col); |
739 | } |
||
453 | werner | 740 | } |
741 | } |
||
742 | |||
291 | werner | 743 | if (show_dom) { |
744 | // paint the lower-res-grid; |
||
1053 | werner | 745 | float max_val = 50.f; |
746 | float min_val = 0.f; |
||
539 | werner | 747 | if (auto_scale_color) { |
748 | max_val = 0.; |
||
749 | for (HeightGridValue *v = domGrid->begin(); v!=domGrid->end(); ++v) |
||
750 | max_val = qMax(max_val, v->height); |
||
751 | } |
||
880 | werner | 752 | mRulerColors->setCaption("Dominant height (m)", "dominant tree height on 10m pixel."); |
753 | mRulerColors->setPalette(GridViewRainbow,0., max_val); // ruler |
||
1041 | werner | 754 | if (!mRulerColors->autoScale()) { |
1157 | werner | 755 | min_val = static_cast<float>( mRulerColors->minValue() ); |
756 | max_val = static_cast<float>( mRulerColors->maxValue() ); |
||
1041 | werner | 757 | } |
291 | werner | 758 | for (iy=0;iy<domGrid->sizeY();iy++) { |
759 | for (ix=0;ix<domGrid->sizeX();ix++) { |
||
760 | QPoint p(ix,iy); |
||
714 | werner | 761 | const HeightGridValue &hgv = domGrid->valueAtIndex(p); |
762 | if (hgv.isValid()) { |
||
538 | werner | 763 | value = domGrid->valueAtIndex(p).height; |
764 | QRect r = vp.toScreen(domGrid->cellRect(p)); |
||
877 | werner | 765 | fill_color = Colors::colorFromValue(value, 0., max_val); // 0..50m |
538 | werner | 766 | painter.fillRect(r, fill_color); |
767 | } |
||
714 | werner | 768 | // areas "outside" are drawn as gray. |
718 | werner | 769 | if (hgv.isForestOutside()) { |
714 | werner | 770 | QRect r = vp.toScreen(domGrid->cellRect(p)); |
720 | werner | 771 | if (hgv.isRadiating()) |
1040 | werner | 772 | painter.fillRect(r, Qt::gray); |
720 | werner | 773 | else |
1041 | werner | 774 | painter.fillRect(r, QColor(240,240,240)); |
720 | werner | 775 | |
714 | werner | 776 | } |
291 | werner | 777 | } |
778 | } |
||
40 | Werner | 779 | |
291 | werner | 780 | } // if (show_dom) |
105 | Werner | 781 | |
291 | werner | 782 | if (show_ru){ |
783 | QString ru_expr = ui->lTreeExpr->text(); |
||
784 | if (ru_expr.isEmpty()) |
||
785 | ru_expr = "id"; |
||
786 | RUWrapper ru_wrapper; |
||
105 | Werner | 787 | |
291 | werner | 788 | Expression ru_value(ru_expr, &ru_wrapper); |
789 | ru_value.setCatchExceptions(); // silent catching... |
||
1040 | werner | 790 | |
1041 | werner | 791 | species_color = ui->visRUSpeciesColor->isChecked(); |
1040 | werner | 792 | const Species *drawspecies=0; |
793 | GridViewType view_type = GridViewRainbow; |
||
794 | if (species_color) { |
||
795 | drawspecies = model->speciesSet()->species(species); |
||
796 | view_type = GridViewGreens; |
||
797 | } |
||
798 | |||
558 | werner | 799 | double min_value = 0.; |
800 | double max_value = 1.; // defaults |
||
801 | double value; |
||
1041 | werner | 802 | if (!mRulerColors->autoScale()) { |
803 | max_value = mRulerColors->maxValue(); |
||
804 | min_value = mRulerColors->minValue(); |
||
805 | |||
806 | } else if (auto_scale_color) { |
||
558 | werner | 807 | min_value = 9999999999999999999.; |
808 | max_value = -999999999999999999.; |
||
809 | foreach (const ResourceUnit *ru, model->ruList()) { |
||
1180 | werner | 810 | if (species_color && drawspecies) { |
1040 | werner | 811 | value = ru->constResourceUnitSpecies(drawspecies)->constStatistics().basalArea(); |
812 | } else { |
||
813 | ru_wrapper.setResourceUnit(ru); |
||
814 | value = ru_value.execute(); |
||
815 | } |
||
558 | werner | 816 | min_value = qMin(min_value, value); |
817 | max_value = qMax(max_value, value); |
||
818 | } |
||
819 | qDebug() << "scale colors: min" << min_value << "max:" << max_value; |
||
820 | } |
||
40 | Werner | 821 | |
1040 | werner | 822 | if (species_color) { |
1180 | werner | 823 | if (drawspecies) { |
824 | drawspecies = model->speciesSet()->species(species); |
||
825 | mRulerColors->setCaption("Species share", QString("Species: '%1'").arg(species)); |
||
826 | mRulerColors->setPalette(GridViewGreens, static_cast<float>(min_value), static_cast<float>(max_value)); // ruler |
||
827 | } else { |
||
828 | mRulerColors->setCaption("Dominant species on resource unit", "The color indicates the species with the biggest share of basal area. \nDashed fill, if the basal area of the max-species is <50%."); |
||
829 | QList<const Species*> specieslist=mRemoteControl.availableSpecies(); |
||
830 | QStringList colors; QStringList speciesnames; |
||
831 | for (int i=0; i<specieslist.count();++i) { |
||
832 | colors.append(specieslist[i]->displayColor().name()); |
||
833 | speciesnames.append(specieslist[i]->name()); |
||
834 | } |
||
835 | mRulerColors->setFactorColors(colors); |
||
836 | mRulerColors->setFactorLabels(speciesnames); |
||
837 | mRulerColors->setPalette(GridViewCustom, 0., 1.); |
||
838 | } |
||
1040 | werner | 839 | } else { |
840 | mRulerColors->setCaption("Resource Units", QString("Result of expression: '%1'").arg(ru_expr)); |
||
1157 | werner | 841 | mRulerColors->setPalette(GridViewRainbow, static_cast<float>(min_value), static_cast<float>(max_value)); // ruler |
1040 | werner | 842 | } |
843 | |||
291 | werner | 844 | // paint resource units |
1180 | werner | 845 | painter.setPen(Qt::black); |
291 | werner | 846 | foreach (const ResourceUnit *ru, model->ruList()) { |
1180 | werner | 847 | bool stroke = false; |
848 | if (species_color) { |
||
849 | if (drawspecies) { |
||
850 | value = ru->constResourceUnitSpecies(drawspecies)->constStatistics().basalArea(); |
||
851 | fill_color = Colors::colorFromValue(static_cast<float>(value), view_type, static_cast<float>(min_value), static_cast<float>(max_value)); |
||
852 | } else { |
||
853 | const Species *max_sp=0; double max_ba = 0.; double total_ba=0.; |
||
854 | foreach(const ResourceUnitSpecies *rus, ru->ruSpecies()) { |
||
855 | total_ba += rus->constStatistics().basalArea(); |
||
856 | if (rus->constStatistics().basalArea()>max_ba) { |
||
857 | max_ba = rus->constStatistics().basalArea(); |
||
858 | max_sp=rus->species(); |
||
859 | } |
||
860 | } |
||
861 | if (max_sp) { |
||
862 | fill_color = max_sp->displayColor(); |
||
863 | if (max_ba < total_ba*0.5) { |
||
864 | stroke = true; |
||
865 | } |
||
866 | } else |
||
867 | fill_color = Qt::white; |
||
868 | } |
||
1040 | werner | 869 | } else { |
870 | ru_wrapper.setResourceUnit(ru); |
||
871 | value = ru_value.execute(); |
||
1180 | werner | 872 | fill_color = Colors::colorFromValue(static_cast<float>(value), view_type, static_cast<float>(min_value), static_cast<float>(max_value)); |
1040 | werner | 873 | } |
291 | werner | 874 | QRect r = vp.toScreen(ru->boundingBox()); |
1040 | werner | 875 | //fill_color = Colors::colorFromValue(value, min_value, max_value); |
1180 | werner | 876 | //fill_color = Colors::colorFromValue(static_cast<float>(value), view_type, static_cast<float>(min_value), static_cast<float>(max_value)); |
877 | if (stroke) |
||
878 | painter.fillRect(r, QBrush(fill_color, Qt::Dense3Pattern)); |
||
879 | else |
||
880 | painter.fillRect(r, fill_color); |
||
291 | werner | 881 | } |
882 | if (!ru_value.lastError().isEmpty()) |
||
883 | qDebug() << "Expression error while painting: " << ru_value.lastError(); |
||
884 | } |
||
48 | Werner | 885 | |
291 | werner | 886 | if (show_trees) { |
148 | iland | 887 | QString single_tree_expr = ui->lTreeExpr->text(); |
888 | if (single_tree_expr.isEmpty()) |
||
889 | single_tree_expr = "1-lri"; |
||
890 | TreeWrapper tw; |
||
891 | |||
892 | Expression tree_value(single_tree_expr, &tw); // get maximum value |
||
893 | tree_value.setCatchExceptions(); // silent catching... |
||
894 | |||
818 | werner | 895 | QString filter_expr = ui->expressionFilter->text(); |
896 | bool do_filter = ui->cbDrawFiltered->isChecked(); |
||
897 | if (filter_expr.isEmpty()) |
||
898 | filter_expr = "1"; // a constant, always true |
||
899 | |||
900 | Expression tree_filter(filter_expr, &tw); |
||
901 | tree_filter.setCatchExceptions(); |
||
902 | |||
903 | bool draw_transparent = ui->drawTransparent->isChecked(); |
||
128 | Werner | 904 | AllTreeIterator treelist(model); |
107 | Werner | 905 | Tree *tree; |
392 | werner | 906 | painter.setPen(Qt::gray); |
1041 | werner | 907 | double max_val=1., min_val=0.; |
908 | if (!mRulerColors->autoScale()) { |
||
909 | max_val = mRulerColors->maxValue(); min_val = mRulerColors->minValue(); |
||
910 | } |
||
911 | |||
145 | Werner | 912 | while ((tree = treelist.next())) { |
114 | Werner | 913 | if ( !vp.isVisible(treelist.currentRU()->boundingBox()) ) { |
914 | continue; |
||
915 | } |
||
514 | werner | 916 | // filter species... |
917 | if (!species.isEmpty()) |
||
918 | if (tree->species()->id() != species) |
||
919 | continue; |
||
920 | |||
716 | werner | 921 | // filter out dead trees |
922 | if (tree->isDead()) |
||
923 | continue; |
||
924 | |||
818 | werner | 925 | // filter (user defined) |
926 | if (do_filter) { |
||
927 | tw.setTree(tree); |
||
928 | if (tree_filter.execute()==0.) |
||
929 | continue; |
||
930 | } |
||
931 | |||
107 | Werner | 932 | QPointF pos = tree->position(); |
56 | Werner | 933 | QPoint p = vp.toScreen(pos); |
493 | werner | 934 | if (species_color) { |
935 | // use species specific color.... |
||
936 | fill_color = tree->species()->displayColor(); |
||
937 | } else { |
||
938 | // calculate expression |
||
939 | tw.setTree(tree); |
||
1157 | werner | 940 | value = static_cast<float>(tree_value.execute()); |
941 | fill_color = Colors::colorFromValue(value, static_cast<float>(min_val), static_cast<float>(max_val), false); |
||
493 | werner | 942 | } |
818 | werner | 943 | if (draw_transparent) |
824 | werner | 944 | fill_color.setAlpha(80); // 50% |
48 | Werner | 945 | painter.setBrush(fill_color); |
407 | werner | 946 | int diameter = qMax(1,vp.meterToPixel( tree->crownRadius())); |
56 | Werner | 947 | painter.drawEllipse(p, diameter, diameter); |
107 | Werner | 948 | } |
291 | werner | 949 | if (!tree_value.lastError().isEmpty()) |
950 | qDebug() << "Expression error while painting: " << tree_value.lastError(); |
||
880 | werner | 951 | // ruler |
952 | if (species_color) { |
||
953 | mRulerColors->setCaption("Single trees", "species specific colors."); |
||
1066 | werner | 954 | QList<const Species*> specieslist=mRemoteControl.availableSpecies(); |
880 | werner | 955 | QStringList colors; QStringList speciesnames; |
1066 | werner | 956 | for (int i=0; i<specieslist.count();++i) { |
957 | colors.append(specieslist[i]->displayColor().name()); |
||
958 | speciesnames.append(specieslist[i]->name()); |
||
880 | werner | 959 | } |
960 | mRulerColors->setFactorColors(colors); |
||
961 | mRulerColors->setFactorLabels(speciesnames); |
||
962 | mRulerColors->setPalette(GridViewCustom, 0., 1.); |
||
963 | } else { |
||
964 | mRulerColors->setCaption("Single trees", QString("result of expression: '%1'").arg(single_tree_expr)); |
||
965 | mRulerColors->setPalette(GridViewRainbow, 0., 1.); |
||
48 | Werner | 966 | |
880 | werner | 967 | } |
968 | |||
291 | werner | 969 | } // if (show_trees) |
970 | |||
971 | // highlight selected tree |
||
1157 | werner | 972 | Tree *t = reinterpret_cast<Tree*>( ui->treeChange->property("tree").toLongLong() ); |
40 | Werner | 973 | if (t) { |
974 | QPointF pos = t->position(); |
||
975 | painter.setPen(Qt::black); |
||
56 | Werner | 976 | QPoint p = vp.toScreen(pos); |
977 | painter.drawRect( p.x()-1, p.y()-1, 3,3); |
||
40 | Werner | 978 | } |
70 | Werner | 979 | } |
55 | Werner | 980 | |
647 | werner | 981 | void MainWindow::paintGrid(QPainter &painter, PaintObject &object) |
982 | { |
||
983 | painter.fillRect(ui->PaintWidget->rect(), object.background_color); |
||
741 | werner | 984 | bool clip_with_stand_grid = ui->visClipStandGrid->isChecked(); |
1009 | werner | 985 | bool shading = ui->visShading->isChecked(); |
986 | if (!mRemoteControl.model() || !mRemoteControl.model()->dem()) |
||
987 | shading=false; |
||
647 | werner | 988 | |
1009 | werner | 989 | |
688 | werner | 990 | int sx=0, sy=0; |
647 | werner | 991 | QRect total_rect; |
992 | object.cur_min_value = object.min_value; |
||
993 | object.cur_max_value = object.max_value; |
||
994 | switch (object.what) { |
||
995 | case PaintObject::PaintMapGrid: |
||
996 | sx = object.map_grid->grid().sizeX(); |
||
997 | sy = object.map_grid->grid().sizeY(); |
||
998 | total_rect = vp.toScreen(object.map_grid->grid().metricRect()); |
||
880 | werner | 999 | mRulerColors->setCaption("Map grid"); |
647 | werner | 1000 | break; |
1001 | case PaintObject::PaintFloatGrid: |
||
1002 | sx = object.float_grid->sizeX(); |
||
1003 | sy = object.float_grid->sizeY(); |
||
1004 | total_rect = vp.toScreen(object.float_grid->metricRect()); |
||
880 | werner | 1005 | mRulerColors->setCaption("Floating point grid"); |
647 | werner | 1006 | break; |
1007 | case PaintObject::PaintLayers: |
||
1008 | sx = object.layered->sizeX(); |
||
1009 | sy = object.layered->sizeY(); |
||
1010 | total_rect = vp.toScreen(object.layered->metricRect()); |
||
1011 | if (object.auto_range) { |
||
1012 | object.layered->range( object.cur_min_value, object.cur_max_value, object.layer_id ); |
||
1013 | } |
||
1014 | werner | 1014 | mRulerColors->setCaption(const_cast<LayeredGridBase*>(object.layered)->names()[object.layer_id].name, |
1015 | const_cast<LayeredGridBase*>(object.layered)->names()[object.layer_id].description); |
||
647 | werner | 1016 | break; |
1017 | case PaintObject::PaintNothing: |
||
880 | werner | 1018 | mRulerColors->setCaption("-"); |
647 | werner | 1019 | return; |
1032 | werner | 1020 | default: return; |
647 | werner | 1021 | } |
1041 | werner | 1022 | if (!mRulerColors->autoScale()) { |
1023 | object.cur_max_value = mRulerColors->maxValue(); |
||
1024 | object.cur_min_value = mRulerColors->minValue(); |
||
1025 | } |
||
647 | werner | 1026 | |
1027 | |||
1028 | |||
1029 | painter.setPen(Qt::black); |
||
1030 | painter.drawRect(total_rect); |
||
1031 | |||
1032 | |||
1033 | int ix,iy; |
||
688 | werner | 1034 | double value=0.; |
647 | werner | 1035 | QRect r; |
1036 | QColor fill_color; |
||
880 | werner | 1037 | double max_value = -1.; |
741 | werner | 1038 | QPointF pmetric; |
647 | werner | 1039 | for (iy=0;iy<sy;iy++) { |
1040 | for (ix=0;ix<sx;ix++) { |
||
1041 | QPoint p(ix,iy); |
||
1042 | switch(object.what) { |
||
1043 | case PaintObject::PaintMapGrid: |
||
1044 | value = object.map_grid->grid().constValueAtIndex(p); |
||
741 | werner | 1045 | pmetric = object.map_grid->grid().cellRect(p).center(); |
647 | werner | 1046 | r = vp.toScreen(object.map_grid->grid().cellRect(p)); |
741 | werner | 1047 | |
647 | werner | 1048 | break; |
1049 | case PaintObject::PaintFloatGrid: |
||
1050 | value = object.float_grid->constValueAtIndex(p); |
||
741 | werner | 1051 | pmetric = object.float_grid->cellRect(p).center(); |
647 | werner | 1052 | r = vp.toScreen(object.float_grid->cellRect(p)); |
1053 | break; |
||
1054 | case PaintObject::PaintLayers: |
||
1055 | value = object.layered->value(ix, iy, object.layer_id); |
||
741 | werner | 1056 | pmetric = object.layered->cellRect(p).center(); |
880 | werner | 1057 | max_value = qMax(max_value, value); |
647 | werner | 1058 | r = vp.toScreen(object.layered->cellRect(p)); |
1059 | break; |
||
1060 | default: ; |
||
1061 | } |
||
741 | werner | 1062 | if (clip_with_stand_grid && !GlobalSettings::instance()->model()->heightGrid()->valueAt(pmetric).isValid()) { |
1063 | fill_color = Qt::white; |
||
1064 | } else { |
||
877 | werner | 1065 | fill_color = Colors::colorFromValue(value, object.view_type, object.cur_min_value, object.cur_max_value); |
1009 | werner | 1066 | if (shading) |
1067 | fill_color = Colors::shadeColor(fill_color, pmetric, mRemoteControl.model()->dem()); |
||
741 | werner | 1068 | } |
647 | werner | 1069 | painter.fillRect(r, fill_color); |
1070 | } |
||
1071 | } |
||
880 | werner | 1072 | // update ruler |
1073 | if (object.view_type>=10) { |
||
1074 | QStringList labels; |
||
1075 | for (int i=0;i<max_value;++i) |
||
1076 | labels.append(object.layered->labelvalue(i,object.layer_id)); |
||
1077 | mRulerColors->setFactorLabels(labels); |
||
1078 | } |
||
1079 | mRulerColors->setPalette(object.view_type, object.cur_min_value, object.cur_max_value); // ruler |
||
647 | werner | 1080 | |
1081 | } |
||
1082 | |||
596 | werner | 1083 | // paint the values of the MapGrid |
643 | werner | 1084 | void MainWindow::paintMapGrid(QPainter &painter, |
1085 | MapGrid *map_grid, const FloatGrid *float_grid, |
||
1086 | const GridViewType view_type, |
||
1087 | double min_val, double max_val) |
||
596 | werner | 1088 | { |
1089 | // clear background |
||
1090 | painter.fillRect(ui->PaintWidget->rect(), Qt::white); |
||
642 | werner | 1091 | const Grid<int> *int_grid = 0; |
20 | Werner | 1092 | |
642 | werner | 1093 | int sx, sy; |
1094 | QRect total_rect; |
||
596 | werner | 1095 | |
642 | werner | 1096 | if (map_grid) { |
1097 | int_grid = &map_grid->grid(); |
||
1098 | sx = int_grid->sizeX(); |
||
1099 | sy = int_grid->sizeY(); |
||
1100 | total_rect = vp.toScreen(int_grid->metricRect()); |
||
1101 | } else { |
||
1102 | if (!float_grid) |
||
1103 | return; |
||
1104 | sx = float_grid->sizeX(); |
||
1105 | sy = float_grid->sizeY(); |
||
1106 | total_rect = vp.toScreen(float_grid->metricRect()); |
||
1107 | } |
||
1108 | |||
596 | werner | 1109 | // draw rectangle around the grid |
1110 | painter.setPen(Qt::black); |
||
642 | werner | 1111 | painter.drawRect(total_rect); |
596 | werner | 1112 | // paint the lower-res-grid; |
1113 | int ix,iy; |
||
642 | werner | 1114 | double value; |
1115 | QRect r; |
||
596 | werner | 1116 | QColor fill_color; |
881 | werner | 1117 | |
880 | werner | 1118 | if (view_type<10) |
1119 | mRulerColors->setPalette(view_type,min_val, max_val); // ruler |
||
1120 | else |
||
1121 | mRulerColors->setPalette(view_type, 0, max_val); // ruler |
||
1122 | |||
643 | werner | 1123 | bool reverse = view_type == GridViewRainbowReverse || view_type == GridViewGrayReverse; |
1124 | bool black_white = view_type == GridViewGray || view_type == GridViewGrayReverse; |
||
642 | werner | 1125 | for (iy=0;iy<sy;iy++) { |
1126 | for (ix=0;ix<sx;ix++) { |
||
596 | werner | 1127 | QPoint p(ix,iy); |
642 | werner | 1128 | if (int_grid){ |
1129 | value = int_grid->constValueAtIndex(p); |
||
1130 | r = vp.toScreen(int_grid->cellRect(p)); |
||
1131 | } else { |
||
1132 | value = float_grid->constValueAtIndex(p); |
||
1133 | r = vp.toScreen(float_grid->cellRect(p)); |
||
1134 | } |
||
877 | werner | 1135 | fill_color = view_type<10? Colors::colorFromValue(value, min_val, max_val, reverse,black_white) : Colors::colorFromPalette(value, view_type); |
596 | werner | 1136 | painter.fillRect(r, fill_color); |
1137 | } |
||
1138 | } |
||
1139 | |||
1140 | } |
||
1141 | |||
20 | Werner | 1142 | void MainWindow::repaintArea(QPainter &painter) |
1143 | { |
||
129 | Werner | 1144 | paintFON(painter, ui->PaintWidget->rect()); |
49 | Werner | 1145 | // fix viewpoint |
1146 | vp.setScreenRect(ui->PaintWidget->rect()); |
||
880 | werner | 1147 | mRulerColors->setScale(vp.pixelToMeter(1)); |
20 | Werner | 1148 | } |
1149 | |||
129 | Werner | 1150 | |
48 | Werner | 1151 | void MainWindow::on_visFon_toggled() { ui->PaintWidget->update(); } |
1152 | void MainWindow::on_visDomGrid_toggled() { on_visFon_toggled(); } |
||
1153 | void MainWindow::on_visImpact_toggled() { on_visFon_toggled(); } |
||
40 | Werner | 1154 | bool wantDrag=false; |
6 | Werner | 1155 | void MainWindow::mouseClick(const QPoint& pos) |
1156 | { |
||
916 | werner | 1157 | if (!mRemoteControl.canRun()) |
1158 | return; |
||
1159 | |||
58 | Werner | 1160 | QPointF coord=vp.toWorld(pos); |
275 | werner | 1161 | //qDebug() << "to world:" << coord; |
40 | Werner | 1162 | wantDrag = false; |
1163 | ui->PaintWidget->setCursor(Qt::CrossCursor); |
||
293 | werner | 1164 | Model *model = mRemoteControl.model(); |
1165 | ResourceUnit *ru = model->ru(coord); |
||
40 | Werner | 1166 | // find adjactent tree |
128 | Werner | 1167 | |
896 | werner | 1168 | // test ressource units... |
293 | werner | 1169 | if (ui->visResourceUnits->isChecked()) { |
1170 | if (!ru) return; |
||
1171 | showResourceUnitDetails(ru); |
||
1172 | return; |
||
1173 | } |
||
1174 | |||
896 | werner | 1175 | // test for ABE grid |
1176 | if (ui->visOtherGrid->isChecked()) { |
||
1177 | if (showABEDetails(coord)) |
||
1178 | return; |
||
1179 | } |
||
275 | werner | 1180 | //qDebug() << "coord:" << coord << "RU:"<< ru << "ru-rect:" << ru->boundingBox(); |
1157 | werner | 1181 | if (!ru) |
1182 | return; |
||
1183 | |||
293 | werner | 1184 | ui->treeChange->setProperty("tree",0); |
114 | Werner | 1185 | QVector<Tree> &mTrees = ru->trees(); |
105 | Werner | 1186 | QVector<Tree>::iterator tit; |
155 | werner | 1187 | Tree *closestTree=0; |
1188 | double min_distance = 100000000, current_dist; |
||
15 | Werner | 1189 | for (tit=mTrees.begin(); tit!=mTrees.end(); ++tit) { |
155 | werner | 1190 | current_dist = distance(tit->position(),coord); |
1191 | if (current_dist<min_distance) { |
||
1192 | closestTree = &(*tit); |
||
1193 | min_distance = current_dist; |
||
1194 | } |
||
1195 | } |
||
1196 | if (min_distance<5 && closestTree) { |
||
1197 | Tree *p = closestTree; |
||
275 | werner | 1198 | //qDebug() << "found!" << tit->id() << "at" << tit->position()<<"value"<<p->lightResourceIndex(); |
1199 | //qDebug() <<p->dump(); |
||
149 | werner | 1200 | showTreeDetails(p); |
1201 | |||
1035 | werner | 1202 | ui->treeChange->setProperty("tree", qVariantFromValue((void*)p)); |
40 | Werner | 1203 | ui->treeDbh->setValue(p->dbh()); |
1204 | ui->treeHeight->setValue(p->height()); |
||
49 | Werner | 1205 | ui->treePosX->setValue(p->position().x()); |
1206 | ui->treePosY->setValue(p->position().y()); |
||
187 | iland | 1207 | ui->treeImpact->setText(QString("#:%1 - %2").arg(p->id()).arg(p->lightResourceIndex(),5)); |
40 | Werner | 1208 | wantDrag=true; |
1209 | ui->PaintWidget->setCursor(Qt::SizeAllCursor); |
||
1210 | ui->PaintWidget->update(); |
||
155 | werner | 1211 | } |
1212 | |||
6 | Werner | 1213 | } |
3 | Werner | 1214 | |
293 | werner | 1215 | void MainWindow::showResourceUnitDetails(const ResourceUnit *ru) |
1216 | { |
||
1217 | ui->dataTree->clear(); |
||
1218 | RUWrapper ruw; |
||
1219 | ruw.setResourceUnit(ru); |
||
1220 | const QStringList &names = ruw.getVariablesList(); |
||
1221 | QList<QTreeWidgetItem *> items; |
||
1222 | foreach(QString name, names) { |
||
1223 | items.append(new QTreeWidgetItem(QStringList()<<name<<QString::number(ruw.valueByName(name)) )); |
||
1224 | } |
||
1078 | werner | 1225 | // add special values (strings) |
1226 | if (ru->climate()) |
||
1227 | items.append(new QTreeWidgetItem(QStringList()<<"climate"<<ru->climate()->name() )); |
||
1228 | |||
528 | werner | 1229 | QList<QPair<QString, QVariant> > dbgdata = GlobalSettings::instance()->debugValues(-ru->index()); // hack: use negative values for resource units |
1230 | |||
1231 | QList<QPair<QString, QVariant> >::const_iterator i = dbgdata.constBegin(); |
||
1232 | while (i != dbgdata.constEnd()) { |
||
1233 | //cout << i.key() << ": " << i.value() << endl; |
||
1234 | items.append(new QTreeWidgetItem(QStringList() |
||
1235 | << (*i).first |
||
1236 | << (*i).second.toString()) ); |
||
1237 | ++i; |
||
1238 | } |
||
293 | werner | 1239 | ui->dataTree->addTopLevelItems(items); |
1240 | } |
||
1241 | |||
896 | werner | 1242 | bool MainWindow::showABEDetails(const QPointF &coord) |
1243 | { |
||
897 | werner | 1244 | if (!mRemoteControl.canRun()) return false; |
962 | werner | 1245 | if (mPaintNext.layered) { |
1246 | if (mPaintNext.layered->onClick(coord)) |
||
1247 | return true; |
||
1248 | } |
||
909 | werner | 1249 | if (!mPaintNext.layered || !mRemoteControl.model()->ABEngine()) return false; |
899 | werner | 1250 | QString grid_name = mPaintNext.name; |
909 | werner | 1251 | QStringList list = mRemoteControl.model()->ABEngine()->evaluateClick(coord, grid_name); |
716 | werner | 1252 | |
896 | werner | 1253 | ui->dataTree->clear(); |
1254 | QList<QTreeWidgetItem *> items; |
||
1255 | QStack<QTreeWidgetItem*> stack; |
||
1256 | stack.push(0); |
||
1257 | foreach (QString s, list) { |
||
1258 | QStringList elem = s.split(":"); |
||
1259 | if (s=="-") |
||
1260 | stack.push(items.back()); |
||
1261 | else if (s=="/-") |
||
1262 | stack.pop(); |
||
1263 | else { |
||
1264 | items.append( new QTreeWidgetItem(stack.last(), elem) ); |
||
1265 | } |
||
1266 | } |
||
1267 | ui->dataTree->addTopLevelItems(items); |
||
1268 | return true; // handled |
||
1269 | |||
1270 | |||
1271 | |||
1272 | } |
||
1273 | |||
1274 | |||
149 | werner | 1275 | void MainWindow::showTreeDetails(Tree *tree) |
1276 | { |
||
1277 | ui->dataTree->clear(); |
||
1278 | TreeWrapper tw; |
||
1279 | tw.setTree(tree); |
||
1280 | const QStringList &names = tw.getVariablesList(); |
||
1281 | QList<QTreeWidgetItem *> items; |
||
1282 | foreach(QString name, names) { |
||
818 | werner | 1283 | if (name=="species") |
1284 | items.append(new QTreeWidgetItem(QStringList() << name << mRemoteControl.model()->speciesSet()->species(tw.valueByName(name))->id() )); |
||
1285 | else |
||
1286 | items.append(new QTreeWidgetItem(QStringList() << name << QString::number(tw.valueByName(name)) )); |
||
149 | werner | 1287 | } |
160 | werner | 1288 | QList<QPair<QString, QVariant> > dbgdata = GlobalSettings::instance()->debugValues(tree->id()); |
153 | werner | 1289 | |
160 | werner | 1290 | QList<QPair<QString, QVariant> >::const_iterator i = dbgdata.constBegin(); |
1291 | while (i != dbgdata.constEnd()) { |
||
1292 | //cout << i.key() << ": " << i.value() << endl; |
||
1293 | items.append(new QTreeWidgetItem(QStringList() |
||
1294 | << (*i).first |
||
1295 | << (*i).second.toString()) ); |
||
1296 | ++i; |
||
1297 | } |
||
149 | werner | 1298 | ui->dataTree->addTopLevelItems(items); |
1299 | } |
||
1300 | |||
49 | Werner | 1301 | void MainWindow::mouseMove(const QPoint& pos) |
1302 | { |
||
127 | Werner | 1303 | |
1071 | werner | 1304 | if (!mRemoteControl.canRun() ) |
49 | Werner | 1305 | return; |
128 | Werner | 1306 | FloatGrid *grid = mRemoteControl.model()->grid(); |
49 | Werner | 1307 | QPointF p = vp.toWorld(pos); |
648 | werner | 1308 | bool has_value = true; |
1309 | double value; |
||
127 | Werner | 1310 | if (grid->coordValid(p)) { |
291 | werner | 1311 | QString location=QString("%1 / %2").arg(p.x()).arg(p.y()); |
732 | werner | 1312 | if (ui->visOtherGrid->isChecked()) { |
1313 | switch (mPaintNext.what) { |
||
1314 | case PaintObject::PaintFloatGrid: |
||
758 | werner | 1315 | value = mPaintNext.float_grid->isEmpty()?0: mPaintNext.float_grid->constValueAt(p); |
732 | werner | 1316 | break; |
1317 | case PaintObject::PaintMapGrid: |
||
1318 | value = mPaintNext.map_grid->grid().constValueAt(p); |
||
1319 | break; |
||
1320 | case PaintObject::PaintLayers: |
||
1321 | value = mPaintNext.layered->value(p, mPaintNext.layer_id); |
||
877 | werner | 1322 | if (mPaintNext.view_type>=10) {// classes |
1323 | location += QString("\n %1").arg(mPaintNext.layered->labelvalue(value, mPaintNext.layer_id)); |
||
1324 | ui->fonValue->setText(location); |
||
1325 | return; |
||
1326 | } |
||
1327 | |||
732 | werner | 1328 | break; |
1329 | default: has_value = false; |
||
1330 | } |
||
1331 | if (has_value) { |
||
1332 | location += QString("\n %1").arg(value); |
||
1333 | ui->fonValue->setText(location); |
||
1334 | return; |
||
1335 | } |
||
648 | werner | 1336 | } |
291 | werner | 1337 | |
642 | werner | 1338 | if (ui->visFon->isChecked() || ui->visImpact->isChecked()) { |
1339 | if (mPaintNext.what == PaintObject::PaintFloatGrid && mPaintNext.float_grid) |
||
1340 | location += QString("\n %1").arg(mPaintNext.float_grid->constValueAt(p)); |
||
1341 | else |
||
1342 | location += QString("\n %1").arg((*grid).valueAt(p)); |
||
1343 | } |
||
58 | Werner | 1344 | if( ui->visDomGrid->isChecked()) |
291 | werner | 1345 | location += QString("\n %1").arg((*mRemoteControl.model()->heightGrid()).valueAt(p).height); |
822 | werner | 1346 | if( ui->visRegeneration->isChecked() && !mRegenerationGrid.isEmpty()) |
453 | werner | 1347 | location += QString("\n %1").arg(mRegenerationGrid.valueAt(p)); |
1179 | werner | 1348 | if (ui->visSeeds->isChecked() && ui->speciesFilterBox->currentIndex()>-1) { |
1349 | Species *s=GlobalSettings::instance()->model()->speciesSet()->species(ui->speciesFilterBox->itemData(ui->speciesFilterBox->currentIndex()).toString()); |
||
1350 | if (s && s->seedDispersal()) |
||
1351 | location += QString("\n %1").arg(s->seedDispersal()->seedMap().constValueAt(p)); |
||
1352 | } |
||
291 | werner | 1353 | |
1354 | ui->fonValue->setText(location); |
||
51 | Werner | 1355 | } |
49 | Werner | 1356 | } |
3 | Werner | 1357 | |
113 | Werner | 1358 | void MainWindow::mouseWheel(const QPoint& pos, int steps) |
40 | Werner | 1359 | { |
274 | werner | 1360 | //qDebug() << "mouse-wheel" << steps; |
113 | Werner | 1361 | vp.zoomTo(pos, qMax(1-(2*steps/10.),0.2)); |
1362 | ui->PaintWidget->update(); |
||
1363 | } |
||
1364 | |||
1365 | void MainWindow::mouseDrag(const QPoint& from, const QPoint &to, Qt::MouseButton button) |
||
1366 | { |
||
1367 | qDebug() << "drag" << button; |
||
40 | Werner | 1368 | ui->PaintWidget->setCursor(Qt::CrossCursor); |
517 | werner | 1369 | // move view area if not dedicately moving around a tree |
1370 | if (!wantDrag) { |
||
113 | Werner | 1371 | vp.moveTo(from, to); |
1372 | ui->PaintWidget->update(); |
||
1373 | return; |
||
1374 | } |
||
517 | werner | 1375 | wantDrag = false; |
40 | Werner | 1376 | qDebug() << "drag from" << from << "to" << to; |
1157 | werner | 1377 | Tree *t = reinterpret_cast<Tree*>( ui->treeChange->property("tree").toLongLong() ); |
40 | Werner | 1378 | if (!t) |
1379 | return; |
||
58 | Werner | 1380 | QPointF pos = vp.toWorld(to); |
40 | Werner | 1381 | // calculate new position... |
1382 | t->setPosition(pos); |
||
127 | Werner | 1383 | readwriteCycle(); |
403 | werner | 1384 | ui->PaintWidget->update(); |
40 | Werner | 1385 | } |
3 | Werner | 1386 | |
1387 | |||
1388 | |||
19 | Werner | 1389 | void MainWindow::on_actionEdit_XML_settings_triggered() |
1390 | { |
||
1391 | ui->editStack->setCurrentIndex(0); |
||
20 | Werner | 1392 | ui->PaintWidget->update(); |
19 | Werner | 1393 | } |
1394 | |||
776 | werner | 1395 | QMutex mutex_yearSimulated; |
222 | werner | 1396 | void MainWindow::yearSimulated(int year) |
1397 | { |
||
776 | werner | 1398 | QMutexLocker mutex_locker(&mutex_yearSimulated); |
1399 | checkModelState(); |
||
1400 | ui->modelRunProgress->setValue(year); |
||
1401 | labelMessage(QString("Running.... year %1 of %2.").arg(year).arg(mRemoteControl.totalYears())); |
||
948 | werner | 1402 | ui->treeChange->setProperty("tree",0); |
776 | werner | 1403 | ui->PaintWidget->update(); |
1404 | QApplication::processEvents(); |
||
222 | werner | 1405 | } |
19 | Werner | 1406 | |
222 | werner | 1407 | void MainWindow::modelFinished(QString errorMessage) |
1408 | { |
||
921 | werner | 1409 | if (!errorMessage.isEmpty()) { |
1410 | Helper::msg(errorMessage); |
||
1411 | labelMessage("Error!"); |
||
1412 | qDebug() << "Error:" << errorMessage; |
||
1413 | } else { |
||
1414 | qDebug() << "Finished!"; |
||
1415 | labelMessage("Finished!!"); |
||
1416 | } |
||
493 | werner | 1417 | |
225 | werner | 1418 | checkModelState(); |
661 | werner | 1419 | if (windowTitle().contains("batch")) { |
1420 | // we are in automatic batch mode. |
||
1421 | // we should therefore close down the application. |
||
921 | werner | 1422 | if (!errorMessage.isEmpty()) |
1423 | batchLog(QString("error: %1").arg(errorMessage)); |
||
661 | werner | 1424 | batchLog(QString("%1 Finished!!! shutting down...").arg(QDateTime::currentDateTime().toString(Qt::ISODate))); |
1425 | |||
1426 | qDebug() << "****************************"; |
||
767 | werner | 1427 | qDebug() << "Finished automated model run: " << errorMessage; |
661 | werner | 1428 | qDebug() << "****************************"; |
1429 | |||
1430 | close(); // shut down the application.... |
||
1431 | |||
1432 | } |
||
222 | werner | 1433 | } |
19 | Werner | 1434 | |
344 | werner | 1435 | /// creates the iLand model |
104 | Werner | 1436 | void MainWindow::setupModel() |
1437 | { |
||
1058 | werner | 1438 | //recent file menu |
1439 | recentFileMenu(); |
||
1440 | |||
129 | Werner | 1441 | // load project xml file to global xml settings structure |
189 | iland | 1442 | mRemoteControl.setFileName(ui->initFileName->text()); |
1443 | //GlobalSettings::instance()->loadProjectFile(ui->initFileName->text()); |
||
493 | werner | 1444 | labelMessage("Creating model..."); |
359 | werner | 1445 | |
1446 | // setup logging |
||
360 | werner | 1447 | setupFileLogging(true); |
359 | werner | 1448 | |
129 | Werner | 1449 | // create the model |
1450 | mRemoteControl.create(); |
||
575 | werner | 1451 | if (!mRemoteControl.canRun()) |
1452 | return; |
||
1453 | |||
129 | Werner | 1454 | Model *model = mRemoteControl.model(); |
189 | iland | 1455 | if (model && model->isSetup()) { |
105 | Werner | 1456 | // set viewport of paintwidget |
129 | Werner | 1457 | vp = Viewport(model->grid()->metricRect(), ui->PaintWidget->rect()); |
135 | Werner | 1458 | ui->PaintWidget->update(); |
129 | Werner | 1459 | } |
776 | werner | 1460 | ui->treeChange->setProperty("tree",0); |
802 | werner | 1461 | |
776 | werner | 1462 | // setup dynamic output |
1463 | QString dout = GlobalSettings::instance()->settings().value("output.dynamic.columns"); |
||
802 | werner | 1464 | mRemoteControl.setupDynamicOutput(dout); |
1465 | mRemoteControl.setDynamicOutputEnabled(GlobalSettings::instance()->settings().valueBool("output.dynamic.enabled",false)); |
||
1466 | |||
776 | werner | 1467 | ui->modelRunProgress->setValue(0); |
1468 | QSettings().setValue("project/lastxmlfile", ui->initFileName->text()); |
||
1469 | // magic debug output number |
||
1470 | GlobalSettings::instance()->setDebugOutput((int) GlobalSettings::instance()->settings().valueDouble("system.settings.debugOutput")); |
||
514 | werner | 1471 | |
776 | werner | 1472 | // populate the tree species filter list |
1473 | ui->speciesFilterBox->clear(); |
||
1474 | ui->speciesFilterBox->addItem("<all species>", ""); |
||
1066 | werner | 1475 | QList<const Species*> list = mRemoteControl.availableSpecies(); |
1476 | for (int i=0;i<list.size();++i) |
||
1477 | ui->speciesFilterBox->addItem(list[i]->name(), list[i]->id()); |
||
514 | werner | 1478 | |
776 | werner | 1479 | // retrieve the active management script file |
1480 | if (mRemoteControl.model()->management()) |
||
1064 | werner | 1481 | ui->scriptActiveScriptFile->setText(QString("%1").arg(mRemoteControl.model()->management()->scriptFile())); |
1482 | if (!mRemoteControl.loadedJavascriptFile().isEmpty()) |
||
1483 | ui->scriptActiveScriptFile->setText(QString("%1").arg(mRemoteControl.loadedJavascriptFile())); |
||
776 | werner | 1484 | labelMessage("Model created. Ready to run."); |
1485 | checkModelState(); |
||
1043 | valentin | 1486 | |
104 | Werner | 1487 | } |
1488 | |||
28 | Werner | 1489 | |
39 | Werner | 1490 | |
58 | Werner | 1491 | void MainWindow::on_pbSetAsDebug_clicked() |
1492 | { |
||
1157 | werner | 1493 | Tree *t = reinterpret_cast<Tree *>( ui->treeChange->property("tree").toLongLong() ); |
1494 | if (!t) |
||
58 | Werner | 1495 | return; |
1496 | t->enableDebugging(); |
||
1497 | |||
1498 | } |
||
65 | Werner | 1499 | |
1500 | void MainWindow::on_openFile_clicked() |
||
1501 | { |
||
1053 | werner | 1502 | QString fileName = Helper::fileDialog("select XML-project file", ui->initFileName->text(), "*.xml",this); |
65 | Werner | 1503 | if (fileName.isEmpty()) |
1504 | return; |
||
1505 | ui->initFileName->setText(fileName); |
||
1506 | QString xmlFile = Helper::loadTextFile(ui->initFileName->text()); |
||
1507 | ui->iniEdit->setPlainText(xmlFile); |
||
776 | werner | 1508 | checkModelState(); |
65 | Werner | 1509 | } |
67 | Werner | 1510 | |
1511 | void MainWindow::on_actionTreelist_triggered() |
||
1512 | { |
||
1513 | QApplication::clipboard()->setText(dumpTreelist()); |
||
1514 | qDebug() << "treelist copied to clipboard."; |
||
1515 | } |
||
1516 | |||
1517 | void MainWindow::on_actionFON_grid_triggered() |
||
1518 | { |
||
356 | werner | 1519 | //if (!mRemoteControl.isRunning()) return; |
128 | Werner | 1520 | QString gr = gridToString(*mRemoteControl.model()->grid()); |
67 | Werner | 1521 | QApplication::clipboard()->setText(gr); |
1522 | qDebug() << "grid copied to clipboard."; |
||
1523 | } |
||
69 | Werner | 1524 | |
106 | Werner | 1525 | |
129 | Werner | 1526 | void MainWindow::on_actionModelCreate_triggered() |
1527 | { |
||
1528 | // create model |
||
1529 | setupModel(); |
||
1530 | checkModelState(); |
||
1531 | } |
||
1532 | |||
1533 | void MainWindow::on_actionModelDestroy_triggered() |
||
1534 | { |
||
1065 | werner | 1535 | mPaintNext.what = PaintObject::PaintNothing; |
129 | Werner | 1536 | mRemoteControl.destroy(); |
1157 | werner | 1537 | mRegenerationGrid.clear(); |
129 | Werner | 1538 | checkModelState(); |
1539 | } |
||
1540 | |||
1541 | void MainWindow::on_actionModelRun_triggered() |
||
1542 | { |
||
1543 | if (!mRemoteControl.canRun()) |
||
1544 | return; |
||
497 | werner | 1545 | QString msg = QString("How many years to run?\nCurrent year: %1.").arg(mRemoteControl.currentYear()); |
322 | werner | 1546 | bool ok; |
138 | Werner | 1547 | int count = QInputDialog::getInt(this, "input value", |
798 | werner | 1548 | msg, 10, 0, 10000, 1, &ok); |
322 | werner | 1549 | if (!ok) |
1550 | return; |
||
497 | werner | 1551 | count = count + mRemoteControl.currentYear(); |
948 | werner | 1552 | ui->treeChange->setProperty("tree",0); |
219 | werner | 1553 | ui->modelRunProgress->setMaximum(count-1); |
222 | werner | 1554 | mRemoteControl.run(count); |
1180 | werner | 1555 | GlobalSettings::instance()->executeJSFunction("onAfterRun"); |
222 | werner | 1556 | |
138 | Werner | 1557 | } |
1558 | |||
1559 | void MainWindow::on_actionRun_one_year_triggered() |
||
1560 | { |
||
1561 | if (!mRemoteControl.canRun()) |
||
1562 | return; |
||
948 | werner | 1563 | ui->treeChange->setProperty("tree",0); |
129 | Werner | 1564 | mRemoteControl.runYear(); |
229 | werner | 1565 | GlobalSettings::instance()->outputManager()->save(); // save output tables when stepping single year by year |
498 | werner | 1566 | labelMessage(QString("Simulated a single year. year %1.").arg(mRemoteControl.currentYear())); |
1567 | |||
776 | werner | 1568 | ui->PaintWidget->update(); |
129 | Werner | 1569 | checkModelState(); |
1570 | } |
||
1571 | |||
138 | Werner | 1572 | void MainWindow::on_actionReload_triggered() |
1573 | { |
||
1574 | if (!mRemoteControl.canDestroy()) |
||
1575 | return; |
||
1065 | werner | 1576 | mPaintNext.what = PaintObject::PaintNothing; |
138 | Werner | 1577 | mRemoteControl.destroy(); |
1157 | werner | 1578 | mRegenerationGrid.clear(); |
138 | Werner | 1579 | setupModel(); |
1580 | } |
||
129 | Werner | 1581 | |
225 | werner | 1582 | void MainWindow::on_actionPause_triggered() |
1583 | { |
||
1584 | mRemoteControl.pause(); |
||
493 | werner | 1585 | if (!mRemoteControl.isRunning()) |
1586 | labelMessage("Model execution paused..."); |
||
776 | werner | 1587 | |
1588 | checkModelState(); |
||
1589 | |||
1590 | if (!mRemoteControl.isPaused()) |
||
1591 | mRemoteControl.continueRun(); |
||
225 | werner | 1592 | } |
1593 | |||
1594 | void MainWindow::on_actionStop_triggered() |
||
1595 | { |
||
1596 | mRemoteControl.cancel(); |
||
493 | werner | 1597 | labelMessage("Model stopped."); |
225 | werner | 1598 | } |
1599 | |||
129 | Werner | 1600 | void MainWindow::on_actionTree_Partition_triggered() |
1601 | { |
||
130 | Werner | 1602 | QStringList result = GlobalSettings::instance()->debugDataTable(GlobalSettings::dTreePartition, ";"); |
129 | Werner | 1603 | QApplication::clipboard()->setText(result.join("\n")); |
1604 | qDebug() << "copied" << result.count() << "lines of debug data to clipboard."; |
||
1605 | } |
||
1606 | |||
1168 | werner | 1607 | void MainWindow::on_action_debugSapling_triggered() |
1608 | { |
||
1609 | QStringList result = GlobalSettings::instance()->debugDataTable(GlobalSettings::dSaplingGrowth, ";"); |
||
1610 | QApplication::clipboard()->setText(result.join("\n")); |
||
1611 | qDebug() << "copied" << result.count() << "lines of debug data to clipboard."; |
||
1612 | |||
1613 | } |
||
1614 | |||
129 | Werner | 1615 | void MainWindow::on_actionTree_Growth_triggered() |
1616 | { |
||
130 | Werner | 1617 | QStringList result = GlobalSettings::instance()->debugDataTable(GlobalSettings::dTreeGrowth, ";"); |
129 | Werner | 1618 | QApplication::clipboard()->setText(result.join("\n")); |
1619 | qDebug() << "copied" << result.count() << "lines of debug data to clipboard."; |
||
1620 | } |
||
1621 | |||
133 | Werner | 1622 | void MainWindow::on_actionTree_NPP_triggered() |
1623 | { |
||
1624 | QStringList result = GlobalSettings::instance()->debugDataTable(GlobalSettings::dTreeNPP, ";"); |
||
1625 | QApplication::clipboard()->setText(result.join("\n")); |
||
1626 | qDebug() << "copied" << result.count() << "lines of debug data to clipboard."; |
||
1627 | } |
||
1628 | |||
239 | werner | 1629 | void MainWindow::on_actionWater_Output_triggered() |
1630 | { |
||
1631 | QStringList result = GlobalSettings::instance()->debugDataTable(GlobalSettings::dWaterCycle, ";"); |
||
1632 | QApplication::clipboard()->setText(result.join("\n")); |
||
1633 | qDebug() << "copied" << result.count() << "lines of debug data to clipboard."; |
||
1634 | } |
||
329 | werner | 1635 | void MainWindow::on_actionDaily_responses_Output_triggered() |
1636 | { |
||
1637 | QStringList result = GlobalSettings::instance()->debugDataTable(GlobalSettings::dDailyResponses, ";"); |
||
1638 | QApplication::clipboard()->setText(result.join("\n")); |
||
1639 | qDebug() << "copied" << result.count() << "lines of debug data to clipboard."; |
||
344 | werner | 1640 | } |
138 | Werner | 1641 | |
442 | werner | 1642 | void MainWindow::on_action_debugEstablishment_triggered() |
1643 | { |
||
1644 | QStringList result = GlobalSettings::instance()->debugDataTable(GlobalSettings::dEstablishment, ";"); |
||
1645 | QApplication::clipboard()->setText(result.join("\n")); |
||
1646 | qDebug() << "copied" << result.count() << "lines of debug data to clipboard."; |
||
1647 | } |
||
1648 | |||
477 | werner | 1649 | void MainWindow::on_actionSnag_Dynamics_triggered() |
1650 | { |
||
526 | werner | 1651 | QStringList result = GlobalSettings::instance()->debugDataTable(GlobalSettings::dCarbonCycle, ";"); |
477 | werner | 1652 | QApplication::clipboard()->setText(result.join("\n")); |
1653 | qDebug() << "copied" << result.count() << "lines of debug data to clipboard."; |
||
442 | werner | 1654 | |
477 | werner | 1655 | } |
1656 | |||
615 | werner | 1657 | void MainWindow::on_actionPerformance_triggered() |
1658 | { |
||
1659 | QStringList result = GlobalSettings::instance()->debugDataTable(GlobalSettings::dPerformance, ";"); |
||
1660 | QApplication::clipboard()->setText(result.join("\n")); |
||
1661 | qDebug() << "copied" << result.count() << "lines of debug data to clipboard."; |
||
573 | werner | 1662 | |
615 | werner | 1663 | } |
1664 | |||
590 | werner | 1665 | QImage MainWindow::screenshot() |
1666 | { |
||
1667 | return ui->PaintWidget->drawImage(); |
||
1668 | } |
||
1669 | |||
634 | werner | 1670 | /// set the viewport of the main viewing window |
1671 | /// @p center_point is the point to zoom to (world coordinates), and @p scael_px_per_m is the |
||
1672 | /// pixel/m scaling. |
||
1673 | void MainWindow::setViewport(QPointF center_point, double scale_px_per_m) |
||
1674 | { |
||
1180 | werner | 1675 | if (scale_px_per_m>0.) |
1676 | vp.setViewPoint(center_point, scale_px_per_m); |
||
1677 | else |
||
1678 | vp.zoomToAll(); |
||
634 | werner | 1679 | |
644 | werner | 1680 | // double current_px = vp.pixelToMeter(1); // number of meters covered by one pixel |
1681 | // if (current_px==0) |
||
1682 | // return; |
||
1683 | |||
1684 | // vp.setCenterPoint(center_point); |
||
1685 | // QPoint screen = vp.toScreen(center_point); // screen coordinates of the target point |
||
1686 | // double target_scale = scale_px_per_m / current_px; |
||
1687 | |||
1688 | // vp.zoomTo(screen, target_scale); |
||
634 | werner | 1689 | ui->PaintWidget->update(); |
1690 | QCoreApplication::processEvents(); |
||
1691 | } |
||
1692 | |||
1061 | werner | 1693 | void MainWindow::setUIshortcuts(QVariantMap shortcuts) |
1694 | { |
||
1695 | if (shortcuts.isEmpty()) { |
||
1696 | ui->lJSShortcuts->setText("(no shortcuts defined)"); |
||
1697 | return; |
||
1698 | } |
||
1699 | QString msg = "<html><head/><body><p>Javascript shortcuts<br>"; |
||
1700 | QVariantMap::const_iterator i; |
||
1701 | for (i = shortcuts.constBegin(); i != shortcuts.constEnd(); ++i) { |
||
1702 | QString line = QString("<a href =\"%1\"><span style=\" text-decoration: underline; color:#0000ff;\">%1</span></a>: %2<br>").arg(i.key(), i.value().toString()); |
||
1703 | msg += line; |
||
1704 | } |
||
1705 | msg += "</body></html>"; |
||
1706 | //qDebug() << msg; |
||
1707 | |||
1708 | ui->lJSShortcuts->setText(msg); |
||
1709 | ui->lJSShortcuts->setTextInteractionFlags(Qt::TextBrowserInteraction); |
||
1710 | } |
||
1711 | |||
716 | werner | 1712 | void MainWindow::closeEvent(QCloseEvent *event) |
1713 | { |
||
1714 | writeSettings(); |
||
1715 | event->accept(); |
||
1716 | } |
||
1717 | |||
573 | werner | 1718 | void MainWindow::on_actionImageToClipboard_triggered() |
1719 | { |
||
1061 | werner | 1720 | //QClipboard *clipboard = QApplication::clipboard(); |
1054 | werner | 1721 | QImage my_img = screenshot(); |
1722 | my_img.convertToFormat(QImage::Format_RGB32); |
||
1723 | //clipboard->setImage( my_img, QClipboard::Clipboard ); |
||
1724 | QString pth = GlobalSettings::instance()->path("screenshot.png", "temp"); |
||
1725 | screenshot().save(pth); |
||
1726 | qDebug() << "copied image to clipboard. save also to: " << pth; |
||
1727 | my_img.load(pth); |
||
1728 | QApplication::clipboard()->setImage(my_img); |
||
1729 | |||
573 | werner | 1730 | } |
1731 | |||
344 | werner | 1732 | |
129 | Werner | 1733 | void MainWindow::on_actionSelect_Data_Types_triggered() |
1734 | { |
||
382 | werner | 1735 | int value = GlobalSettings::instance()->currentDebugOutput(); |
129 | Werner | 1736 | int newvalue = QInputDialog::getInt(this, "QInputDialog::getText()", |
1737 | "Enter code for desired outputs: add\n" \ |
||
133 | Werner | 1738 | "1 ... Tree NPP\n" \ |
129 | Werner | 1739 | "2 ... Tree partition\n" \ |
133 | Werner | 1740 | "4 ... Tree growth (dbh,h)\n" \ |
1196 | werner | 1741 | "8 ... Standlevel GPP\n" \ |
239 | werner | 1742 | "16...Water Cycle\n" \ |
442 | werner | 1743 | "32...Daily responses\n" \ |
476 | werner | 1744 | "64...Establishment\n" \ |
1168 | werner | 1745 | "128...Sapling growth\n" \ |
1746 | "256...Carbon cycle\n" \ |
||
1747 | "512...Performance\n" |
||
129 | Werner | 1748 | "(e.g.: 5 = NPP + tree growth) or 0 for no debug outputs.", value); |
1749 | GlobalSettings::instance()->setDebugOutput(newvalue); |
||
1750 | } |
||
133 | Werner | 1751 | |
1752 | |||
138 | Werner | 1753 | |
1754 | |||
142 | Werner | 1755 | // Expression test |
1756 | void MainWindow::on_pbCalculateExpression_clicked() |
||
1757 | { |
||
1758 | QString expr_text=ui->expressionText->text(); |
||
1759 | QString expr_filter=ui->expressionFilter->text(); |
||
143 | Werner | 1760 | if (expr_text == "test") { |
808 | werner | 1761 | on_actionTest_triggered(); |
143 | Werner | 1762 | return; |
1763 | } |
||
142 | Werner | 1764 | if (expr_filter.isEmpty()) |
1765 | expr_filter = "1"; // a constant true expression |
||
1766 | TreeWrapper wrapper; |
||
1767 | Expression expr(expr_text, &wrapper); |
||
1768 | Expression filter(expr_filter, &wrapper); |
||
1769 | AllTreeIterator at(GlobalSettings::instance()->model()); |
||
143 | Werner | 1770 | int totalcount=0; |
1771 | QVector<double> datavector; |
||
142 | Werner | 1772 | try { |
143 | Werner | 1773 | |
142 | Werner | 1774 | while (Tree *tree=at.next()) { |
1775 | wrapper.setTree(tree); |
||
1776 | if (filter.execute()) { |
||
143 | Werner | 1777 | datavector << expr.execute(); |
142 | Werner | 1778 | } |
1779 | totalcount++; |
||
1780 | } |
||
1781 | } catch (IException &e) { |
||
575 | werner | 1782 | Helper::msg(e.message()); |
142 | Werner | 1783 | } |
143 | Werner | 1784 | StatData stats(datavector); |
1785 | qDebug() << "Expression:" << expr_text << "filtered" << datavector.count() << "of" << totalcount; |
||
1786 | qDebug() << "sum:" << stats.sum() << "min" << stats.min() << "max" << stats.max() << "average" << stats.mean(); |
||
1787 | qDebug() << "P25" << stats.percentile25() << "median" << stats.median() << "P75" << stats.percentile75() << "P90" << stats.percentile(90); |
||
1788 | |||
1789 | //qDebug() << "Expression:" << expr_text << "results: count of total: " << count << "/" << totalcount |
||
1790 | // << "sum:" << sum << "average:" << (count>0?sum/double(count):0.) << "minval:" << minval << "maxval:" << maxval; |
||
142 | Werner | 1791 | // add to history |
1792 | if (!ui->expressionHistory->currentItem() || ui->expressionHistory->currentItem()->text() != expr_text) { |
||
1793 | ui->expressionHistory->insertItem(0, expr_text); |
||
1794 | ui->expressionHistory->setCurrentRow(0); |
||
1795 | } |
||
1796 | } |
||
148 | iland | 1797 | |
1798 | void MainWindow::on_pbExecExpression_clicked() |
||
1799 | { |
||
1800 | // just repaint... |
||
1801 | ui->PaintWidget->update(); |
||
1802 | } |
||
161 | werner | 1803 | |
1804 | void MainWindow::on_actionDynamic_Output_triggered() |
||
1805 | { |
||
1806 | QApplication::clipboard()->setText(mRemoteControl.dynamicOutput()); |
||
1807 | qDebug() << "copied dynamic output to clipboard"; |
||
1808 | } |
||
194 | werner | 1809 | |
1810 | void MainWindow::on_actionShow_Debug_Messages_triggered(bool checked) |
||
1811 | { |
||
1812 | // enable/disble debug messages |
||
1813 | showDebugMessages=checked; |
||
1814 | } |
||
216 | werner | 1815 | |
1816 | void MainWindow::on_reloadJavaScript_clicked() |
||
1817 | { |
||
221 | werner | 1818 | if (!GlobalSettings::instance()->model()) |
414 | werner | 1819 | MSGRETURN("no model available."); |
1064 | werner | 1820 | |
1821 | ScriptGlobal::loadScript(ui->scriptActiveScriptFile->text()); |
||
767 | werner | 1822 | ScriptGlobal::scriptOutput = ui->scriptResult; |
414 | werner | 1823 | } |
216 | werner | 1824 | |
414 | werner | 1825 | void MainWindow::on_selectJavaScript_clicked() |
1826 | { |
||
1827 | if (!GlobalSettings::instance()->model()) |
||
1828 | return; |
||
1829 | QString fileName = Helper::fileDialog("select a Javascript file:"); |
||
1830 | if (fileName.isEmpty()) |
||
1831 | return; |
||
767 | werner | 1832 | ScriptGlobal::loadScript(fileName); |
1833 | |||
794 | werner | 1834 | ui->scriptActiveScriptFile->setText(QString("%1").arg(fileName)); |
767 | werner | 1835 | qDebug() << "loaded Javascript file" << fileName; |
1836 | ScriptGlobal::scriptOutput = ui->scriptResult; |
||
414 | werner | 1837 | |
216 | werner | 1838 | } |
1839 | |||
1840 | void MainWindow::on_scriptCommand_returnPressed() |
||
1841 | { |
||
717 | werner | 1842 | QString command = ui->scriptCommand->text(); |
1843 | if (ui->scriptCommandHistory->currentText() != command) { |
||
1844 | ui->scriptCommandHistory->insertItem(0, command); |
||
1845 | ui->scriptCommandHistory->setCurrentIndex(0); |
||
1846 | } |
||
716 | werner | 1847 | |
717 | werner | 1848 | qDebug() << "executing" << command; |
294 | werner | 1849 | try { |
767 | werner | 1850 | |
1851 | QString result = ScriptGlobal::executeScript(command); |
||
392 | werner | 1852 | if (!result.isEmpty()) { |
294 | werner | 1853 | ui->scriptResult->append(result); |
392 | werner | 1854 | qDebug() << result; |
1855 | } |
||
294 | werner | 1856 | } catch(const IException &e) { |
575 | werner | 1857 | Helper::msg(e.message()); |
294 | werner | 1858 | } |
216 | werner | 1859 | } |
225 | werner | 1860 | |
1861 | |||
239 | werner | 1862 | |
1863 | |||
254 | werner | 1864 | |
1865 | void MainWindow::on_actionOutput_table_description_triggered() |
||
1866 | { |
||
1867 | QString txt = GlobalSettings::instance()->outputManager()->wikiFormat(); |
||
1868 | QApplication::clipboard()->setText(txt); |
||
1869 | qDebug() << "Description copied to clipboard!"; |
||
1870 | } |
||
274 | werner | 1871 | |
1872 | void MainWindow::on_actionTimers_triggered() |
||
1873 | { |
||
360 | werner | 1874 | LogToWindow l; |
274 | werner | 1875 | DebugTimer::printAllTimers(); |
1876 | } |
||
323 | werner | 1877 | |
1878 | void MainWindow::on_actionOnline_ressources_triggered() |
||
1879 | { |
||
1880 | QDesktopServices::openUrl(QUrl("http://iland.boku.ac.at/")); |
||
1881 | } |
||
1882 | |||
1883 | void MainWindow::on_actionAbout_triggered() |
||
1884 | { |
||
1885 | AboutDialog dialog; |
||
1886 | dialog.exec(); |
||
1887 | } |
||
329 | werner | 1888 | |
1889 | |||
365 | werner | 1890 | /* Logging and filtering of logging */ |
1891 | void MainWindow::on_pbLogToClipboard_clicked() |
||
1892 | { |
||
1893 | // copy content of log window to clipboard |
||
1894 | QApplication::clipboard()->setText(ui->logOutput->toPlainText()); |
||
1895 | |||
1896 | } |
||
1897 | |||
1898 | void MainWindow::on_pbLogClearText_clicked() |
||
1899 | { |
||
1900 | ui->logOutput->clear(); |
||
1901 | ui->logOutput->setProperty("fullText",""); |
||
1902 | ui->pbLogFilterClear->setEnabled(false); |
||
1903 | } |
||
1904 | |||
1905 | void MainWindow::on_pbFilterExecute_clicked() |
||
1906 | { |
||
1907 | QStringList lines; |
||
1908 | QString search_for = ui->logFilterExpression->text(); |
||
1909 | if (search_for.isEmpty()) |
||
1910 | return; |
||
1911 | QString full_content; |
||
1912 | if (ui->logOutput->property("fullText").toString().isEmpty()) { |
||
1913 | full_content = ui->logOutput->toPlainText(); |
||
1914 | ui->logOutput->setProperty("fullText",full_content); |
||
1915 | } else |
||
1916 | full_content = ui->logOutput->property("fullText").toString(); |
||
1917 | QStringList debugLines = full_content.split("\n"); |
||
1918 | int i=0; |
||
1919 | foreach(const QString &line, debugLines) { |
||
1920 | i++; // line counter |
||
1921 | if (line.contains(search_for)) |
||
1922 | lines.push_back(QString("%1: %2").arg(i).arg(line) ); |
||
1923 | } |
||
1924 | if (lines.count()>0) { |
||
1925 | ui->logOutput->setPlainText(lines.join("\n")); |
||
1926 | } else { |
||
1927 | ui->logOutput->setPlainText("Search term not found!"); |
||
1928 | } |
||
1929 | ui->pbLogFilterClear->setEnabled(true); |
||
1930 | } |
||
1931 | |||
1932 | void MainWindow::on_pbLogFilterClear_clicked() |
||
1933 | { |
||
1934 | QString text = ui->logOutput->property("fullText").toString(); |
||
1935 | if (text.isEmpty()) |
||
1936 | return; |
||
392 | werner | 1937 | //QString sel = ui->logOutput->textCursor().selectedText(); |
1938 | //int line = sel.toInt(); |
||
1939 | int line = atoi(ui->logOutput->textCursor().block().text().toLocal8Bit()); |
||
365 | werner | 1940 | ui->logOutput->setPlainText(text); |
1941 | ui->logOutput->setProperty("fullText",""); |
||
392 | werner | 1942 | //int bl = ui->logOutput->document()->findBlockByNumber(line).position(); |
1943 | ui->logOutput->setTextCursor(QTextCursor(ui->logOutput->document()->findBlockByNumber(line))); |
||
1944 | ui->logOutput->ensureCursorVisible(); |
||
365 | werner | 1945 | ui->pbLogFilterClear->setEnabled(false); |
1946 | |||
1947 | } |
||
386 | werner | 1948 | |
1949 | void MainWindow::on_actionClearDebugOutput_triggered() |
||
1950 | { |
||
1951 | GlobalSettings::instance()->clearDebugLists(); |
||
1952 | } |
||
414 | werner | 1953 | |
503 | werner | 1954 | |
1955 | void MainWindow::on_actionDebug_triggered() |
||
1956 | { |
||
1957 | // |
||
1958 | QObject *o = QObject::sender(); |
||
1959 | int level = o->property("logLevel").toInt(); |
||
1960 | ui->actionDebug->setChecked( level == 0); |
||
1961 | ui->actionInfo->setChecked( level == 1); |
||
1962 | ui->actionWarning->setChecked( level == 2); |
||
1963 | ui->actionError->setChecked( level == 3); |
||
1964 | |||
1965 | setLogLevel(level); |
||
1966 | } |
||
1967 | |||
573 | werner | 1968 | |
634 | werner | 1969 | |
717 | werner | 1970 | void MainWindow::on_scriptCommandHistory_currentIndexChanged(int index) |
716 | werner | 1971 | { |
717 | werner | 1972 | if (index>=0) |
1973 | ui->scriptCommand->setText(ui->scriptCommandHistory->itemText(index)); |
||
716 | werner | 1974 | } |
647 | werner | 1975 | |
716 | werner | 1976 | void MainWindow::writeSettings() |
1977 | { |
||
1978 | QSettings settings; |
||
1979 | settings.beginGroup("MainWindow"); |
||
1980 | settings.setValue("geometry", saveGeometry()); |
||
1981 | settings.setValue("windowState", saveState()); |
||
1982 | settings.endGroup(); |
||
1983 | // javascript commands |
||
1984 | settings.beginWriteArray("javascriptCommands"); |
||
1985 | int size = qMin(ui->scriptCommandHistory->count(), 15); // max 15 entries in the history |
||
1986 | for (int i=0;i<size; ++i) { |
||
1987 | settings.setArrayIndex(i); |
||
1988 | settings.setValue("item", ui->scriptCommandHistory->itemText(i)); |
||
1989 | } |
||
1990 | settings.endArray(); |
||
1991 | settings.beginGroup("project"); |
||
1992 | settings.setValue("lastxmlfile", ui->initFileName->text()); |
||
1993 | settings.endGroup(); |
||
1043 | valentin | 1994 | //recent files menu qsettings registry save |
1995 | settings.beginGroup("recent_files"); |
||
1058 | werner | 1996 | for(int i = 0;i < mRecentFileList.size();i++){ |
1997 | settings.setValue(QString("file-%1").arg(i),mRecentFileList[i]); |
||
1043 | valentin | 1998 | } |
1999 | settings.endGroup(); |
||
716 | werner | 2000 | } |
2001 | void MainWindow::readSettings() |
||
2002 | { |
||
2003 | QSettings::setDefaultFormat(QSettings::IniFormat); |
||
2004 | QCoreApplication::setOrganizationName("iLand"); |
||
2005 | QCoreApplication::setOrganizationDomain("iland.boku.ac.at"); |
||
2006 | QCoreApplication::setApplicationName("iLand"); |
||
2007 | QSettings settings; |
||
2008 | qDebug() << "reading settings from" << settings.fileName(); |
||
2009 | |||
2010 | // window state and |
||
2011 | restoreGeometry(settings.value("MainWindow/geometry").toByteArray()); |
||
2012 | restoreState(settings.value("MainWindow/windowState").toByteArray()); |
||
2013 | |||
2014 | // read javascript commands |
||
2015 | int size = settings.beginReadArray("javascriptCommands"); |
||
2016 | for (int i=0;i<size; ++i) { |
||
2017 | settings.setArrayIndex(i); |
||
2018 | ui->scriptCommandHistory->addItem(settings.value("item").toString()); |
||
2019 | } |
||
2020 | settings.endArray(); |
||
1043 | valentin | 2021 | //recent files menu qsettings registry load |
2022 | settings.beginGroup("recent_files"); |
||
2023 | for(int i = 0;i < settings.childKeys().size();i++){ |
||
2024 | //resize(settings.value("size", QSize(400, 400)).toSize()); |
||
1058 | werner | 2025 | mRecentFileList.append(settings.value(QString("file-%1").arg(i)).toString()); |
1043 | valentin | 2026 | } |
2027 | for(int i = 0;i < ui->menuRecent_Files->actions().size();i++){ |
||
1058 | werner | 2028 | if(i < mRecentFileList.size()){ |
2029 | ui->menuRecent_Files->actions()[i]->setText(mRecentFileList[i]); |
||
1043 | valentin | 2030 | connect(ui->menuRecent_Files->actions()[i],SIGNAL(triggered()),this,SLOT(menuRecent_Files())); |
2031 | ui->menuRecent_Files->actions()[i]->setVisible(true); |
||
2032 | }else{ |
||
2033 | ui->menuRecent_Files->actions()[i]->setVisible(false); |
||
2034 | } |
||
2035 | } |
||
2036 | settings.endGroup(); |
||
716 | werner | 2037 | } |
2038 | |||
732 | werner | 2039 | |
2040 | void MainWindow::on_paintGridBox_currentIndexChanged(int index) |
||
2041 | { |
||
780 | werner | 2042 | Q_UNUSED(index); |
732 | werner | 2043 | ui->visOtherGrid->setChecked(true); |
2044 | } |
||
808 | werner | 2045 | |
2046 | void MainWindow::on_actionTest_triggered() |
||
2047 | { |
||
2048 | Tests t(this); |
||
2049 | int which = QInputDialog::getInt(this, "Which test", |
||
2050 | "which test?\n0: expression speed\n1: tree clear\n" \ |
||
2051 | "2:kill trees\n3: climate\n4: multiple light automation\n" \ |
||
2052 | "5: species response\n" \ |
||
2053 | "6: watercycle\n" \ |
||
2054 | "7: CSV File\n" \ |
||
2055 | "8: Xml setters\n" \ |
||
2056 | "9: random functions\n" \ |
||
2057 | "10: seed dispersal.\n" \ |
||
2058 | "11: multiple thread expression\n" \ |
||
2059 | "12: linearized expressions\n" \ |
||
2060 | "13: establishment\n" \ |
||
2061 | "14: GridRunner\n" \ |
||
2062 | "15: Soil (ICBM/2N)\n" \ |
||
2063 | "16: load Map \n" \ |
||
2064 | "17: test DEM \n" \ |
||
2065 | "18: test fire module \n" \ |
||
2066 | "19: test wind module\n" \ |
||
2067 | "20: test rumple index\n" \ |
||
876 | werner | 2068 | "21: test FOME setup\n" \ |
1002 | werner | 2069 | "22: test FOME step\n" \ |
1067 | werner | 2070 | "23: test debug establishment\n" \ |
2071 | "24: test grid special index hack",-1); |
||
808 | werner | 2072 | switch (which) { |
2073 | case 0: t.speedOfExpression();break; |
||
2074 | case 1: t.clearTrees(); break; |
||
2075 | case 2: t.killTrees(); break; |
||
2076 | case 3: t.climate(); break; |
||
2077 | case 4: t.multipleLightRuns(GlobalSettings::instance()->path("automation.xml", "home")); |
||
2078 | case 5: t.climateResponse(); break; |
||
2079 | case 6: t.testWater(); break; |
||
2080 | case 7: t.testCSVFile(); break; |
||
2081 | case 8: t.testXml(); break; |
||
2082 | case 9: t.testRandom(); break; |
||
2083 | case 10: t.testSeedDispersal(); break; |
||
2084 | case 11: t.testMultithreadExecute(); break; |
||
2085 | case 12: t.testLinearExpressions(); break; |
||
2086 | case 13: t.testEstablishment(); break; |
||
2087 | case 14: t.testGridRunner(); break; |
||
2088 | case 15: t.testSoil(); break; |
||
2089 | case 16: t.testMap(); break; |
||
2090 | case 17: t.testDEM(); break; |
||
2091 | case 18: t.testFire(); break; |
||
2092 | case 19: t.testWind(); break; |
||
2093 | case 20: t.testRumple(); break; |
||
2094 | case 21: t.testFOMEsetup(); break; |
||
876 | werner | 2095 | case 22: t.testFOMEstep(); break; |
1002 | werner | 2096 | case 23: t.testDbgEstablishment(); break; |
1067 | werner | 2097 | case 24: t.testGridIndexHack(); break; |
808 | werner | 2098 | } |
2099 | |||
2100 | } |
||
879 | werner | 2101 | |
2102 | void MainWindow::on_pbReloadQml_clicked() |
||
2103 | { |
||
2104 | //engine()->clearComponentCache(); |
||
2105 | //setSource(source()); |
||
2106 | if (!mRuler) |
||
2107 | return; |
||
2108 | mRuler->engine()->clearComponentCache(); |
||
2109 | mRuler->setSource(mRuler->source()); |
||
2110 | } |
||
942 | werner | 2111 | |
2112 | void MainWindow::on_actionExit_triggered() |
||
2113 | { |
||
2114 | if (Helper::question("Do you really want to quit?")) |
||
2115 | close(); |
||
2116 | } |
||
2117 | |||
2118 | void MainWindow::on_actionOpen_triggered() |
||
2119 | { |
||
2120 | QString fileName = Helper::fileDialog("select XML-project file", ui->initFileName->text(), "*.xml"); |
||
2121 | if (fileName.isEmpty()) |
||
2122 | return; |
||
2123 | ui->initFileName->setText(fileName); |
||
2124 | QString xmlFile = Helper::loadTextFile(ui->initFileName->text()); |
||
2125 | ui->iniEdit->setPlainText(xmlFile); |
||
2126 | checkModelState(); |
||
2127 | |||
2128 | } |
||
1043 | valentin | 2129 | |
2130 | void MainWindow::menuRecent_Files() |
||
2131 | { |
||
2132 | QAction* action = dynamic_cast<QAction*>(sender()); |
||
1047 | werner | 2133 | if (action) |
2134 | ui->initFileName->setText(action->text()); |
||
1043 | valentin | 2135 | } |
2136 | |||
2137 | void MainWindow::recentFileMenu(){ |
||
1058 | werner | 2138 | if(mRecentFileList.size() > 9){ |
2139 | mRecentFileList.removeAt(9); |
||
1043 | valentin | 2140 | } |
1058 | werner | 2141 | if(mRecentFileList.contains(ui->initFileName->text())){ |
2142 | mRecentFileList.removeAt(mRecentFileList.indexOf(ui->initFileName->text())); |
||
1043 | valentin | 2143 | } |
1058 | werner | 2144 | mRecentFileList.prepend(ui->initFileName->text()); |
1043 | valentin | 2145 | |
2146 | for(int i = 0;i < ui->menuRecent_Files->actions().size();i++){ |
||
1058 | werner | 2147 | if(i < mRecentFileList.size()){ |
2148 | ui->menuRecent_Files->actions()[i]->setText(mRecentFileList[i]); |
||
1043 | valentin | 2149 | connect(ui->menuRecent_Files->actions()[i],SIGNAL(triggered()),this,SLOT(menuRecent_Files())); |
2150 | ui->menuRecent_Files->actions()[i]->setVisible(true); |
||
2151 | }else{ |
||
2152 | ui->menuRecent_Files->actions()[i]->setVisible(false); |
||
2153 | } |
||
2154 | } |
||
2155 | } |
||
1046 | werner | 2156 | |
2157 | void MainWindow::on_saveFile_clicked() |
||
2158 | { |
||
2159 | ui->iniEdit->setVisible(!ui->iniEdit->isVisible()); |
||
2160 | } |
||
1061 | werner | 2161 | |
2162 | void MainWindow::on_lJSShortcuts_linkActivated(const QString &link) |
||
2163 | { |
||
2164 | qDebug() << "executing: " << link; |
||
2165 | try { |
||
2166 | |||
2167 | qDebug() << ScriptGlobal::executeScript(link); |
||
2168 | |||
2169 | } catch(const IException &e) { |
||
2170 | Helper::msg(e.message()); |
||
2171 | } |
||
2172 | |||
2173 | } |
||
1168 | werner | 2174 | |
2175 | |||
1179 | werner | 2176 | |
2177 | |||
2178 |