Subversion Repositories public iLand

Rev

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