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 | |||
185 | werner | 20 | #include "global.h" |
21 | #include "management.h" |
||
22 | #include "helper.h" |
||
186 | werner | 23 | #include "model.h" |
189 | iland | 24 | #include "resourceunit.h" |
186 | werner | 25 | #include "tree.h" |
216 | werner | 26 | #include "expressionwrapper.h" |
566 | werner | 27 | #include "soil.h" |
186 | werner | 28 | |
767 | werner | 29 | //#include "climateconverter.h" |
30 | //#include "csvfile.h" |
||
247 | werner | 31 | #include "scriptglobal.h" |
552 | werner | 32 | #include "mapgrid.h" |
767 | werner | 33 | //#include "modules.h" |
186 | werner | 34 | |
793 | werner | 35 | #include <QJSEngine> |
36 | #include <QJSValue> |
||
185 | werner | 37 | |
697 | werner | 38 | /** @class Management Management executes management routines. |
39 | @ingroup core |
||
40 | The actual iLand management is based on Javascript functions. This class provides |
||
41 | the frame for executing the javascript as well as the functions that are called by scripts and |
||
42 | that really do the work. |
||
43 | See http://iland.boku.ac.at/iLand+scripting, http://iland.boku.ac.at/Object+Management for management Javascript API. |
||
44 | */ |
||
45 | |||
186 | werner | 46 | |
216 | werner | 47 | // global output function |
48 | QString Management::executeScript(QString cmd) |
||
49 | { |
||
767 | werner | 50 | return ScriptGlobal::executeScript(cmd); |
216 | werner | 51 | } |
52 | |||
185 | werner | 53 | Management::Management() |
54 | { |
||
564 | werner | 55 | // setup the scripting engine |
767 | werner | 56 | mEngine = GlobalSettings::instance()->scriptEngine(); |
793 | werner | 57 | QJSValue objectValue = mEngine->newQObject(this); |
185 | werner | 58 | mEngine->globalObject().setProperty("management", objectValue); |
247 | werner | 59 | |
564 | werner | 60 | // default values for removal fractions |
61 | // 100% of the stem, 0% of foliage and branches |
||
62 | mRemoveFoliage = 0.; |
||
63 | mRemoveBranch = 0.; |
||
64 | mRemoveStem = 1.; |
||
247 | werner | 65 | |
185 | werner | 66 | } |
67 | |||
68 | Management::~Management() |
||
69 | { |
||
70 | } |
||
71 | |||
72 | |||
566 | werner | 73 | int Management::remain(int number) |
185 | werner | 74 | { |
75 | qDebug() << "remain called (number): " << number; |
||
186 | werner | 76 | Model *m = GlobalSettings::instance()->model(); |
77 | AllTreeIterator at(m); |
||
78 | QList<Tree*> trees; |
||
79 | while (Tree *t=at.next()) |
||
80 | trees.push_back(t); |
||
81 | int to_kill = trees.count() - number; |
||
82 | qDebug() << trees.count() << " standing, targetsize" << number << ", hence " << to_kill << "trees to remove"; |
||
83 | for (int i=0;i<to_kill;i++) { |
||
1164 | werner | 84 | int index = irandom(0, trees.count()); |
278 | werner | 85 | trees[index]->remove(); |
186 | werner | 86 | trees.removeAt(index); |
87 | } |
||
88 | mRemoved += to_kill; |
||
566 | werner | 89 | return to_kill; |
185 | werner | 90 | } |
91 | |||
92 | |||
825 | werner | 93 | int Management::killAll() |
252 | werner | 94 | { |
564 | werner | 95 | int c = mTrees.count(); |
252 | werner | 96 | for (int i=0;i<mTrees.count();i++) |
278 | werner | 97 | mTrees[i].first->remove(); |
252 | werner | 98 | mTrees.clear(); |
564 | werner | 99 | return c; |
252 | werner | 100 | } |
101 | |||
914 | werner | 102 | int Management::disturbanceKill() |
103 | { |
||
104 | int c = mTrees.count(); |
||
105 | for (int i=0;i<mTrees.count();i++) |
||
106 | mTrees[i].first->removeDisturbance(0.1, 0.1, 0.1, 0.1, 1.); |
||
107 | mTrees.clear(); |
||
108 | return c; |
||
109 | } |
||
110 | |||
579 | werner | 111 | int Management::kill(QString filter, double fraction) |
112 | { |
||
113 | return remove_trees(filter, fraction, false); |
||
114 | } |
||
115 | int Management::manage(QString filter, double fraction) |
||
116 | { |
||
117 | return remove_trees(filter, fraction, true); |
||
118 | } |
||
119 | |||
1044 | werner | 120 | void Management::cutAndDrop() |
121 | { |
||
1053 | werner | 122 | //int c = mTrees.count(); |
1044 | werner | 123 | for (int i=0;i<mTrees.count();i++) { |
1204 | werner | 124 | mTrees[i].first->setDeathCutdown(); // set flag that tree is cut down |
1044 | werner | 125 | mTrees[i].first->die(); |
126 | } |
||
127 | mTrees.clear(); |
||
128 | } |
||
129 | |||
564 | werner | 130 | int Management::remove_percentiles(int pctfrom, int pctto, int number, bool management) |
216 | werner | 131 | { |
132 | if (mTrees.isEmpty()) |
||
133 | return 0; |
||
134 | int index_from = limit(int(pctfrom/100. * mTrees.count()), 0, mTrees.count()); |
||
1164 | werner | 135 | int index_to = limit(int(pctto/100. * mTrees.count()), 0, mTrees.count()); |
216 | werner | 136 | if (index_from>=index_to) |
137 | return 0; |
||
217 | werner | 138 | qDebug() << "attempting to remove" << number << "trees between indices" << index_from << "and" << index_to; |
216 | werner | 139 | int i; |
140 | int count = number; |
||
217 | werner | 141 | if (index_to-index_from <= number) { |
216 | werner | 142 | // kill all |
564 | werner | 143 | if (management) { |
144 | // management |
||
145 | for (i=index_from; i<index_to; i++) |
||
146 | mTrees.at(i).first->remove(removeFoliage(), removeBranch(), removeStem()); |
||
147 | } else { |
||
148 | // just kill... |
||
149 | for (i=index_from; i<index_to; i++) |
||
150 | mTrees.at(i).first->remove(); |
||
151 | } |
||
216 | werner | 152 | count = index_to - index_from; |
153 | } else { |
||
154 | // kill randomly the provided number |
||
155 | int cancel = 1000; |
||
156 | while(number>=0) { |
||
157 | int rnd_index = irandom(index_from, index_to); |
||
158 | if (mTrees[rnd_index].first->isDead()) { |
||
159 | if (--cancel<0) { |
||
160 | qDebug() << "Management::kill: canceling search." << number << "trees left."; |
||
217 | werner | 161 | count-=number; // not all trees were killed |
216 | werner | 162 | break; |
163 | } |
||
164 | continue; |
||
165 | } |
||
166 | cancel = 1000; |
||
167 | number--; |
||
564 | werner | 168 | if (management) { |
169 | mTrees[rnd_index].first->remove( removeFoliage(), removeBranch(), removeStem() ); |
||
170 | } else { |
||
171 | mTrees[rnd_index].first->remove(); |
||
172 | } |
||
216 | werner | 173 | } |
174 | } |
||
217 | werner | 175 | qDebug() << count << "removed."; |
564 | werner | 176 | // clean up the tree list... |
177 | for (int i=mTrees.count()-1; i>=0; --i) { |
||
178 | if (mTrees[i].first->isDead()) |
||
179 | mTrees.removeAt(i); |
||
180 | } |
||
181 | return count; // killed or manages |
||
216 | werner | 182 | } |
183 | |||
579 | werner | 184 | /** remove trees from a list and reduce the list. |
185 | |||
186 | */ |
||
187 | int Management::remove_trees(QString expression, double fraction, bool management) |
||
188 | { |
||
189 | TreeWrapper tw; |
||
190 | Expression expr(expression,&tw); |
||
191 | expr.enableIncSum(); |
||
192 | int n = 0; |
||
193 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
||
194 | try { |
||
195 | while (tp!=mTrees.end()) { |
||
196 | tw.setTree(tp->first); |
||
197 | // if expression evaluates to true and if random number below threshold... |
||
198 | if (expr.calculate(tw) && drandom() <=fraction) { |
||
199 | // remove from system |
||
200 | if (management) |
||
201 | tp->first->remove(removeFoliage(), removeBranch(), removeStem()); // management with removal fractions |
||
202 | else |
||
203 | tp->first->remove(); // kill |
||
1044 | werner | 204 | |
579 | werner | 205 | // remove from tree list |
206 | tp = mTrees.erase(tp); |
||
207 | n++; |
||
208 | } else { |
||
753 | werner | 209 | ++tp; |
579 | werner | 210 | } |
211 | } |
||
212 | } catch(const IException &e) { |
||
793 | werner | 213 | throwError(e.message()); |
579 | werner | 214 | } |
215 | return n; |
||
216 | } |
||
217 | |||
218 | // calculate aggregates for all trees in the internal list |
||
219 | double Management::aggregate_function(QString expression, QString filter, QString type) |
||
220 | { |
||
221 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
||
222 | TreeWrapper tw; |
||
223 | Expression expr(expression,&tw); |
||
224 | |||
225 | double sum = 0.; |
||
226 | int n=0; |
||
227 | try { |
||
228 | |||
229 | if (filter.isEmpty()) { |
||
230 | // without filtering |
||
231 | while (tp!=mTrees.end()) { |
||
232 | tw.setTree(tp->first); |
||
233 | sum += expr.calculate(); |
||
234 | ++n; |
||
235 | ++tp; |
||
236 | } |
||
237 | } else { |
||
238 | // with filtering |
||
239 | Expression filter_expr(filter,&tw); |
||
240 | filter_expr.enableIncSum(); |
||
241 | while (tp!=mTrees.end()) { |
||
242 | tw.setTree(tp->first); |
||
243 | if (filter_expr.calculate()) { |
||
244 | sum += expr.calculate(); |
||
245 | ++n; |
||
246 | } |
||
247 | ++tp; |
||
248 | } |
||
249 | } |
||
250 | |||
251 | } catch(const IException &e) { |
||
793 | werner | 252 | throwError(e.message()); |
579 | werner | 253 | } |
254 | if (type=="sum") |
||
255 | return sum; |
||
256 | if (type=="mean") |
||
257 | return n>0?sum/double(n):0.; |
||
258 | return 0.; |
||
259 | } |
||
260 | |||
793 | werner | 261 | // introduced with switch to QJSEngine (context->throwMessage not available any more) |
262 | void Management::throwError(const QString &errormessage) |
||
263 | { |
||
264 | GlobalSettings::instance()->scriptEngine()->evaluate(QString("throw '%1'").arg(errormessage)); |
||
915 | werner | 265 | qDebug() << "Management-script error:" << errormessage; |
793 | werner | 266 | // no idea if this works!!! |
267 | } |
||
579 | werner | 268 | |
793 | werner | 269 | |
564 | werner | 270 | // from the range percentile range pctfrom to pctto (each 1..100) |
825 | werner | 271 | int Management::killPct(int pctfrom, int pctto, int number) |
564 | werner | 272 | { |
273 | return remove_percentiles(pctfrom, pctto, number, false); |
||
274 | } |
||
275 | |||
276 | // from the range percentile range pctfrom to pctto (each 1..100) |
||
825 | werner | 277 | int Management::managePct(int pctfrom, int pctto, int number) |
564 | werner | 278 | { |
279 | return remove_percentiles(pctfrom, pctto, number, true); |
||
280 | } |
||
281 | |||
825 | werner | 282 | int Management::manageAll() |
564 | werner | 283 | { |
284 | int c = mTrees.count(); |
||
285 | for (int i=0;i<mTrees.count();i++) |
||
286 | mTrees[i].first->remove(removeFoliage(), |
||
287 | removeBranch(), |
||
288 | removeStem()); // remove with current removal fractions |
||
289 | mTrees.clear(); |
||
290 | return c; |
||
291 | } |
||
292 | |||
293 | |||
294 | |||
185 | werner | 295 | void Management::run() |
296 | { |
||
216 | werner | 297 | mTrees.clear(); |
186 | werner | 298 | mRemoved=0; |
185 | werner | 299 | qDebug() << "Management::run() called"; |
793 | werner | 300 | QJSValue mgmt = mEngine->globalObject().property("manage"); |
185 | werner | 301 | int year = GlobalSettings::instance()->currentYear(); |
793 | werner | 302 | //mgmt.call(QJSValue(), QScriptValueList()<<year); |
303 | QJSValue result = mgmt.call(QJSValueList() << year); |
||
304 | if (result.isError()) |
||
305 | qDebug() << "Script Error occured: " << result.toString();// << "\n" << mEngine->uncaughtExceptionBacktrace(); |
||
185 | werner | 306 | |
307 | } |
||
216 | werner | 308 | |
767 | werner | 309 | void Management::loadScript(const QString &fileName) |
310 | { |
||
311 | mScriptFile = fileName; |
||
312 | ScriptGlobal::loadScript(fileName); |
||
313 | } |
||
314 | |||
848 | werner | 315 | int Management::filterIdList(QVariantList idList) |
250 | werner | 316 | { |
389 | werner | 317 | QVector<int> ids; |
250 | werner | 318 | foreach(const QVariant &v, idList) |
389 | werner | 319 | if (!v.isNull()) |
320 | ids << v.toInt(); |
||
321 | // QHash<int, int> ids; |
||
322 | // foreach(const QVariant &v, idList) |
||
323 | // ids[v.toInt()] = 1; |
||
216 | werner | 324 | |
250 | werner | 325 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
326 | while (tp!=mTrees.end()) { |
||
327 | if (!ids.contains(tp->first->id()) ) |
||
328 | tp = mTrees.erase(tp); |
||
329 | else |
||
753 | werner | 330 | ++tp; |
250 | werner | 331 | } |
389 | werner | 332 | qDebug() << "Management::filter by id-list:" << mTrees.count(); |
250 | werner | 333 | return mTrees.count(); |
334 | } |
||
335 | |||
336 | int Management::filter(QString filter) |
||
337 | { |
||
338 | TreeWrapper tw; |
||
339 | Expression expr(filter,&tw); |
||
579 | werner | 340 | expr.enableIncSum(); |
575 | werner | 341 | int n_before = mTrees.count(); |
250 | werner | 342 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
575 | werner | 343 | try { |
344 | while (tp!=mTrees.end()) { |
||
345 | tw.setTree(tp->first); |
||
848 | werner | 346 | double value = expr.calculate(tw); |
347 | // keep if expression returns true (1) |
||
348 | bool keep = value==1.; |
||
349 | // if value is >0 (i.e. not "false"), then draw a random number |
||
350 | if (!keep && value>0.) |
||
351 | keep = drandom() < value; |
||
352 | |||
353 | if (!keep) |
||
575 | werner | 354 | tp = mTrees.erase(tp); |
355 | else |
||
753 | werner | 356 | ++tp; |
575 | werner | 357 | } |
358 | } catch(const IException &e) { |
||
793 | werner | 359 | throwError(e.message()); |
250 | werner | 360 | } |
575 | werner | 361 | |
362 | qDebug() << "filtering with" << filter << "N=" << n_before << "/" << mTrees.count() << "trees (before/after filtering)."; |
||
250 | werner | 363 | return mTrees.count(); |
364 | } |
||
365 | |||
825 | werner | 366 | int Management::loadResourceUnit(int ruindex) |
294 | werner | 367 | { |
368 | Model *m = GlobalSettings::instance()->model(); |
||
369 | ResourceUnit *ru = m->ru(ruindex); |
||
370 | if (!ru) |
||
371 | return -1; |
||
372 | mTrees.clear(); |
||
373 | for (int i=0;i<ru->trees().count();i++) |
||
579 | werner | 374 | if (!ru->tree(i)->isDead()) |
375 | mTrees.push_back(QPair<Tree*,double>(ru->tree(i), 0.)); |
||
294 | werner | 376 | return mTrees.count(); |
377 | } |
||
378 | |||
216 | werner | 379 | int Management::load(QString filter) |
380 | { |
||
381 | TreeWrapper tw; |
||
382 | Model *m = GlobalSettings::instance()->model(); |
||
383 | mTrees.clear(); |
||
384 | AllTreeIterator at(m); |
||
385 | if (filter.isEmpty()) { |
||
579 | werner | 386 | while (Tree *t=at.nextLiving()) |
216 | werner | 387 | if (!t->isDead()) |
388 | mTrees.push_back(QPair<Tree*, double>(t, 0.)); |
||
389 | } else { |
||
390 | Expression expr(filter,&tw); |
||
579 | werner | 391 | expr.enableIncSum(); |
216 | werner | 392 | qDebug() << "filtering with" << filter; |
579 | werner | 393 | while (Tree *t=at.nextLiving()) { |
216 | werner | 394 | tw.setTree(t); |
395 | if (!t->isDead() && expr.execute()) |
||
396 | mTrees.push_back(QPair<Tree*, double>(t, 0.)); |
||
397 | } |
||
398 | } |
||
399 | return mTrees.count(); |
||
400 | } |
||
401 | |||
555 | werner | 402 | /** |
403 | */ |
||
544 | werner | 404 | void Management::loadFromTreeList(QList<Tree*>tree_list) |
405 | { |
||
406 | mTrees.clear(); |
||
407 | for (int i=0;i<tree_list.count();++i) |
||
408 | mTrees.append(QPair<Tree*, double>(tree_list[i], 0.)); |
||
409 | } |
||
410 | |||
555 | werner | 411 | // loadFromMap: script access |
604 | werner | 412 | void Management::loadFromMap(MapGridWrapper *wrap, int key) |
552 | werner | 413 | { |
555 | werner | 414 | if (!wrap) { |
793 | werner | 415 | throwError("loadFromMap called with invalid map object!"); |
555 | werner | 416 | return; |
417 | } |
||
418 | loadFromMap(wrap->map(), key); |
||
419 | } |
||
420 | |||
604 | werner | 421 | void Management::killSaplings(MapGridWrapper *wrap, int key) |
564 | werner | 422 | { |
604 | werner | 423 | //MapGridWrapper *wrap = qobject_cast<MapGridWrapper*>(map_grid_object.toQObject()); |
424 | //if (!wrap) { |
||
425 | // context()->throwError("loadFromMap called with invalid map object!"); |
||
426 | // return; |
||
427 | //} |
||
564 | werner | 428 | //loadFromMap(wrap->map(), key); |
1203 | werner | 429 | QRectF box = wrap->map()->boundingBox(key); |
430 | GridRunner<float> runner(GlobalSettings::instance()->model()->grid(), box); |
||
431 | ResourceUnit *ru; |
||
432 | while (runner.next()) { |
||
433 | if (wrap->map()->standIDFromLIFCoord(runner.currentIndex()) == key) { |
||
434 | SaplingCell *sc=GlobalSettings::instance()->model()->saplings()->cell(runner.currentIndex(),true, &ru); |
||
435 | if (sc) |
||
436 | GlobalSettings::instance()->model()->saplings()->clearSaplings(sc,ru,true); |
||
437 | } |
||
438 | } |
||
564 | werner | 439 | } |
440 | |||
604 | werner | 441 | /// specify removal fractions |
442 | /// @param SWDFrac 0: no change, 1: remove all of standing woody debris |
||
443 | /// @param DWDfrac 0: no change, 1: remove all of downled woody debris |
||
444 | /// @param litterFrac 0: no change, 1: remove all of soil litter |
||
445 | /// @param soilFrac 0: no change, 1: remove all of soil organic matter |
||
446 | void Management::removeSoilCarbon(MapGridWrapper *wrap, int key, double SWDfrac, double DWDfrac, double litterFrac, double soilFrac) |
||
565 | werner | 447 | { |
590 | werner | 448 | if (!(SWDfrac>=0. && SWDfrac<=1. && DWDfrac>=0. && DWDfrac<=1. && soilFrac>=0. && soilFrac<=1. && litterFrac>=0. && litterFrac<=1.)) { |
793 | werner | 449 | throwError(QString("removeSoilCarbon called with invalid parameters!!\nArgs: ---")); |
590 | werner | 450 | return; |
451 | } |
||
565 | werner | 452 | QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key); |
453 | double total_area = 0.; |
||
454 | for (int i=0;i<ru_areas.size();++i) { |
||
455 | ResourceUnit *ru = ru_areas[i].first; |
||
456 | double area_factor = ru_areas[i].second; // 0..1 |
||
457 | total_area += area_factor; |
||
566 | werner | 458 | // swd |
604 | werner | 459 | if (SWDfrac>0.) |
460 | ru->snag()->removeCarbon(SWDfrac*area_factor); |
||
566 | werner | 461 | // soil pools |
462 | ru->soil()->disturbance(DWDfrac*area_factor, litterFrac*area_factor, soilFrac*area_factor); |
||
585 | werner | 463 | // qDebug() << ru->index() << area_factor; |
565 | werner | 464 | } |
465 | qDebug() << "total area" << total_area << "of" << wrap->map()->area(key); |
||
466 | } |
||
467 | |||
607 | werner | 468 | /** slash snags (SWD and otherWood-Pools) of polygon \p key on the map \p wrap. |
469 | The factor is scaled to the overlapping area of \p key on the resource unit. |
||
470 | @param wrap MapGrid to use together with \p key |
||
471 | @param key ID of the polygon. |
||
472 | @param slash_fraction 0: no change, 1: 100% |
||
473 | */ |
||
474 | void Management::slashSnags(MapGridWrapper *wrap, int key, double slash_fraction) |
||
475 | { |
||
476 | if (slash_fraction<0 || slash_fraction>1) { |
||
793 | werner | 477 | throwError(QString("slashSnags called with invalid parameters!!\nArgs: ....")); |
607 | werner | 478 | return; |
479 | } |
||
480 | QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key); |
||
481 | double total_area = 0.; |
||
482 | for (int i=0;i<ru_areas.size();++i) { |
||
483 | ResourceUnit *ru = ru_areas[i].first; |
||
484 | double area_factor = ru_areas[i].second; // 0..1 |
||
485 | total_area += area_factor; |
||
486 | ru->snag()->management(slash_fraction * area_factor); |
||
487 | // qDebug() << ru->index() << area_factor; |
||
488 | } |
||
489 | qDebug() << "total area" << total_area << "of" << wrap->map()->area(key); |
||
490 | |||
491 | } |
||
492 | |||
555 | werner | 493 | /** loadFromMap selects trees located on pixels with value 'key' within the grid 'map_grid'. |
494 | */ |
||
495 | void Management::loadFromMap(const MapGrid *map_grid, int key) |
||
496 | { |
||
497 | if (!map_grid) { |
||
552 | werner | 498 | qDebug() << "invalid parameter for Management::loadFromMap: Map expected!"; |
499 | return; |
||
500 | } |
||
555 | werner | 501 | if (map_grid->isValid()) { |
502 | QList<Tree*> tree_list = map_grid->trees(key); |
||
552 | werner | 503 | loadFromTreeList( tree_list ); |
504 | } else { |
||
505 | qDebug() << "Management::loadFromMap: grid is not valid - no trees loaded"; |
||
506 | } |
||
507 | |||
508 | } |
||
509 | |||
216 | werner | 510 | bool treePairValue(const QPair<Tree*, double> &p1, const QPair<Tree*, double> &p2) |
511 | { |
||
512 | return p1.second < p2.second; |
||
513 | } |
||
514 | |||
515 | void Management::sort(QString statement) |
||
516 | { |
||
517 | TreeWrapper tw; |
||
518 | Expression sorter(statement, &tw); |
||
519 | // fill the "value" part of the tree storage with a value for each tree |
||
520 | for (int i=0;i<mTrees.count(); ++i) { |
||
521 | tw.setTree(mTrees.at(i).first); |
||
522 | mTrees[i].second = sorter.execute(); |
||
523 | } |
||
524 | // now sort the list.... |
||
525 | qSort(mTrees.begin(), mTrees.end(), treePairValue); |
||
526 | } |
||
527 | |||
528 | double Management::percentile(int pct) |
||
529 | { |
||
530 | if (mTrees.count()==0) |
||
531 | return -1.; |
||
532 | int idx = int( (pct/100.) * mTrees.count()); |
||
533 | if (idx>=0 && idx<mTrees.count()) |
||
534 | return mTrees.at(idx).second; |
||
535 | else |
||
536 | return -1; |
||
537 | } |
||
564 | werner | 538 | |
579 | werner | 539 | /// random shuffle of all trees in the list |
540 | void Management::randomize() |
||
541 | { |
||
542 | // fill the "value" part of the tree storage with a random value for each tree |
||
543 | for (int i=0;i<mTrees.count(); ++i) { |
||
544 | mTrees[i].second = drandom(); |
||
545 | } |
||
546 | // now sort the list.... |
||
547 | qSort(mTrees.begin(), mTrees.end(), treePairValue); |
||
548 | |||
549 | } |
||
550 | |||
551 | |||
552 | |||
607 | werner | 553 | |
554 |