Subversion Repositories public iLand

Rev

Rev 555 | Rev 565 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1
 
185 werner 2
#include "global.h"
3
#include "management.h"
4
#include "helper.h"
186 werner 5
#include "model.h"
189 iland 6
#include "resourceunit.h"
186 werner 7
#include "tree.h"
216 werner 8
#include "expressionwrapper.h"
564 werner 9
#include "sapling.h"
186 werner 10
 
242 werner 11
#include "climateconverter.h"
245 werner 12
#include "csvfile.h"
247 werner 13
#include "scriptglobal.h"
552 werner 14
#include "mapgrid.h"
186 werner 15
 
185 werner 16
#include <QtScript>
216 werner 17
#include <QTextEdit>
18
QObject *Management::scriptOutput = 0;
185 werner 19
 
216 werner 20
QScriptValue script_debug(QScriptContext *ctx, QScriptEngine *eng)
294 werner 21
{
22
    QString value;
23
    for (int i = 0; i < ctx->argumentCount(); ++i) {
24
        if (i > 0)
25
            value.append(" ");
26
        value.append(ctx->argument(i).toString());
27
    }
28
    if (Management::scriptOutput) {
29
        QTextEdit *e = qobject_cast<QTextEdit*>(Management::scriptOutput);
30
        if (e)
31
            e->append(value);
32
    } else {
33
        qDebug() << "Script:" << value;
34
    }
35
    return eng->undefinedValue();
36
}
186 werner 37
 
294 werner 38
QScriptValue script_include(QScriptContext *ctx, QScriptEngine *eng)
39
{
552 werner 40
 
294 werner 41
    QString fileName = ctx->argument(0).toString();
42
    QString path =GlobalSettings::instance()->path(fileName, "script") ;
43
    QString includeFile=Helper::loadTextFile(path);
552 werner 44
 
45
    ctx->setActivationObject(ctx->parentContext()->activationObject());
46
    ctx->setThisObject(ctx->parentContext()->thisObject());
47
 
48
    QScriptValue ret = eng->evaluate(includeFile, fileName);
294 werner 49
    if (eng->hasUncaughtException())
50
        qDebug() << "Error in include:" << eng->uncaughtException().toString();
552 werner 51
    return ret;
294 werner 52
}
53
 
54
QScriptValue script_alert(QScriptContext *ctx, QScriptEngine *eng)
55
{
56
    QString value = ctx->argument(0).toString();
57
    Helper::msg(value);
58
    return eng->undefinedValue();
59
}
216 werner 60
// global output function
61
QString Management::executeScript(QString cmd)
62
{
63
    DebugTimer t("execute javascript");
64
    if (mEngine)
65
        mEngine->evaluate(cmd);
295 werner 66
    if (mEngine->hasUncaughtException()) {
321 werner 67
        //int line = mEngine->uncaughtExceptionLineNumber();
295 werner 68
        QString msg = QString( "Script Error occured: %1\n").arg( mEngine->uncaughtException().toString());
69
        msg+=mEngine->uncaughtExceptionBacktrace().join("\n");
70
        return msg;
71
    } else {
216 werner 72
        return QString();
295 werner 73
    }
216 werner 74
}
75
 
185 werner 76
Management::Management()
77
{
564 werner 78
    // setup the scripting engine
185 werner 79
    mEngine = new QScriptEngine();
80
    QScriptValue objectValue = mEngine->newQObject(this);
216 werner 81
    QScriptValue dbgprint = mEngine->newFunction(script_debug);
294 werner 82
    QScriptValue sinclude = mEngine->newFunction(script_include);
83
    QScriptValue alert = mEngine->newFunction(script_alert);
185 werner 84
    mEngine->globalObject().setProperty("management", objectValue);
216 werner 85
    mEngine->globalObject().setProperty("print",dbgprint);
294 werner 86
    mEngine->globalObject().setProperty("include",sinclude);
87
    mEngine->globalObject().setProperty("alert", alert);
247 werner 88
 
89
    // globals object: instatiate here, but ownership goes to script engine
90
    ScriptGlobal *global = new ScriptGlobal();
91
    QScriptValue glb = mEngine->newQObject(global,QScriptEngine::ScriptOwnership);
92
    mEngine->globalObject().setProperty("Globals", glb);
242 werner 93
    // other object types
94
    ClimateConverter::addToScriptEngine(*mEngine);
245 werner 95
    CSVFile::addToScriptEngine(*mEngine);
552 werner 96
    MapGridWrapper::addToScriptEngine(*mEngine);
216 werner 97
 
564 werner 98
    // default values for removal fractions
99
    // 100% of the stem, 0% of foliage and branches
100
    mRemoveFoliage = 0.;
101
    mRemoveBranch = 0.;
102
    mRemoveStem = 1.;
247 werner 103
 
564 werner 104
 
185 werner 105
}
106
 
