Subversion Repositories public iLand

Rev

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

Rev Author Line No. Line
1
 
33 Werner 2
#include "stampcontainer.h"
102 Werner 3
#include "globalsettings.h"
103 Werner 4
#include "exception.h"
33 Werner 5
 
6
//constants
7
const int StampContainer::cBHDclassWidth=4;
357 werner 8
const int StampContainer::cBHDclassLow = 4; ///< bhd classes start with 4: class 0 = 4-8, class1 = 8..112
9
const int StampContainer::cBHDclassCount = 70; ///< class count, see getKey(): for lower dbhs classes are smaller
33 Werner 10
const int StampContainer::cHDclassWidth=10;
61 Werner 11
const int StampContainer::cHDclassLow = 35; ///< hd classes offset is 35: class 0 = 35-45, class 1 = 45-55
362 werner 12
const int StampContainer::cHDclassCount = 16; ///< class count. highest class:  185-195
33 Werner 13
 
401 werner 14
// static values
15
Grid<float> StampContainer::m_distance;
33 Werner 16
 
17
StampContainer::StampContainer()
18
{
19
    //
20
    m_lookup.setup(1., // cellsize
21
                   cBHDclassCount, // count x
22
                   cHDclassCount); // count y
23
    m_lookup.initialize(NULL);
37 Werner 24
    //qDebug() << "grid after init" << gridToString(m_lookup);
33 Werner 25
    m_maxBhd = -1;
26
    m_useLookup = true;
27
}
28
 
29
StampContainer::~StampContainer()
30
{
31
    // delete stamps.
32
    while (!m_stamps.isEmpty())
33
        delete m_stamps.takeLast().stamp;
34
 
35
}
64 Werner 36
/// getKey: decodes a floating point piar of dbh and hd-ratio to indices for the
37
/// lookup table containing pointers to the actual stamps.
38
void StampContainer::getKey(const float dbh, const float hd_value, int &dbh_class, int &hd_class) const
33 Werner 39
{
64 Werner 40
    hd_class = int(hd_value - cHDclassLow) / cHDclassWidth;
41
    dbh_class = int(dbh - cBHDclassLow) / cBHDclassWidth;
42
    // fixed scheme: smallest classification scheme for tree-diameters:
43
    // 1cm width from 4 up to 9cm,
44
    // 2cm bins from 10 to 18cm
45
    // 4cm bins starting from 20cm
46
    if (dbh < 10.f) {
47
        dbh_class = qMax(0, int(dbh-4.)); // classes from 0..5
48
    } else if (dbh<20.f) {
49
        dbh_class = 6 + int((dbh-10.f) / 2.f); // 10-12cm has index 6
50
    } else {
51
        dbh_class = 11 + int((dbh-20.f) / 4.f); // 20-24cm has index 11
52
    }
33 Werner 53
}
54
 
58 Werner 55
/** fill up the NULLs in the lookup map */
56
void StampContainer::finalizeSetup()
57
{
58
    if (!m_useLookup)
59
        return;
60
    Stamp *s;
61
    int h;
401 werner 62
    int max_size=0;
58 Werner 63
    for (int b=0;b<cBHDclassCount;b++) {
64
        // find lowest value...
65
        for (h=0;h<cHDclassCount;h++) {
66
            s=m_lookup.valueAtIndex(b,h);
67
            if (s) {
68
                // fill up values left from this value
69
                for (int hfill=0;hfill<h;hfill++)
361 werner 70
                    m_lookup.valueAtIndex(b,hfill) = s;
58 Werner 71
                break;
72
            }
73
        }
74
        // go to last filled cell...
75
        for (;h<cHDclassCount;h++) {
76
            if (m_lookup.valueAtIndex(b,h)==0)
77
                break;
78
            s=m_lookup.valueAtIndex(b,h);
79
        }
80
        // fill up the rest...
81
        for (;h<cHDclassCount;h++) {
82
            m_lookup.valueAtIndex(b,h)=s;
83
        }
401 werner 84
        if(s)
85
            max_size = std::max(max_size, s->dataSize());
58 Werner 86
    }
401 werner 87
    // distance grid
88
    if (m_distance.sizeX()<max_size) {
89
        setupDistanceGrid(max_size);
90
    }
400 werner 91
    //if (GlobalSettings::instance()->settings().paramValueBool("debugDumpStamps", false) )
92
    //    qDebug() << dump();
58 Werner 93
}
94
 
