Rev 406 | Rev 410 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 406 | Rev 407 | ||
---|---|---|---|
Line 41... | Line 41... | ||
41 | mOpacity=mFoliageMass=mWoodyMass=mCoarseRootMass=mFineRootMass=mLeafArea=0.; |
41 | mOpacity=mFoliageMass=mWoodyMass=mCoarseRootMass=mFineRootMass=mLeafArea=0.; |
42 | mDbhDelta=mNPPReserve=mLRI=mStressIndex=0.; |
42 | mDbhDelta=mNPPReserve=mLRI=mStressIndex=0.; |
43 | mLightResponse = 0.; |
43 | mLightResponse = 0.; |
44 | mId = m_nextId++; |
44 | mId = m_nextId++; |
45 | m_statCreated++; |
45 | m_statCreated++; |
- | 46 | }
|
|
- | 47 | ||
- | 48 | float Tree::crownRadius() const |
|
- | 49 | {
|
|
- | 50 | Q_ASSERT(mStamp!=0); |
|
- | 51 | return mStamp->crownRadius(); |
|
46 | }
|
52 | }
|
47 | 53 | ||
48 | void Tree::setGrid(FloatGrid* gridToStamp, Grid<HeightGridValue> *dominanceGrid) |
54 | void Tree::setGrid(FloatGrid* gridToStamp, Grid<HeightGridValue> *dominanceGrid) |
49 | {
|
55 | {
|
50 | mGrid = gridToStamp; mHeightGrid = dominanceGrid; |
56 | mGrid = gridToStamp; mHeightGrid = dominanceGrid; |
Line 120... | Line 126... | ||
120 | float value, z, z_zstar; |
126 | float value, z, z_zstar; |
121 | int gr_stamp = mStamp->size(); |
127 | int gr_stamp = mStamp->size(); |
122 | int grid_x, grid_y; |
128 | int grid_x, grid_y; |
123 | float *grid_value_ptr; |
129 | float *grid_value_ptr; |
124 | if (!mGrid->isIndexValid(pos) || !mGrid->isIndexValid(pos+QPoint(gr_stamp, gr_stamp))) { |
130 | if (!mGrid->isIndexValid(pos) || !mGrid->isIndexValid(pos+QPoint(gr_stamp, gr_stamp))) { |
125 | // todo: in this case we should use another algorithm!!!
|
- | |
- | 131 | // this should not happen because of the buffer
|
|
126 | return; |
132 | return; |
127 | }
|
133 | }
|
128 | grid_y = pos.y(); |
134 | grid_y = pos.y(); |
129 | for (y=0;y<gr_stamp; ++y) { |
135 | for (y=0;y<gr_stamp; ++y) { |
130 | 136 | ||
Line 184... | Line 190... | ||
184 | float *grid_value; |
190 | float *grid_value; |
185 | if (!mGrid->isIndexValid(pos) || !mGrid->isIndexValid(pos+QPoint(gr_stamp, gr_stamp))) { |
191 | if (!mGrid->isIndexValid(pos) || !mGrid->isIndexValid(pos+QPoint(gr_stamp, gr_stamp))) { |
186 | // todo: in this case we should use another algorithm!!! necessary????
|
192 | // todo: in this case we should use another algorithm!!! necessary????
|
187 | return; |
193 | return; |
188 | }
|
194 | }
|
189 | - | ||
- | 195 | float z, z_zstar; |
|
190 | int xt, yt; // wraparound coordinates |
196 | int xt, yt; // wraparound coordinates |
191 | for (y=0;y<gr_stamp; ++y) { |
197 | for (y=0;y<gr_stamp; ++y) { |
192 | grid_y = pos.y() + y; |
198 | grid_y = pos.y() + y; |
193 | yt = torusIndex(grid_y, cPxPerRU,bufferOffset, ru_offset.y()); // 50 cells per 100m |
199 | yt = torusIndex(grid_y, cPxPerRU,bufferOffset, ru_offset.y()); // 50 cells per 100m |
194 | for (x=0;x<gr_stamp;++x) { |
200 | for (x=0;x<gr_stamp;++x) { |
195 | // suppose there is no stamping outside
|
201 | // suppose there is no stamping outside
|
196 | grid_x = pos.x() + x; |
202 | grid_x = pos.x() + x; |
197 | xt = torusIndex(grid_x,cPxPerRU,bufferOffset, ru_offset.x()); |
203 | xt = torusIndex(grid_x,cPxPerRU,bufferOffset, ru_offset.x()); |
198 | 204 | ||
199 | local_dom = mHeightGrid->valueAtIndex(xt/cPxPerHeight,yt/cPxPerHeight).height; |
205 | local_dom = mHeightGrid->valueAtIndex(xt/cPxPerHeight,yt/cPxPerHeight).height; |
- | 206 | ||
- | 207 | z = std::max(mHeight - (*mStamp).distanceToCenter(x,y), 0.f); // distance to center = height (45° line) |
|
- | 208 | z_zstar = (z>=local_dom)?1.f:z/local_dom; |
|
200 | value = (*mStamp)(x,y); // stampvalue |
209 | value = (*mStamp)(x,y); // stampvalue |
201 | value = 1. - value*mOpacity / local_dom; // calculated value |
- | |
- | 210 | value = 1. - value*mOpacity * z_zstar; // calculated value |
|
- | 211 | // old: value = 1. - value*mOpacity / local_dom; // calculated value
|
|
202 | value = qMax(value, 0.02f); // limit value |
212 | value = qMax(value, 0.02f); // limit value |
203 | 213 | ||
204 | grid_value = mGrid->ptr(xt, yt); // use wraparound coordinates |
214 | grid_value = mGrid->ptr(xt, yt); // use wraparound coordinates |
205 | *grid_value *= value; |
215 | *grid_value *= value; |
206 | }
|
216 | }
|
Line 271... | Line 281... | ||
271 | // for (iy=-ringcount; iy<=+ringcount; iy++) {
|
281 | // for (iy=-ringcount; iy<=+ringcount; iy++) {
|
272 | // ring = qMax(abs(ix), abs(iy));
|
282 | // ring = qMax(abs(ix), abs(iy));
|
273 | // QPoint pos(ix+p.x(), iy+p.y());
|
283 | // QPoint pos(ix+p.x(), iy+p.y());
|
274 | // if (mHeightGrid->isIndexValid(pos)) {
|
284 | // if (mHeightGrid->isIndexValid(pos)) {
|
275 | // float &rHGrid = mHeightGrid->valueAtIndex(pos).height;
|
285 | // float &rHGrid = mHeightGrid->valueAtIndex(pos).height;
|
- | 286 | // if (rHGrid > mHeight) // skip calculation if grid is higher than tree
|
|
- | 287 | // continue;
|
|
- | 288 | // int direction = 4 + (ix?(ix<0?-3:3):0) + (iy?(iy<0?-1:1):0); // 4 + 3*sgn(x) + sgn(y)
|
|
- | 289 | // hdom = mHeight - dist[direction];
|
|
- | 290 | // if (ring>1)
|
|
- | 291 | // hdom -= (ring-1)*10;
|
|
- | 292 | //
|
|
- | 293 | // rHGrid = qMax(rHGrid, hdom); // write value
|
|
- | 294 | // } // is valid
|
|
- | 295 | // } // for (y)
|
|
- | 296 | }
|
|
- | 297 | ||
- | 298 | void Tree::heightGrid_torus() |
|
- | 299 | {
|
|
- | 300 | // height of Z*
|
|
- | 301 | ||
- | 302 | QPoint p = QPoint(mPositionIndex.x()/cPxPerHeight, mPositionIndex.y()/cPxPerHeight); // pos of tree on height grid |
|
- | 303 | int bufferOffset = mHeightGrid->indexAt(QPointF(0.,0.)).x(); // offset of buffer (i.e.: size of buffer in height-pixels) |
|
- | 304 | p.setX((p.x()-bufferOffset)%10 + bufferOffset); // 10: 10 x 10m pixeln in 100m |
|
- | 305 | p.setY((p.y()-bufferOffset)%10 + bufferOffset); |
|
- | 306 | ||
- | 307 | ||
- | 308 | // torus coordinates: ru_offset = coords of lower left corner of 1ha patch
|
|
- | 309 | QPoint ru_offset =QPoint(mPositionIndex.x()/cPxPerHeight - p.x(), mPositionIndex.y()/cPxPerHeight - p.y()); |
|
- | 310 | ||
- | 311 | // count trees that are on height-grid cells (used for stockable area)
|
|
- | 312 | HeightGridValue &v = mHeightGrid->valueAtIndex(torusIndex(p.x(),10,bufferOffset,ru_offset.x()), |
|
- | 313 | torusIndex(p.y(),10,bufferOffset,ru_offset.y())); |
|
- | 314 | v.increaseCount(); |
|
- | 315 | v.height = qMax(v.height, mHeight); |
|
- | 316 | ||
- | 317 | ||
- | 318 | int r = mStamp->reader()->offset(); // distance between edge and the center pixel. e.g.: if r = 2 -> stamp=5x5 |
|
- | 319 | int index_eastwest = mPositionIndex.x() % cPxPerHeight; // 4: very west, 0 east edge |
|
- | 320 | int index_northsouth = mPositionIndex.y() % cPxPerHeight; // 4: northern edge, 0: southern edge |
|
- | 321 | if (index_eastwest - r < 0) { // east |
|
- | 322 | HeightGridValue &v = mHeightGrid->valueAtIndex(torusIndex(p.x()-1,10,bufferOffset,ru_offset.x()), |
|
- | 323 | torusIndex(p.y(),10,bufferOffset,ru_offset.y())); |
|
- | 324 | v.height = qMax(v.height, mHeight-5); |
|
- | 325 | }
|
|
- | 326 | if (index_eastwest + r >= cPxPerHeight) { // west |
|
- | 327 | HeightGridValue &v = mHeightGrid->valueAtIndex(torusIndex(p.x()+1,10,bufferOffset,ru_offset.x()), |
|
- | 328 | torusIndex(p.y(),10,bufferOffset,ru_offset.y())); |
|
- | 329 | v.height = qMax(v.height, mHeight-5); |
|
- | 330 | }
|
|
- | 331 | if (index_northsouth - r < 0) { // south |
|
- | 332 | HeightGridValue &v = mHeightGrid->valueAtIndex(torusIndex(p.x(),10,bufferOffset,ru_offset.x()), |
|
- | 333 | torusIndex(p.y()-1,10,bufferOffset,ru_offset.y())); |
|
- | 334 | v.height = qMax(v.height, mHeight-5); |
|
- | 335 | }
|
|
- | 336 | if (index_northsouth + r >= cPxPerHeight) { // north |
|
- | 337 | HeightGridValue &v = mHeightGrid->valueAtIndex(torusIndex(p.x(),10,bufferOffset,ru_offset.x()), |
|
- | 338 | torusIndex(p.y()+1,10,bufferOffset,ru_offset.y())); |
|
- | 339 | v.height = qMax(v.height, mHeight-5); |
|
- | 340 | }
|
|
- | 341 | ||
- | 342 | ||
- | 343 | ||
- | 344 | ||
- | 345 | // int index_eastwest = mPositionIndex.x() % cPxPerHeight; // 4: very west, 0 east edge
|
|
- | 346 | // int index_northsouth = mPositionIndex.y() % cPxPerHeight; // 4: northern edge, 0: southern edge
|
|
- | 347 | // int dist[9];
|
|
- | 348 | // dist[3] = index_northsouth * 2 + 1; // south
|
|
- | 349 | // dist[1] = index_eastwest * 2 + 1; // west
|
|
- | 350 | // dist[5] = 10 - dist[3]; // north
|
|
- | 351 | // dist[7] = 10 - dist[1]; // east
|
|
- | 352 | // dist[8] = qMax(dist[5], dist[7]); // north-east
|
|
- | 353 | // dist[6] = qMax(dist[3], dist[7]); // south-east
|
|
- | 354 | // dist[0] = qMax(dist[3], dist[1]); // south-west
|
|
- | 355 | // dist[2] = qMax(dist[5], dist[1]); // north-west
|
|
- | 356 | // dist[4] = 0; // center cell
|
|
- | 357 | // /* the scheme of indices is as follows: if sign(ix)= -1, if ix<0, 0 for ix=0, 1 for ix>0 (detto iy), then:
|
|
- | 358 | // index = 4 + 3*sign(ix) + sign(iy) transforms combinations of directions to unique ids (0..8), which are used above.
|
|
- | 359 | // e.g.: sign(ix) = -1, sign(iy) = 1 (=north-west) -> index = 4 + -3 + 1 = 2
|
|
- | 360 | // */
|
|
- | 361 | //
|
|
- | 362 | //
|
|
- | 363 | // int ringcount = int(floor(mHeight / cellsize)) + 1;
|
|
- | 364 | // int ix, iy;
|
|
- | 365 | // int ring;
|
|
- | 366 | // float hdom;
|
|
- | 367 | // for (ix=-ringcount;ix<=ringcount;ix++)
|
|
- | 368 | // for (iy=-ringcount; iy<=+ringcount; iy++) {
|
|
- | 369 | // ring = qMax(abs(ix), abs(iy));
|
|
- | 370 | // QPoint pos(ix+p.x(), iy+p.y());
|
|
- | 371 | // QPoint p_torus(torusIndex(pos.x(),10,bufferOffset,ru_offset.x()),
|
|
- | 372 | // torusIndex(pos.y(),10,bufferOffset,ru_offset.y()));
|
|
- | 373 | // if (mHeightGrid->isIndexValid(p_torus)) {
|
|
- | 374 | // float &rHGrid = mHeightGrid->valueAtIndex(p_torus.x(),p_torus.y()).height;
|
|
276 | // if (rHGrid > mHeight) // skip calculation if grid is higher than tree
|
375 | // if (rHGrid > mHeight) // skip calculation if grid is higher than tree
|
277 | // continue;
|
376 | // continue;
|
278 | // int direction = 4 + (ix?(ix<0?-3:3):0) + (iy?(iy<0?-1:1):0); // 4 + 3*sgn(x) + sgn(y)
|
377 | // int direction = 4 + (ix?(ix<0?-3:3):0) + (iy?(iy<0?-1:1):0); // 4 + 3*sgn(x) + sgn(y)
|
279 | // hdom = mHeight - dist[direction];
|
378 | // hdom = mHeight - dist[direction];
|
280 | // if (ring>1)
|
379 | // if (ring>1)
|
Line 348... | Line 447... | ||
348 | mRU->addWLA(mLeafArea, mLRI); |
447 | mRU->addWLA(mLeafArea, mLRI); |
349 | 448 | ||
350 | 449 | ||
351 | //qDebug() << "Tree #"<< id() << "value" << sum << "Impact" << mImpact;
|
450 | //qDebug() << "Tree #"<< id() << "value" << sum << "Impact" << mImpact;
|
352 | //mRU->addWLA(mLRI*mLeafArea, mLeafArea);
|
451 | //mRU->addWLA(mLRI*mLeafArea, mLeafArea);
|
353 | }
|
- | |
354 | - | ||
355 | void Tree::heightGrid_torus() |
- | |
356 | {
|
- | |
357 | // height of Z*
|
- | |
358 | const float cellsize = mHeightGrid->cellsize(); |
- | |
359 | - | ||
360 | QPoint p = QPoint(mPositionIndex.x()/cPxPerHeight, mPositionIndex.y()/cPxPerHeight); // pos of tree on height grid |
- | |
361 | int bufferOffset = mHeightGrid->indexAt(QPointF(0.,0.)).x(); // offset of buffer |
- | |
362 | - | ||
363 | // count trees that are on height-grid cells (used for stockable area)
|
- | |
364 | mHeightGrid->valueAtIndex(p).increaseCount(); |
- | |
365 | - | ||
366 | // torus coordinates
|
- | |
367 | p.setX((p.x()-bufferOffset)%10 + bufferOffset); |
- | |
368 | p.setY((p.y()-bufferOffset)%10 + bufferOffset); |
- | |
369 | QPoint ru_offset =QPoint(mPositionIndex.x()/cPxPerHeight - p.x(), mPositionIndex.y()/cPxPerHeight - p.y()); |
- | |
370 | - | ||
371 | int index_eastwest = mPositionIndex.x() % cPxPerHeight; // 4: very west, 0 east edge |
- | |
372 | int index_northsouth = mPositionIndex.y() % cPxPerHeight; // 4: northern edge, 0: southern edge |
- | |
373 | int dist[9]; |
- | |
374 | dist[3] = index_northsouth * 2 + 1; // south |
- | |
375 | dist[1] = index_eastwest * 2 + 1; // west |
- | |
376 | dist[5] = 10 - dist[3]; // north |
- | |
377 | dist[7] = 10 - dist[1]; // east |
- | |
378 | dist[8] = qMax(dist[5], dist[7]); // north-east |
- | |
379 | dist[6] = qMax(dist[3], dist[7]); // south-east |
- | |
380 | dist[0] = qMax(dist[3], dist[1]); // south-west |
- | |
381 | dist[2] = qMax(dist[5], dist[1]); // north-west |
- | |
382 | dist[4] = 0; // center cell |
- | |
383 | /* the scheme of indices is as follows: if sign(ix)= -1, if ix<0, 0 for ix=0, 1 for ix>0 (detto iy), then:
|
- | |
384 | index = 4 + 3*sign(ix) + sign(iy) transforms combinations of directions to unique ids (0..8), which are used above.
|
- | |
385 | e.g.: sign(ix) = -1, sign(iy) = 1 (=north-west) -> index = 4 + -3 + 1 = 2
|
- | |
386 | */
|
- | |
387 | - | ||
388 | - | ||
389 | int ringcount = int(floor(mHeight / cellsize)) + 1; |
- | |
390 | int ix, iy; |
- | |
391 | int ring; |
- | |
392 | float hdom; |
- | |
393 | for (ix=-ringcount;ix<=ringcount;ix++) |
- | |
394 | for (iy=-ringcount; iy<=+ringcount; iy++) { |
- | |
395 | ring = qMax(abs(ix), abs(iy)); |
- | |
396 | QPoint pos(ix+p.x(), iy+p.y()); |
- | |
397 | QPoint p_torus(torusIndex(pos.x(),10,bufferOffset,ru_offset.x()), |
- | |
398 | torusIndex(pos.y(),10,bufferOffset,ru_offset.y())); |
- | |
399 | if (mHeightGrid->isIndexValid(p_torus)) { |
- | |
400 | float &rHGrid = mHeightGrid->valueAtIndex(p_torus.x(),p_torus.y()).height; |
- | |
401 | if (rHGrid > mHeight) // skip calculation if grid is higher than tree |
- | |
402 | continue; |
- | |
403 | int direction = 4 + (ix?(ix<0?-3:3):0) + (iy?(iy<0?-1:1):0); // 4 + 3*sgn(x) + sgn(y) |
- | |
404 | hdom = mHeight - dist[direction]; |
- | |
405 | if (ring>1) |
- | |
406 | hdom -= (ring-1)*10; |
- | |
407 | - | ||
408 | rHGrid = qMax(rHGrid, hdom); // write value |
- | |
409 | } // is valid |
- | |
410 | } // for (y) |
- | |
411 | }
|
452 | }
|
412 | 453 | ||
413 | /// Torus version of read stamp (glued edges)
|
454 | /// Torus version of read stamp (glued edges)
|
414 | void Tree::readLIF_torus() |
455 | void Tree::readLIF_torus() |
415 | {
|
456 | {
|
Line 434... | Line 475... | ||
434 | 475 | ||
435 | int x,y; |
476 | int x,y; |
436 | double sum=0.; |
477 | double sum=0.; |
437 | double value, own_value; |
478 | double value, own_value; |
438 | float *grid_value; |
479 | float *grid_value; |
- | 480 | float z, z_zstar; |
|
439 | int reader_size = reader->size(); |
481 | int reader_size = reader->size(); |
440 | int rx = pos_reader.x(); |
482 | int rx = pos_reader.x(); |
441 | int ry = pos_reader.y(); |
483 | int ry = pos_reader.y(); |
442 | int xt, yt; // wrapped coords |
484 | int xt, yt; // wrapped coords |
443 | 485 | ||
444 | for (y=0;y<reader_size; ++y) { |
486 | for (y=0;y<reader_size; ++y) { |
445 | yt = torusIndex(ry+y,cPxPerRU, bufferOffset, ru_offset.y()); |
487 | yt = torusIndex(ry+y,cPxPerRU, bufferOffset, ru_offset.y()); |
446 | for (x=0;x<reader_size;++x) { |
488 | for (x=0;x<reader_size;++x) { |
447 | xt = torusIndex(rx+x,cPxPerRU, bufferOffset, ru_offset.x()); |
489 | xt = torusIndex(rx+x,cPxPerRU, bufferOffset, ru_offset.x()); |
448 | grid_value = mGrid->ptr(xt,yt); |
490 | grid_value = mGrid->ptr(xt,yt); |
449 | //p = pos_reader + QPoint(x,y);
|
- | |
450 | //if (m_grid->isIndexValid(p)) {
|
- | |
- | 491 | ||
451 | local_dom = mHeightGrid->valueAtIndex(xt/cPxPerHeight, yt/cPxPerHeight).height; // ry: gets ++ed in outer loop, rx not |
492 | local_dom = mHeightGrid->valueAtIndex(xt/cPxPerHeight, yt/cPxPerHeight).height; // ry: gets ++ed in outer loop, rx not |
452 | //local_dom = m_dominanceGrid->valueAt( m_grid->cellCoordinates(p) );
|
- | |
- | 493 | z = std::max(mHeight - reader->distanceToCenter(x,y), 0.f); // distance to center = height (45° line) |
|
- | 494 | z_zstar = (z>=local_dom)?1.f:z/local_dom; |
|
453 | 495 | ||
454 | own_value = 1. - mStamp->offsetValue(x,y,d_offset)*mOpacity / local_dom; // old: dom_height; |
- | |
- | 496 | own_value = 1. - mStamp->offsetValue(x,y,d_offset)*mOpacity * z_zstar; |
|
- | 497 | // old: own_value = 1. - mStamp->offsetValue(x,y,d_offset)*mOpacity / local_dom; // old: dom_height;
|
|
455 | own_value = qMax(own_value, 0.02); |
498 | own_value = qMax(own_value, 0.02); |
456 | value = *grid_value / own_value; // remove impact of focal tree |
- | |
- | 499 | value = *grid_value++ / own_value; // remove impact of focal tree |
|
- | 500 | ||
457 | // debug for one tree in HJA
|
501 | // debug for one tree in HJA
|
458 | //if (id()==178020)
|
502 | //if (id()==178020)
|
459 | // qDebug() << x << y << xt << yt << *grid_value << local_dom << own_value << value << (*reader)(x,y);
|
503 | // qDebug() << x << y << xt << yt << *grid_value << local_dom << own_value << value << (*reader)(x,y);
|
460 | //if (_isnan(value))
|
504 | //if (_isnan(value))
|
461 | // qDebug() << "isnan" << id();
|
505 | // qDebug() << "isnan" << id();
|