Subversion Repositories public iLand

Rev

Rev 102 | Rev 143 | 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);
58 Werner 135
    if (!stamp)
136
        qDebug() << "Stamp::readerStamp(): no stamp found for radius" << crown_radius_m;
40 Werner 137
    return stamp;
138
}
139
 
33 Werner 140
/** fast access for an individual stamp using a lookup table.
141
    the dimensions of the lookup table are defined by class-constants.
142
    If stamp is not found there, the more complete list of stamps is searched. */
39 Werner 143
const Stamp* StampContainer::stamp(const float bhd_cm, const float height_m) const
33 Werner 144
{
145
 
40 Werner 146
    float hd_value = 100.f * height_m / bhd_cm;
35 Werner 147
 
64 Werner 148
    int cls_bhd, cls_hd;
149
    getKey(bhd_cm, hd_value, cls_bhd, cls_hd);
35 Werner 150
 
33 Werner 151
    // check loopup table
40 Werner 152
    if (cls_bhd<cBHDclassCount && cls_bhd>=0 && cls_hd < cHDclassCount && cls_bhd>=0) {
153
        const Stamp* stamp = m_lookup(cls_bhd, cls_hd);
154
        if (stamp)
155
            return stamp;
58 Werner 156
        qDebug() << "StampContainer::stamp(): not in list: bhd height:" << bhd_cm << height_m;
40 Werner 157
        return m_stamps.first().stamp; // default value: the first stamp in the list....
158
    }
33 Werner 159
 
160
    // extra work: search in list...
161
    //if (bhd_cm > m_maxBhd)
162
    qDebug() << "No stamp defined for bhd " << bhd_cm << "and h="<< height_m;
163
    return NULL;
164
 
165
}
166
 
167
/// static factory function to create stamps with a given size
168
/// @param type indicates type of stamp
169
Stamp* StampContainer::newStamp(const Stamp::StampType type)
170
{
171
    Stamp *stamp;
172
    switch (type) {
63 Werner 173
       case Stamp::est4x4:  //qDebug() << "4x4stamp";
174
           stamp=new Stamp(4); break;
175
 
33 Werner 176
    default:
177
          stamp = new Stamp(int(type));
178
    }
179
    return stamp;
180
}
181
 
47 Werner 182
 
183
void StampContainer::attachReaderStamps(const StampContainer &source)
184
{
185
    int found=0, total=0;
186
    foreach (StampItem si, m_stamps) {
187
        const Stamp *s = source.readerStamp(si.crown_radius);
188
        si.stamp->setReader(const_cast<Stamp*>(s));
189
        if (s) found++;
190
        total++;
191
        //si.crown_radius
192
    }
193
    qDebug() << "attachReaderStamps: found" << found << "stamps of" << total;
194
}
195
 
51 Werner 196
void StampContainer::invert()
197
{
198
    StampItem  si;
199
    foreach(si, m_stamps) {
200
        Stamp *s =si.stamp;
201
        float *p = s->data();
202
        while (p!=s->end()) {
203
            *p = 1. - *p;
204
            p++;
205
        }
206
    }
207
}
99 Werner 208
/// convenience function that loads stamps directly from a single file.
209
void StampContainer::load(const QString &fileName)
210
{
211
    QFile readerfile(fileName);
102 Werner 212
    if (!readerfile.exists())
213
        throw IException(QString("The LIP stampfile %1 cannot be found!").arg(fileName));
99 Werner 214
    readerfile.open(QIODevice::ReadOnly);
215
    QDataStream rin(&readerfile);
216
    load(rin);
217
    readerfile.close();
218
}
51 Werner 219
 