401 werner 95
void StampContainer::setupDistanceGrid(const int size)
96
{
97
    const float px_size = cPxSize;
98
    m_distance.setup(px_size, size, size);
99
    float *p=m_distance.begin();
100
    QPoint idx;
101
    for (;p!=m_distance.end();++p) {
102
        idx = m_distance.indexOf(p);
103
        *p = sqrt(double(idx.x()*idx.x()) + double(idx.y()*idx.y()))*px_size;
104
    }
105
}
64 Werner 106
 
107
 void StampContainer::addStamp(Stamp* stamp, const int cls_dbh, const int cls_hd, const float crown_radius_m, const float dbh, const float hd_value)
108
 {
33 Werner 109
    if (m_useLookup) {
357 werner 110
        if (cls_dbh<0 || cls_dbh>=cBHDclassCount || cls_hd<0 || cls_hd>=cHDclassCount)
111
            throw IException(QString("StampContainer::addStamp: Stamp out of range. dbh=%1 hd=%2.").arg(dbh).arg(hd_value));
64 Werner 112
        m_lookup.valueAtIndex(cls_dbh, cls_hd) = stamp; // save address in look up table
33 Werner 113
    } // if (useLookup)
114
 
115
    StampItem si;
64 Werner 116
    si.dbh = dbh;
33 Werner 117
    si.hd = hd_value;
47 Werner 118
    si.crown_radius = crown_radius_m;
33 Werner 119
    si.stamp = stamp;
120
    m_stamps.append(si); // store entry in list of stamps
121
 
64 Werner 122
 }
123
 
124
 
125
/** add a stamp to the internal storage.
126
    After loading the function finalizeSetup() must be called to ensure that gaps in the matrix get filled. */
65 Werner 127
void  StampContainer::addStamp(Stamp* stamp, const float dbh, const float hd_value, const float crown_radius)
64 Werner 128
{
129
    int cls_dbh, cls_hd;
130
    getKey(dbh, hd_value, cls_dbh, cls_hd); // decode dbh/hd-value
65 Werner 131
    addStamp(stamp, cls_dbh, cls_hd, crown_radius, dbh, hd_value); // dont set crownradius
33 Werner 132
}
133
 
64 Werner 134
void StampContainer::addReaderStamp(Stamp *stamp, const float crown_radius_m)
40 Werner 135
{
397 werner 136
    double rest = fmod(crown_radius_m, 1.)+0.0001;
137
    int cls_hd = int( rest * 10 ); // 0 .. 9.99999999
40 Werner 138
    if (cls_hd>=cHDclassCount)
139
        cls_hd=cHDclassCount-1;
64 Werner 140
    int cls_dbh = int(crown_radius_m);
102 Werner 141
    //qDebug() << "Readerstamp r="<< crown_radius_m<<" index dbh hd:" << cls_dbh << cls_hd;
397 werner 142
    stamp->setCrownRadius(crown_radius_m);
143
 
64 Werner 144
    // prepare special keys for reader stamps
145
    addStamp(stamp,cls_dbh, cls_hd, crown_radius_m, 0., 0.); // set crownradius, but not dbh/hd
146
}
40 Werner 147
 
148
 
149
/** retrieve a read-out-stamp. Readers depend solely on a crown radius.
150
Internally, readers are stored in the same lookup-table, but using a encoding/decoding trick.*/
151
const Stamp* StampContainer::readerStamp(const float crown_radius_m) const
152
{
153
    // Readers: from 0..10m in 50 steps???
397 werner 154
    int cls_hd = int( (fmod(crown_radius_m, 1.)+0.0001) * 10 ); // 0 .. 9.99999999
40 Werner 155
    if (cls_hd>=cHDclassCount)
156
        cls_hd=cHDclassCount-1;
157
    int cls_bhd = int(crown_radius_m);
158
    const Stamp* stamp = m_lookup(cls_bhd, cls_hd);
58 Werner 159
    if (!stamp)
160
        qDebug() << "Stamp::readerStamp(): no stamp found for radius" << crown_radius_m;
40 Werner 161
    return stamp;
162
}
163
 
33 Werner 164
/** fast access for an individual stamp using a lookup table.
165
    the dimensions of the lookup table are defined by class-constants.
166
    If stamp is not found there, the more complete list of stamps is searched. */
