Subversion Repositories public iLand

Rev

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