33 Werner 220
void StampContainer::load(QDataStream &in)
221
{
222
    qint32 type;
223
    qint32 count;
47 Werner 224
    float bhd, hdvalue, readsum, domvalue, crownradius;
33 Werner 225
    in >> count; // read count of stamps
226
    qDebug() << count << "stamps to read";
63 Werner 227
    QString desc;
228
    in >> desc; // read textual description of stamp
229
    qDebug() << "Stamp notes:" << desc;
230
    m_desc = desc;
33 Werner 231
    for (int i=0;i<count;i++) {
232
        in >> type; // read type
233
        in >> bhd;
234
        in >> hdvalue;
47 Werner 235
        in >> crownradius;
42 Werner 236
        in >> readsum;
43 Werner 237
        in >> domvalue;
63 Werner 238
        //qDebug() << "stamp bhd hdvalue type readsum dominance" << bhd << hdvalue << type << readsum << domvalue;
64 Werner 239
 
33 Werner 240
        Stamp *stamp = newStamp( Stamp::StampType(type) );
241
        stamp->load(in);
42 Werner 242
        stamp->setReadSum(readsum);
43 Werner 243
        stamp->setDominanceValue(domvalue);
65 Werner 244
        if (bhd > 0.f)
245
            addStamp(stamp, bhd, hdvalue, crownradius);
246
        else
64 Werner 247
            addReaderStamp(stamp, crownradius);
33 Werner 248
    }
58 Werner 249
    finalizeSetup(); // fill up lookup grid
102 Werner 250
    if (count==0)
251
        throw IException("no stamps loaded!");
33 Werner 252
}
253
/** Saves all stamps of the container to a binary stream.
34 Werner 254
  Format: * count of stamps (int32)
63 Werner 255
          * a string containing a description (free text) (QString)
33 Werner 256
      for each stamp:
257
      - type (enum Stamp::StampType, 4, 8, 12, 16, ...)
258
      - bhd of the stamp (float)
42 Werner 259
      - hd-value of the tree (float)
47 Werner 260
      - crownradius of the stamp (float) in [m]
43 Werner 261
      - the sum of values in the center of the stamp (used for read out)
262
      - the dominance value of the stamp
33 Werner 263
      - individual data values (Stamp::save() / Stamp::load())
264
      -- offset (int) no. of pixels away from center
265
      -- list of data items (type*type items)
34 Werner 266
      see also stamp creation (FonStudio application, MainWindow.cpp).
33 Werner 267
*/
268
void StampContainer::save(QDataStream &out)
269
{
270
    qint32 type;
34 Werner 271
    qint32 size = m_stamps.count();
63 Werner 272
    out << size; // count of stamps...
273
    out << m_desc; // text...
33 Werner 274
    foreach(StampItem si, m_stamps) {
40 Werner 275
        type = si.stamp->dataSize();
35 Werner 276
        out << type;
64 Werner 277
        out << si.dbh;
35 Werner 278
        out << si.hd;
47 Werner 279
        out << si.crown_radius;
42 Werner 280
        out << si.stamp->readSum();
43 Werner 281
        out << si.stamp->dominanceValue();
34 Werner 282
        si.stamp->save(out);
33 Werner 283
    }
34 Werner 284
 
33 Werner 285
}
35 Werner 286
 
287
QString StampContainer::dump()
288
{
289
    QString res;
290
    QString line;
291
    int x,y;
292
    int maxidx;
293
    foreach (StampItem si, m_stamps) {
294
        line = QString("%5 -> size: %1 offset: %2 dbh: %3 hd-ratio: %4\r\n")
295
               .arg(sqrt(si.stamp->count())).arg(si.stamp->offset())
64 Werner 296
               .arg(si.dbh).arg(si.hd).arg((int)si.stamp, 0, 16);
35 Werner 297
        // add data....
298
        maxidx = 2*si.stamp->offset() + 1;
41 Werner 299
        for (y=0;y<maxidx;++y)  {
300
            for (x=0;x<maxidx;++x)  {
35 Werner 301
                line+= QString::number(*si.stamp->data(x,y)) + " ";
302
            }
303
            line+="\r\n";
304
        }
305
        line+="==============================================\r\n";
306
        res+=line;
307
    }
36 Werner 308
    res+= "Dump of lookup map\r\n=====================\r\n";
35 Werner 309
    for (Stamp **s = m_lookup.begin(); s!=m_lookup.end(); ++s) {
310
        if (*s)
36 Werner 311
         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 312
    }
36 Werner 313
    res+="\r\n" + gridToString(m_lookup);
35 Werner 314
    return res;
315
}