Subversion Repositories public iLand

Rev

Rev 1221 | Blame | Compare with Previous | Last modification | View Log | RSS feed


#include "hemigrid.h"

//#include <algorithm>
#include <QtCore>
// needed for drawing: image & color
#include <QImage>
#include <QColor>

//////////////////////////////////////////////////////
// Setup memory for the Grid.
// @param size of a single pixel in degree
//////////////////////////////////////////////////////
void HemiGrid::setup(double cellsize_degree)
{
      // setup grid...
      mMatrixCountAzimuth = int(360 / cellsize_degree);
      mMatrixCountElevation = int(90 / cellsize_degree);
      mCellSizeDegree = cellsize_degree;
      // size occupied by one pixel in rad
      mMatrixCellSize = cellsize_degree * M_PI / 180.;
      if (mMatrix)
        delete[] mMatrix;
      mMatrix = new double[mMatrixCountAzimuth*mMatrixCountElevation];

      clear();

}


//////////////////////////////////////////////////////
// Clear the Grid.
// @param SetWith value used to fill (default 0.)
//////////////////////////////////////////////////////
void HemiGrid::clear(double SetWith)
{
    if (mMatrix) {
      // blank matrix...
      for (int i=0;i<mMatrixCountAzimuth*mMatrixCountElevation;i++)
         mMatrix[i]=SetWith;
    }
}

void HemiGrid::matrixMinMax(double &rMatrixMin, double &rMatrixMax) const
{
    rMatrixMin = 100000000.;
    rMatrixMax = -1000000000;
    if (mMatrix) {
      // blank matrix...
      for (int i=0;i<mMatrixCountAzimuth*mMatrixCountElevation;i++) {
         rMatrixMin = std::min(mMatrix[i], rMatrixMin);
         rMatrixMax = std::max(mMatrix[i], rMatrixMax);
      }
    }
}
double HemiGrid::sum(const double elevation) const
{
    int ie=indexElevation(elevation);
    int emax=matrixCountElevation();
    int amax=matrixCountAzimuth();
    double value = 0;
    for (int e=ie;e<emax;e++)
        for (int a=0;a<amax;a++)
            value+=rGetByIndex(a,e);
    return value;
}

//////////////////////////////////////////////////////
// Dump the grid into a TStringList
//////////////////////////////////////////////////////
//void HemiGrid::DumpGrid(TStrings* List)
//{
//    AnsiString Line;
//    for (int i=0;i<mMatrixCountAzimuth;i++)  {
//       Line=AnsiString(i);
//       for (int j=0;j<mMatrixCountElevation;j++)  {
//           Line+=";"+AnsiString(rGetByIndex(i,j));
//       }
//       List->Add(Line);
//    }
//
//}

//////////////////////////////////////////////////////
// Get Gridvalue by integer internal grid indices
// @param iAzimuth index of azimuth (0..count(pixels)-1
// @param iElevation index of elevatin (0..count-1)
// @return ref. to grid-value
//////////////////////////////////////////////////////
double& HemiGrid::rGetByIndex(const int iAzimuth, const int iElevation) const
{
if (iAzimuth < mMatrixCountAzimuth && iElevation < mMatrixCountElevation
        && iAzimuth>=0 && iElevation>=0)
       return mMatrix[iAzimuth*mMatrixCountElevation + iElevation];
    else
       throw QString("TSolar::Rad::Get() - invalid indices");
}

//////////////////////////////////////////////////////
// Get Gridvalue
// @param Azimuth azimuth angle (-pi .. +pi, 0=south)
// @param Elevation elevation angle (0=horizon, pi/2: zenith)
// @return ref. to grid-value
//////////////////////////////////////////////////////
double& HemiGrid::rGet(const double Azimuth, const double Elevation) const
{
    // Azimuth goes from -pi .. +pi -> move to 0..2pi, scale to 0..1 and convert to integer indices
    int iAzimuth = indexAzimuth(Azimuth);
    // Elevation goes from 0..90° = 0..pi/2
    int iElevation = indexElevation(Elevation);

    return rGetByIndex(iAzimuth, iElevation);
}

void HemiGrid::modify(const HemiGrid &Source, const ModifyMode mode)
{
        for (int i=0; i<mMatrixCountAzimuth*mMatrixCountElevation; i++) {
            switch (mode) {
                case Add: mMatrix[i]+=Source.mMatrix[i]; break;
                case Multiply: mMatrix[i] *= Source.mMatrix[i]; break;
                case SetTo: mMatrix[i] = Source.mMatrix[i]; break;
            }
        }

}

/** retrieve total sum of the hemigrid.
  @param Weighter if available (non null) each cell value of this grid is multiplied with the weighter grid (note: no additional calculations are performed) */

double HemiGrid::getSum(const HemiGrid *Weighter) const
{
    double Sum=0.;
    if (Weighter) {
        if (Weighter->matrixCountAzimuth()!=this->matrixCountAzimuth()
            || Weighter->matrixCountElevation() != this->matrixCountElevation())
                throw QString("HemiGrid::getSum: invalid weighing object!");

        for (int i=0; i<mMatrixCountAzimuth*mMatrixCountElevation; i++) {
            Sum += mMatrix[i]*Weighter->mMatrix[i];
        }
        return Sum;
    }
    for (int i=0; i<mMatrixCountAzimuth*mMatrixCountElevation; i++) {
        Sum += mMatrix[i];
    }
    return Sum;
}