39 Werner 167
const Stamp* StampContainer::stamp(const float bhd_cm, const float height_m) const
33 Werner 168
{
169
 
40 Werner 170
    float hd_value = 100.f * height_m / bhd_cm;
35 Werner 171
 
64 Werner 172
    int cls_bhd, cls_hd;
173
    getKey(bhd_cm, hd_value, cls_bhd, cls_hd);
35 Werner 174
 
33 Werner 175
    // check loopup table
393 werner 176
    if (cls_bhd<cBHDclassCount && cls_bhd>=0 && cls_hd < cHDclassCount && cls_hd>=0) {
40 Werner 177
        const Stamp* stamp = m_lookup(cls_bhd, cls_hd);
178
        if (stamp)
179
            return stamp;
58 Werner 180
        qDebug() << "StampContainer::stamp(): not in list: bhd height:" << bhd_cm << height_m;
40 Werner 181
        return m_stamps.first().stamp; // default value: the first stamp in the list....
182
    }
33 Werner 183
 
184
    // extra work: search in list...
185
    //if (bhd_cm > m_maxBhd)
143 Werner 186
    if (cls_bhd<cBHDclassCount && cls_bhd>=0) {
187
        qDebug() << "HD for stamp out of range bhd " << bhd_cm << "and h="<< height_m << "(using smallest/largeset HD)";
188
        if (cls_hd>=cHDclassCount)
189
            return m_lookup(cls_bhd, cHDclassCount-1); // highest
190
        return m_lookup(cls_bhd, 0); // smallest
191
    }
33 Werner 192
    qDebug() << "No stamp defined for bhd " << bhd_cm << "and h="<< height_m;
193
    return NULL;
194
 
195
}
196
 
197
/// static factory function to create stamps with a given size
198
/// @param type indicates type of stamp
199
Stamp* StampContainer::newStamp(const Stamp::StampType type)
200
{
201
    Stamp *stamp;
202
    switch (type) {
63 Werner 203
       case Stamp::est4x4:  //qDebug() << "4x4stamp";
204
           stamp=new Stamp(4); break;
205
 
33 Werner 206
    default:
207
          stamp = new Stamp(int(type));
208
    }
209
    return stamp;
210
}
211
 
47 Werner 212
 
213
void StampContainer::attachReaderStamps(const StampContainer &source)
214
{
215
    int found=0, total=0;
216
    foreach (StampItem si, m_stamps) {
217
        const Stamp *s = source.readerStamp(si.crown_radius);
218
        si.stamp->setReader(const_cast<Stamp*>(s));
219
        if (s) found++;
220
        total++;
221
        //si.crown_radius
222
    }
223
    qDebug() << "attachReaderStamps: found" << found << "stamps of" << total;
224
}
225
 
51 Werner 226
void StampContainer::invert()
227
{
228
    StampItem  si;
229
    foreach(si, m_stamps) {
230
        Stamp *s =si.stamp;
231
        float *p = s->data();
232
        while (p!=s->end()) {
233
            *p = 1. - *p;
234
            p++;
235
        }
236
    }
237
}
99 Werner 238
/// convenience function that loads stamps directly from a single file.
239
void StampContainer::load(const QString &fileName)
240
{
241
    QFile readerfile(fileName);
102 Werner 242
    if (!readerfile.exists())
243
        throw IException(QString("The LIP stampfile %1 cannot be found!").arg(fileName));
99 Werner 244
    readerfile.open(QIODevice::ReadOnly);
245
    QDataStream rin(&readerfile);
361 werner 246
    qDebug() << "loading stamp file" << fileName;
99 Werner 247
    load(rin);
248
    readerfile.close();
249
}
51 Werner 250
 
