Rev 25 |
Rev 27 |
Go to most recent revision |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
#include "lightroom.h"
#include "tools/helper.h"
LightRoom::LightRoom()
{
m_roomObject = 0;
}
/** setup routine.
sets up datastructures (3d space, hemi grids)
@param size_x count of cells in x direction
@param size_y count of cells in y direction
@param size_z count of cells in z direction
@param cellsize metric length of cells (used for all 3 dimensions).
@param hemigridsize size of hemigrid-cells (in degrees).
@param latitude lat. in degrees.
@param diffus_frac fraction [0..1] of diffus radiation of global radiation. */
void LightRoom::setup(const int size_x, const int size_y, const int size_z,
const double cellsize, const double hemigridsize,
const double latitude, const double diffus_frac)
{
DebugTimer t1("setup of lightroom");
m_countX = size_x; m_countY=size_y; m_countZ=size_z;
m_cellsize = cellsize;
if (m_countX%2==0) m_countX++; // make uneven
if (m_countY%2==0) m_countY++;
QRectF rect(-m_countX/2*cellsize, -m_countY/2*cellsize, m_countX*cellsize, m_countY*cellsize);
m_2dvalues.setup(rect, cellsize);
m_2dvalues.initialize(0.);
m_3dvalues.setup(rect, cellsize);
// setup room
int x,y;
for (x=0;x<m_countX;x++)
for (y=0;y<m_countY;y++)
m_3dvalues.valueAtIndex(QPoint(x,y)).resize(size_z);
// setup hemigrids
SolarRadiation solar;
solar.setLatidude(latitude); // austria
solar.setVegetationPeriod(0,367); // no. veg. period
solar.setDiffusRadFraction(diffus_frac); // 50% diffuse radiation
// calculate global radiation values
DebugTimer t2("calculate solar radiation matrix");
solar.calculateRadMatrix(hemigridsize, m_solarGrid);
t2.showElapsed();
m_shadowGrid.setup(hemigridsize); // setup size
}
double LightRoom::calculateGridAtPoint(const double p_x, const double p_y, const double p_z)
{
if (!m_roomObject)
return 0;
// check feasibility
if (m_roomObject->noHitGuaranteed(p_x, p_y, p_z)) {
qDebug()<<"skipped";
return 0;
}
m_shadowGrid.clear(0.);
// start with 45°
int ie = m_shadowGrid.indexElevation(RAD(45));
int ia = 0;
int max_a = m_shadowGrid.matrixCountAzimuth();
int max_e = m_shadowGrid.matrixCountElevation();
double elevation, azimuth;
bool hit;
int c_hit = 0;
int c_test = 0;
for (;ie<max_e;ie++){
for (ia=0;ia<max_a;ia++) {
azimuth = m_shadowGrid.azimuth(ia);
elevation = m_shadowGrid.elevation(ie);
hit = m_roomObject->hittest(p_x, p_y, p_z,azimuth,elevation);
//qDebug() << "testing azimuth" << GRAD(azimuth) << "elevation" << GRAD(elevation)<<"hit"<<hit;
c_test++;
if (hit) {
m_shadowGrid.rGetByIndex(ia, ie) = 1.;
c_hit++;
}
}
}
double ratio = c_hit / double(c_test);
qDebug() << "tested"<< c_test<<"hit count:" << c_hit<<"ratio"<<c_hit/double(c_test)<<"total sum"<<m_shadowGrid.getSum();
return ratio; // TODO: the global radiation is not calculated!!!!!
}
void LightRoom::calculateFullGrid()
{
QVector<float> *v = m_3dvalues.begin();
QVector<float> *vend = m_3dvalues.end();
int z;
QPoint pindex;
QPointF coord;
double hit_ratio;
DebugTimer t("calculate full grid");
int c=0;
while (v!=vend) {
pindex = m_3dvalues.indexOf(v);
coord = m_3dvalues.getCellCoordinates(pindex);
for (z=0;z<m_countZ;z++) {
hit_ratio = calculateGridAtPoint(coord.x(), coord.y(), z*m_cellsize);
(*v)[z] = hit_ratio;
}
v++;
c++;
if (c%1000==0) {
qDebug() << c << "processed...time: ms: " << t.elapsed();
QCoreApplication::processEvents();
}
}
}
//////////////////////////////////////////////////////////
// Lightroom Object
//////////////////////////////////////////////////////////
LightRoomObject::~LightRoomObject()
{
if (m_radiusFormula)
delete m_radiusFormula;
}
void LightRoomObject::setuptree(const double height, const double crownheight, const QString &formula)
{
if (m_radiusFormula)
delete m_radiusFormula;
m_radiusFormula = new Expression(formula);
m_baseradius = m_radiusFormula->calculate(crownheight/height);
m_height = height;
m_crownheight = crownheight;
}
/** The tree is located in x/y=0/0.
*/
bool LightRoomObject::hittest(const double p_x, const double p_y, const double p_z,
const double azimuth_rad, const double elevation_rad)
{
if (p_z > m_height)
return false;
// Test 1: does the ray (azimuth) direction hit the crown?
double phi = atan2(-p_y, -p_x); // angle between P and the tree center
double dist2d = sqrt(p_x*p_x + p_y*p_y); // distance at ground
if (dist2d==0)
return true;
double alpha = phi - azimuth_rad; // angle between the ray and the center of the tree
if (dist2d>m_baseradius) { // test only, if p not the crown
double half_max_angle = asin(m_baseradius / dist2d); // maximum deviation angle from direct connection p - tree where ray hits maxradius
if (fabs(alpha) > half_max_angle)
return false;
} else {
// test if p is inside the crown
if (p_z<=m_height && p_z>=m_crownheight) {
double radius_hit = m_radiusFormula->calculate(p_z / m_height);
if (radius_hit <= dist2d)
return true;
}
}
// Test 2: test if the crown-"plate" at the bottom of the crown is hit.
if (elevation_rad>0. && p_z<m_crownheight) {
// calc. base distance between p and the point where the height of the ray reaches the bottom of the crown:
double r_hitbottom = dist2d; // for 90°
if (elevation_rad < M_PI_2) {
double d_hitbottom = (m_crownheight - p_z) / tan(elevation_rad);
// calc. position (projected) of that hit point
double rx = p_x + sin(azimuth_rad)*d_hitbottom;
double ry = p_y + cos(azimuth_rad)*d_hitbottom;
r_hitbottom = sqrt(rx*rx + ry*ry);
}
if (r_hitbottom <= m_baseradius)
return true;
}
return false;
// Test 3: determine height of hitting tree
// double z_hit = p_z + dist2d*tan(elevation_rad);
// if (z_hit > m_height || z_hit<m_crownheight)
// return false;
// // determine angle of crownradius in hitting height (use relative height as variable in formula!)
// // e.g. for a simple parabola: 1-h_rel^2
// double radius_hit = m_radiusFormula->calculate(z_hit / m_height);
// if (radius_hit < 0)
// return false;
// double dist3d = sqrt(p_x*p_x + p_y*p_y + (z_hit-p_z)*(z_hit-p_z) );
// double radius_angle = asin(radius_hit/dist3d);
//
// if (fabs(alpha) > radius_angle)
// return false;
return true;
}
bool LightRoomObject::noHitGuaranteed(const double p_x, const double p_y, const double p_z)
{
// 1. simple: compare height...
if (p_z > m_height)
return true;
// 2. 45° test:
if (p_z > m_height - sqrt(p_x*p_x + p_y*p_y)) // 45°: height = distance from tree center
return true;
return false;
}