void HemiGrid::projectLine(const double &x, const double &y, const double &deltah, const double &r, double &elevation, double &azimuth1, double &azimuth2)
{
   // transform coordinates....
   // distance to footing point (x/y)
   double distance = sqrt(x*x + y*y);
   elevation = atan2(deltah, distance);
   double azimuth = atan2(x,y);
   // distance to point (x/y/z)
   double dist3 = sqrt(x*x+y*y+deltah*deltah);
   double azimuth_delta = atan2(r, dist3);
   azimuth1 = azimuth - azimuth_delta;
   azimuth2 = azimuth + azimuth_delta;
}

//////////////////////////////////////////////////////
// Modify a rect defined by coordinates, a mode and a value
// @param  elow, ehigh: elevation angles
// @param alow1, alow2: azimuth angles at base, alow1 must be < alow2
// @param ahigh1, ahigh2: azimuth angles at the top, ahigh1 must be < ahigh2
// @param ModifyMode multiply or add to the matrix
// @param Value value used for multiply/add,...
//////////////////////////////////////////////////////
void HemiGrid::modifyAngleRect( const double &elow, const double &alow1, const double &alow2,
                    const double &ehigh, const double &ahigh1, const double &ahigh2,
                    const ModifyMode mode, const double &value)
{
    int i_e_low = indexElevation(elow);
    int i_e_high = indexElevation(ehigh);
    int i_a_low1 = indexAzimuth(alow1);
    int i_a_low2 = indexAzimuth(alow2);
    int i_a_high1 = indexAzimuth(ahigh1);
    int i_a_high2 = indexAzimuth(ahigh2);
    int i_a_min = std::min(i_a_low1, i_a_high1);
    int i_a_max = std::max(i_a_low2, i_a_high2);

    for (int e = i_e_low; e<=i_e_high; e++) {
       for (int a = i_a_min; a<=i_a_max; a++) {
          double &ref = rGetByIndex((a+mMatrixCountAzimuth)%mMatrixCountAzimuth, e);
          switch (mode) {
            case Multiply: ref*=value; break;
            case Add: ref+=value; break;
            case SetTo: ref=value; break;
          }
       }
    }

}


//////////////////////////////////////////////////////
// Project a cylinder onto the grid.
// @param deltax, deltay: relative position
// @param offsetz: relative height of lower edge
// @param height, r: height and radius of cylinder
// @param mode, value: mode and value of change
// @param  elow, ehigh: elevation angles
//////////////////////////////////////////////////////
void HemiGrid::projectCylinder(const double &deltax, const double &deltay,
                     const double &offsetz, const double &height, const double &r,
                     const ModifyMode mode, const double &value)
{
    double elow, ehigh; // elevations...
    double al1, al2, ah1, ah2;
    projectLine(deltax, deltay, std::max(offsetz+height, 0.), r, ehigh, ah1, ah2);
    // ignore if top is t
    if (ehigh < 5.*M_PI/180.)
       return;
    projectLine(deltax, deltay, std::max(offsetz, 0.), r, elow, al1, al2);
    modifyAngleRect(elow, al1, al2, ehigh, ah1, ah2, mode, value);
}


void HemiGrid::paintGrid(QImage &image) const
{
    int dx = image.width();
    int dy = image.height();
    int ix,iy;
    double x,y;
    int maxsize = std::min(dx,dy);
    double mmin=0, mmax=0; // min and max values of matrix
    //if (mmax==0) mmax=1;
    matrixMinMax(mmin, mmax);
    QColor col;
    double phi, r, elevation, value;
    for (ix=0;ix<maxsize;ix++){
        for (iy=0;iy<maxsize;iy++){
            // to -1..1
            x = 2*(ix-maxsize/2.) / maxsize;
            y = 2*(iy-maxsize/2.) / maxsize;
            // get phi,r (polar coords)
            if (x==0 && y==0)
                continue;

            r = sqrt(x*x + y*y);
            if (r>=1)
                continue;
            phi = atan2(y,x);
            elevation = M_PI_2 - (r * M_PI_2);
            value = rGet(phi, elevation);
            value /= mmax;
            col = QColor::fromHsvF((1.-value)*0.666666 ,0.9, 0.9); // hue from 0..240 = red to blue
            image.setPixel(ix,maxsize-iy,col.rgb());
        }
    }
}

QString HemiGrid::dumpGrid() const
{
    QString text;
    text="rows: azimuth steps, cols: elevation. (first value in row: index of azimuth)\n";
    for (int i=0;i<mMatrixCountAzimuth;i++)  {
       text+=QString::number(i);
       for (int j=0;j<mMatrixCountElevation;j++)  {
           text+=";"+QString::number(rGetByIndex(i,j));
       }
       text+="\n";
    }
    return text;
}