107
Management::~Management()
108
{
109
    delete mEngine;
110
}
111
 
112
void Management::loadScript(const QString &fileName)
113
{
216 werner 114
    mScriptFile = fileName;
185 werner 115
    QString program = Helper::loadTextFile(fileName);
116
    if (program.isEmpty())
117
        return;
118
 
119
    mEngine->evaluate(program);
120
    qDebug() << "management script loaded";
121
    if (mEngine->hasUncaughtException())
122
        qDebug() << "Script Error occured: " << mEngine->uncaughtExceptionBacktrace();
123
 
124
}
125
 
126
void Management::remain(int number)
127
{
128
    qDebug() << "remain called (number): " << number;
186 werner 129
    Model *m = GlobalSettings::instance()->model();
130
    AllTreeIterator at(m);
131
    QList<Tree*> trees;
132
    while (Tree *t=at.next())
133
        trees.push_back(t);
134
    int to_kill = trees.count() - number;
135
    qDebug() << trees.count() << " standing, targetsize" << number << ", hence " << to_kill << "trees to remove";
136
    for (int i=0;i<to_kill;i++) {
349 werner 137
        int index = irandom(0, trees.count()-1);
278 werner 138
        trees[index]->remove();
186 werner 139
        trees.removeAt(index);
140
    }
141
    mRemoved += to_kill;
185 werner 142
}
143
 
144
 
564 werner 145
int Management::kill()
252 werner 146
{
564 werner 147
    int c = mTrees.count();
252 werner 148
    for (int i=0;i<mTrees.count();i++)
278 werner 149
        mTrees[i].first->remove();
252 werner 150
    mTrees.clear();
564 werner 151
    return c;
252 werner 152
}
153
 
564 werner 154
int Management::remove_percentiles(int pctfrom, int pctto, int number, bool management)
216 werner 155
{
156
    if (mTrees.isEmpty())
157
        return 0;
158
    int index_from = limit(int(pctfrom/100. * mTrees.count()), 0, mTrees.count());
346 werner 159
    int index_to = limit(int(pctto/100. * mTrees.count()), 0, mTrees.count()-1);
216 werner 160
    if (index_from>=index_to)
161
        return 0;
217 werner 162
    qDebug() << "attempting to remove" << number << "trees between indices" << index_from << "and" << index_to;
216 werner 163
    int i;
164
    int count = number;
217 werner 165
    if (index_to-index_from <= number)  {
216 werner 166
        // kill all
564 werner 167
        if (management) {
168
            // management
169
            for (i=index_from; i<index_to; i++)
170
                mTrees.at(i).first->remove(removeFoliage(), removeBranch(), removeStem());
171
        } else {
172
            // just kill...
173
            for (i=index_from; i<index_to; i++)
174
                mTrees.at(i).first->remove();
175
        }
216 werner 176
        count = index_to - index_from;
177
    } else {
178
        // kill randomly the provided number
179
        int cancel = 1000;
180
        while(number>=0) {
181
            int rnd_index = irandom(index_from, index_to);
182
            if (mTrees[rnd_index].first->isDead()) {
183
                if (--cancel<0) {
184
                    qDebug() << "Management::kill: canceling search." << number << "trees left.";
217 werner 185
                    count-=number; // not all trees were killed
216 werner 186
                    break;
187
                }
188
                continue;
189
            }
190
            cancel = 1000;
191
            number--;
564 werner 192
            if (management) {
193
                mTrees[rnd_index].first->remove( removeFoliage(), removeBranch(), removeStem() );
194
            } else {
195
                mTrees[rnd_index].first->remove();
196
            }
216 werner 197
        }
198
    }
217 werner 199
    qDebug() << count << "removed.";
564 werner 200
    // clean up the tree list...
201
    for (int i=mTrees.count()-1; i>=0; --i) {
202
        if (mTrees[i].first->isDead())
203
            mTrees.removeAt(i);
204
    }
205
    return count; // killed or manages
216 werner 206
}
207
 