33 Werner 251
void StampContainer::load(QDataStream &in)
252
{
253
    qint32 type;
254
    qint32 count;
400 werner 255
    float bhd, hdvalue, crownradius;
256
    quint32 magic;
257
    in >> magic;
258
    if (magic!=0xFEED0001)
259
        throw IException("StampContainer: invalid file type!");
260
    quint16 version;
261
    in >> version;
262
    if (version != 100)
263
        throw IException(QString("StampContainer: invalid file version: %1").arg(version));
264
    in.setVersion(QDataStream::Qt_4_5);
265
 
33 Werner 266
    in >> count; // read count of stamps
267
    qDebug() << count << "stamps to read";
63 Werner 268
    QString desc;
269
    in >> desc; // read textual description of stamp
270
    qDebug() << "Stamp notes:" << desc;
271
    m_desc = desc;
33 Werner 272
    for (int i=0;i<count;i++) {
273
        in >> type; // read type
274
        in >> bhd;
275
        in >> hdvalue;
47 Werner 276
        in >> crownradius;
309 werner 277
        //qDebug() << "stamp bhd hdvalue type readsum dominance type" << bhd << hdvalue << type << readsum << domvalue << type;
64 Werner 278
 
33 Werner 279
        Stamp *stamp = newStamp( Stamp::StampType(type) );
280
        stamp->load(in);
400 werner 281
 
65 Werner 282
        if (bhd > 0.f)
283
            addStamp(stamp, bhd, hdvalue, crownradius);
284
        else
64 Werner 285
            addReaderStamp(stamp, crownradius);
33 Werner 286
    }
58 Werner 287
    finalizeSetup(); // fill up lookup grid
102 Werner 288
    if (count==0)
289
        throw IException("no stamps loaded!");
33 Werner 290
}
291
/** Saves all stamps of the container to a binary stream.
34 Werner 292
  Format: * count of stamps (int32)
63 Werner 293
          * a string containing a description (free text) (QString)
33 Werner 294
      for each stamp:
295
      - type (enum Stamp::StampType, 4, 8, 12, 16, ...)
296
      - bhd of the stamp (float)
42 Werner 297
      - hd-value of the tree (float)
47 Werner 298
      - crownradius of the stamp (float) in [m]
43 Werner 299
      - the sum of values in the center of the stamp (used for read out)
300
      - the dominance value of the stamp
33 Werner 301
      - individual data values (Stamp::save() / Stamp::load())
302
      -- offset (int) no. of pixels away from center
303
      -- list of data items (type*type items)
34 Werner 304
      see also stamp creation (FonStudio application, MainWindow.cpp).
33 Werner 305
*/
306
void StampContainer::save(QDataStream &out)
307
{
308
    qint32 type;
34 Werner 309
    qint32 size = m_stamps.count();
400 werner 310
    out << (quint32)0xFEED0001; // magic number
311
    out << (quint16)100; // version
312
    out.setVersion(QDataStream::Qt_4_5);
313
 
63 Werner 314
    out << size; // count of stamps...
315
    out << m_desc; // text...
33 Werner 316
    foreach(StampItem si, m_stamps) {
40 Werner 317
        type = si.stamp->dataSize();
35 Werner 318
        out << type;
64 Werner 319
        out << si.dbh;
35 Werner 320
        out << si.hd;
47 Werner 321
        out << si.crown_radius;
34 Werner 322
        si.stamp->save(out);
33 Werner 323
    }
34 Werner 324
 
33 Werner 325
}
35 Werner 326
 
327
QString StampContainer::dump()
328
{
329
    QString res;
330
    QString line;
331
    int x,y;
332
    int maxidx;
333
    foreach (StampItem si, m_stamps) {
334
        line = QString("%5 -> size: %1 offset: %2 dbh: %3 hd-ratio: %4\r\n")
335
               .arg(sqrt(si.stamp->count())).arg(si.stamp->offset())
64 Werner 336
               .arg(si.dbh).arg(si.hd).arg((int)si.stamp, 0, 16);
35 Werner 337
        // add data....
338
        maxidx = 2*si.stamp->offset() + 1;
41 Werner 339
        for (y=0;y<maxidx;++y)  {
340
            for (x=0;x<maxidx;++x)  {
35 Werner 341
                line+= QString::number(*si.stamp->data(x,y)) + " ";
342
            }
343
            line+="\r\n";
344
        }
345
        line+="==============================================\r\n";
346
        res+=line;
347
    }
36 Werner 348
    res+= "Dump of lookup map\r\n=====================\r\n";
35 Werner 349
    for (Stamp **s = m_lookup.begin(); s!=m_lookup.end(); ++s) {
350
        if (*s)
36 Werner 351
         res += QString("P: x/y: %1/%2 addr %3\r\n").arg( m_lookup.indexOf(s).x()).arg(m_lookup.indexOf(s).y()).arg((int)*s, 0, 16);
35 Werner 352
    }
36 Werner 353
    res+="\r\n" + gridToString(m_lookup);
35 Werner 354
    return res;
355
}