564 werner 208
// from the range percentile range pctfrom to pctto (each 1..100)
209
int Management::kill(int pctfrom, int pctto, int number)
210
{
211
    return remove_percentiles(pctfrom, pctto, number, false);
212
}
213
 
214
// from the range percentile range pctfrom to pctto (each 1..100)
215
int Management::manage(int pctfrom, int pctto, int number)
216
{
217
    return remove_percentiles(pctfrom, pctto, number, true);
218
}
219
 
220
int Management::manage()
221
{
222
    int c = mTrees.count();
223
    for (int i=0;i<mTrees.count();i++)
224
        mTrees[i].first->remove(removeFoliage(),
225
                                removeBranch(),
226
                                removeStem()); // remove with current removal fractions
227
    mTrees.clear();
228
    return c;
229
}
230
 
231
 
232
 
185 werner 233
void Management::run()
234
{
216 werner 235
    mTrees.clear();
186 werner 236
    mRemoved=0;
185 werner 237
    qDebug() << "Management::run() called";
238
    QScriptValue mgmt = mEngine->globalObject().property("manage");
239
    int year = GlobalSettings::instance()->currentYear();
240
    mgmt.call(QScriptValue(), QScriptValueList()<<year);
241
    if (mEngine->hasUncaughtException())
242
        qDebug() << "Script Error occured: " << mEngine->uncaughtExceptionBacktrace();
243
 
186 werner 244
    if (mRemoved>0) {
187 iland 245
        foreach(ResourceUnit *ru, GlobalSettings::instance()->model()->ruList())
186 werner 246
           ru->cleanTreeList();
247
   }
185 werner 248
}
216 werner 249
 
250 werner 250
int Management::filter(QVariantList idList)
251
{
389 werner 252
    QVector<int> ids;
250 werner 253
    foreach(const QVariant &v, idList)
389 werner 254
        if (!v.isNull())
255
            ids << v.toInt();
256
//    QHash<int, int> ids;
257
//    foreach(const QVariant &v, idList)
258
//        ids[v.toInt()] = 1;
216 werner 259
 
250 werner 260
    QList<QPair<Tree*, double> >::iterator tp=mTrees.begin();
261
    while (tp!=mTrees.end()) {
262
        if (!ids.contains(tp->first->id()) )
263
            tp = mTrees.erase(tp);
264
        else
265
            tp++;
266
    }
389 werner 267
    qDebug() << "Management::filter by id-list:" << mTrees.count();
250 werner 268
    return mTrees.count();
269
}
270
 
271
int Management::filter(QString filter)
272
{
273
    TreeWrapper tw;
274
    Expression expr(filter,&tw);
275
    qDebug() << "filtering with" << filter;
276
    QList<QPair<Tree*, double> >::iterator tp=mTrees.begin();
277
    while (tp!=mTrees.end()) {
278
        tw.setTree(tp->first);
420 werner 279
        if (!expr.calculate(tw))
280
            tp = mTrees.erase(tp);
250 werner 281
        else
282
            tp++;
283
    }
284
    return mTrees.count();
285
}
286
 
294 werner 287
int Management::load(int ruindex)
288
{
289
    Model *m = GlobalSettings::instance()->model();
290
    ResourceUnit *ru = m->ru(ruindex);
291
    if (!ru)
292
        return -1;
293
    mTrees.clear();
294
    for (int i=0;i<ru->trees().count();i++)
295
        mTrees.push_back(QPair<Tree*,double>(ru->tree(i), 0.));
296
    return mTrees.count();
297
}
298
 
216 werner 299
int Management::load(QString filter)
300
{
301
    TreeWrapper tw;
302
    Model *m = GlobalSettings::instance()->model();
303
    mTrees.clear();
304
    AllTreeIterator at(m);
305
    if (filter.isEmpty()) {
306
        while (Tree *t=at.next())
307
            if (!t->isDead())
308
                mTrees.push_back(QPair<Tree*, double>(t, 0.));
309
    } else {
310
        Expression expr(filter,&tw);
311
        qDebug() << "filtering with" << filter;
312
        while (Tree *t=at.next()) {
313
            tw.setTree(t);
314
            if (!t->isDead() && expr.execute())
315
                mTrees.push_back(QPair<Tree*, double>(t, 0.));
316
        }
317
    }
318
    return mTrees.count();
319
}
320
 
555 werner 321
/**
322
*/
544 werner 323
void Management::loadFromTreeList(QList<Tree*>tree_list)
324
{
325
    mTrees.clear();
326
    for (int i=0;i<tree_list.count();++i)
327
        mTrees.append(QPair<Tree*, double>(tree_list[i], 0.));
328
}
329
 
555 werner 330
// loadFromMap: script access
331
void Management::loadFromMap(QScriptValue map_grid_object, int key)
552 werner 332
{
555 werner 333
    MapGridWrapper *wrap = qobject_cast<MapGridWrapper*>(map_grid_object.toQObject());
334
    if (!wrap) {
335
        context()->throwError("loadFromMap called with invalid map object!");
336
        return;
337
    }
338
    loadFromMap(wrap->map(), key);
339
}
340
 
564 werner 341
void Management::killSaplings(QScriptValue map_grid_object, int key)
342
{
343
    MapGridWrapper *wrap = qobject_cast<MapGridWrapper*>(map_grid_object.toQObject());
344
    if (!wrap) {
345
        context()->throwError("loadFromMap called with invalid map object!");
346
        return;
347
    }
348
    //loadFromMap(wrap->map(), key);
349
    // retrieve all sapling trees on the stand:
350
    QList<QPair<ResourceUnitSpecies *, SaplingTree *> > list = wrap->map()->saplingTrees(key);
351
    // for now, just kill em all...
352
    for (QList<QPair<ResourceUnitSpecies *, SaplingTree *> >::iterator it = list.begin(); it!=list.end(); ++it)
353
        (*it).second->pixel = 0;
354
    // the storage for unused/invalid saplingtrees is released lazily (once a year, after growth)
355
}
356
 
555 werner 357
/** loadFromMap selects trees located on pixels with value 'key' within the grid 'map_grid'.
358
*/
359
void Management::loadFromMap(const MapGrid *map_grid, int key)
360
{
361
    if (!map_grid) {
552 werner 362
        qDebug() << "invalid parameter for Management::loadFromMap: Map expected!";
363
        return;
364
    }
555 werner 365
    if (map_grid->isValid()) {
366
        QList<Tree*> tree_list = map_grid->trees(key);
552 werner 367
        loadFromTreeList( tree_list );
368
    } else {
369
        qDebug() << "Management::loadFromMap: grid is not valid - no trees loaded";
370
    }
371
 
372
}
373
 
216 werner 374
bool treePairValue(const QPair<Tree*, double> &p1, const QPair<Tree*, double> &p2)
375
{
376
    return p1.second < p2.second;
377
}
378
 
379
void Management::sort(QString statement)
380
{
381
    TreeWrapper tw;
382
    Expression sorter(statement, &tw);
383
    // fill the "value" part of the tree storage with a value for each tree
384
    for (int i=0;i<mTrees.count(); ++i) {
385
        tw.setTree(mTrees.at(i).first);
386
        mTrees[i].second = sorter.execute();
387
   }
388
   // now sort the list....
389
   qSort(mTrees.begin(), mTrees.end(), treePairValue);
390
}
391
 
392
double Management::percentile(int pct)
393
{
394
    if (mTrees.count()==0)
395
        return -1.;
396
    int idx = int( (pct/100.) * mTrees.count());
397
    if (idx>=0 && idx<mTrees.count())
398
        return mTrees.at(idx).second;
399
    else
400
        return -1;
401
}
564 werner 402