Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
15 | Werner | 1 | |
2 | #include "hemigrid.h" |
||
3 | |||
4 | //#include <algorithm> |
||
25 | Werner | 5 | #include <QtCore> |
6 | // needed for drawing: image & color |
||
7 | #include <QImage> |
||
8 | #include <QColor> |
||
15 | Werner | 9 | |
10 | ////////////////////////////////////////////////////// |
||
11 | // Setup memory for the Grid. |
||
12 | // @param size of a single pixel in degree |
||
13 | ////////////////////////////////////////////////////// |
||
14 | void HemiGrid::setup(double cellsize_degree) |
||
15 | { |
||
16 | // setup grid... |
||
17 | mMatrixCountAzimuth = int(360 / cellsize_degree); |
||
18 | mMatrixCountElevation = int(90 / cellsize_degree); |
||
25 | Werner | 19 | mCellSizeDegree = cellsize_degree; |
15 | Werner | 20 | // size occupied by one pixel in rad |
21 | mMatrixCellSize = cellsize_degree * M_PI / 180.; |
||
22 | if (mMatrix) |
||
23 | delete[] mMatrix; |
||
24 | mMatrix = new double[mMatrixCountAzimuth*mMatrixCountElevation]; |
||
25 | |||
26 | clear(); |
||
27 | |||
28 | } |
||
29 | |||
30 | |||
31 | ////////////////////////////////////////////////////// |
||
32 | // Clear the Grid. |
||
33 | // @param SetWith value used to fill (default 0.) |
||
34 | ////////////////////////////////////////////////////// |
||
35 | void HemiGrid::clear(double SetWith) |
||
36 | { |
||
37 | if (mMatrix) { |
||
38 | // blank matrix... |
||
39 | for (int i=0;i<mMatrixCountAzimuth*mMatrixCountElevation;i++) |
||
40 | mMatrix[i]=SetWith; |
||
41 | } |
||
42 | } |
||
43 | |||
25 | Werner | 44 | void HemiGrid::matrixMinMax(double &rMatrixMin, double &rMatrixMax) const |
15 | Werner | 45 | { |
46 | rMatrixMin = 100000000.; |
||
47 | rMatrixMax = -1000000000; |
||
48 | if (mMatrix) { |
||
49 | // blank matrix... |
||
50 | for (int i=0;i<mMatrixCountAzimuth*mMatrixCountElevation;i++) { |
||
51 | rMatrixMin = std::min(mMatrix[i], rMatrixMin); |
||
52 | rMatrixMax = std::max(mMatrix[i], rMatrixMax); |
||
53 | } |
||
54 | } |
||
55 | } |
||
772 | werner | 56 | double HemiGrid::sum(const double elevation) const |
29 | Werner | 57 | { |
58 | int ie=indexElevation(elevation); |
||
59 | int emax=matrixCountElevation(); |
||
60 | int amax=matrixCountAzimuth(); |
||
61 | double value = 0; |
||
62 | for (int e=ie;e<emax;e++) |
||
63 | for (int a=0;a<amax;a++) |
||
64 | value+=rGetByIndex(a,e); |
||
65 | return value; |
||
66 | } |
||
15 | Werner | 67 | |
68 | ////////////////////////////////////////////////////// |
||
69 | // Dump the grid into a TStringList |
||
70 | ////////////////////////////////////////////////////// |
||
71 | //void HemiGrid::DumpGrid(TStrings* List) |
||
72 | //{ |
||
73 | // AnsiString Line; |
||
74 | // for (int i=0;i<mMatrixCountAzimuth;i++) { |
||
75 | // Line=AnsiString(i); |
||
76 | // for (int j=0;j<mMatrixCountElevation;j++) { |
||
77 | // Line+=";"+AnsiString(rGetByIndex(i,j)); |
||
78 | // } |
||
79 | // List->Add(Line); |
||
80 | // } |
||
81 | // |
||
82 | //} |
||
83 | |||
84 | ////////////////////////////////////////////////////// |
||
85 | // Get Gridvalue by integer internal grid indices |
||
86 | // @param iAzimuth index of azimuth (0..count(pixels)-1 |
||
87 | // @param iElevation index of elevatin (0..count-1) |
||
88 | // @return ref. to grid-value |
||
89 | ////////////////////////////////////////////////////// |
||
25 | Werner | 90 | double& HemiGrid::rGetByIndex(const int iAzimuth, const int iElevation) const |
15 | Werner | 91 | { |
92 | if (iAzimuth < mMatrixCountAzimuth && iElevation < mMatrixCountElevation |
||
93 | && iAzimuth>=0 && iElevation>=0) |
||
94 | return mMatrix[iAzimuth*mMatrixCountElevation + iElevation]; |
||
95 | else |
||
96 | throw QString("TSolar::Rad::Get() - invalid indices"); |
||
97 | } |
||
98 | |||
99 | ////////////////////////////////////////////////////// |
||
100 | // Get Gridvalue |
||
101 | // @param Azimuth azimuth angle (-pi .. +pi, 0=south) |
||
102 | // @param Elevation elevation angle (0=horizon, pi/2: zenith) |
||
103 | // @return ref. to grid-value |
||
104 | ////////////////////////////////////////////////////// |
||
25 | Werner | 105 | double& HemiGrid::rGet(const double Azimuth, const double Elevation) const |
15 | Werner | 106 | { |
107 | // Azimuth goes from -pi .. +pi -> move to 0..2pi, scale to 0..1 and convert to integer indices |
||
24 | Werner | 108 | int iAzimuth = indexAzimuth(Azimuth); |
15 | Werner | 109 | // Elevation goes from 0..90° = 0..pi/2 |
24 | Werner | 110 | int iElevation = indexElevation(Elevation); |
15 | Werner | 111 | |
112 | return rGetByIndex(iAzimuth, iElevation); |
||
113 | } |
||
114 | |||
115 | void HemiGrid::modify(const HemiGrid &Source, const ModifyMode mode) |
||
116 | { |
||
117 | for (int i=0; i<mMatrixCountAzimuth*mMatrixCountElevation; i++) { |
||
118 | switch (mode) { |
||
119 | case Add: mMatrix[i]+=Source.mMatrix[i]; break; |
||
120 | case Multiply: mMatrix[i] *= Source.mMatrix[i]; break; |
||
121 | case SetTo: mMatrix[i] = Source.mMatrix[i]; break; |
||
122 | } |
||
123 | } |
||
124 | |||
125 | } |
||
126 | |||
127 | /** retrieve total sum of the hemigrid. |
||
128 | @param Weighter if available (non null) each cell value of this grid is multiplied with the weighter grid (note: no additional calculations are performed) */ |
||
129 | double HemiGrid::getSum(const HemiGrid *Weighter) const |
||
130 | { |
||
131 | double Sum=0.; |
||
132 | if (Weighter) { |
||
24 | Werner | 133 | if (Weighter->matrixCountAzimuth()!=this->matrixCountAzimuth() |
134 | || Weighter->matrixCountElevation() != this->matrixCountElevation()) |
||
15 | Werner | 135 | throw QString("HemiGrid::getSum: invalid weighing object!"); |
136 | |||
137 | for (int i=0; i<mMatrixCountAzimuth*mMatrixCountElevation; i++) { |
||
138 | Sum += mMatrix[i]*Weighter->mMatrix[i]; |
||
139 | } |
||
140 | return Sum; |
||
141 | } |
||
142 | for (int i=0; i<mMatrixCountAzimuth*mMatrixCountElevation; i++) { |
||
143 | Sum += mMatrix[i]; |
||
144 | } |
||
145 | return Sum; |
||
146 | } |
||
147 | |||
148 | void HemiGrid::projectLine(const double &x, const double &y, const double &deltah, const double &r, double &elevation, double &azimuth1, double &azimuth2) |
||
149 | { |
||
150 | // transform coordinates.... |
||
151 | // distance to footing point (x/y) |
||
152 | double distance = sqrt(x*x + y*y); |
||
153 | elevation = atan2(deltah, distance); |
||
154 | double azimuth = atan2(x,y); |
||
155 | // distance to point (x/y/z) |
||
156 | double dist3 = sqrt(x*x+y*y+deltah*deltah); |
||
157 | double azimuth_delta = atan2(r, dist3); |
||
158 | azimuth1 = azimuth - azimuth_delta; |
||
159 | azimuth2 = azimuth + azimuth_delta; |
||
160 | } |
||
161 | |||
162 | ////////////////////////////////////////////////////// |
||
163 | // Modify a rect defined by coordinates, a mode and a value |
||
164 | // @param elow, ehigh: elevation angles |
||
165 | // @param alow1, alow2: azimuth angles at base, alow1 must be < alow2 |
||
166 | // @param ahigh1, ahigh2: azimuth angles at the top, ahigh1 must be < ahigh2 |
||
167 | // @param ModifyMode multiply or add to the matrix |
||
168 | // @param Value value used for multiply/add,... |
||
169 | ////////////////////////////////////////////////////// |
||
170 | void HemiGrid::modifyAngleRect( const double &elow, const double &alow1, const double &alow2, |
||
171 | const double &ehigh, const double &ahigh1, const double &ahigh2, |
||
172 | const ModifyMode mode, const double &value) |
||
173 | { |
||
24 | Werner | 174 | int i_e_low = indexElevation(elow); |
175 | int i_e_high = indexElevation(ehigh); |
||
176 | int i_a_low1 = indexAzimuth(alow1); |
||
177 | int i_a_low2 = indexAzimuth(alow2); |
||
178 | int i_a_high1 = indexAzimuth(ahigh1); |
||
179 | int i_a_high2 = indexAzimuth(ahigh2); |
||
15 | Werner | 180 | int i_a_min = std::min(i_a_low1, i_a_high1); |
181 | int i_a_max = std::max(i_a_low2, i_a_high2); |
||
182 | |||
183 | for (int e = i_e_low; e<=i_e_high; e++) { |
||
184 | for (int a = i_a_min; a<=i_a_max; a++) { |
||
185 | double &ref = rGetByIndex((a+mMatrixCountAzimuth)%mMatrixCountAzimuth, e); |
||
186 | switch (mode) { |
||
187 | case Multiply: ref*=value; break; |
||
188 | case Add: ref+=value; break; |
||
189 | case SetTo: ref=value; break; |
||
190 | } |
||
191 | } |
||
192 | } |
||
193 | |||
194 | } |
||
195 | |||
196 | |||
197 | ////////////////////////////////////////////////////// |
||
198 | // Project a cylinder onto the grid. |
||
199 | // @param deltax, deltay: relative position |
||
200 | // @param offsetz: relative height of lower edge |
||
201 | // @param height, r: height and radius of cylinder |
||
202 | // @param mode, value: mode and value of change |
||
203 | // @param elow, ehigh: elevation angles |
||
204 | ////////////////////////////////////////////////////// |
||
205 | void HemiGrid::projectCylinder(const double &deltax, const double &deltay, |
||
206 | const double &offsetz, const double &height, const double &r, |
||
207 | const ModifyMode mode, const double &value) |
||
208 | { |
||
209 | double elow, ehigh; // elevations... |
||
210 | double al1, al2, ah1, ah2; |
||
211 | projectLine(deltax, deltay, std::max(offsetz+height, 0.), r, ehigh, ah1, ah2); |
||
212 | // ignore if top is t |
||
213 | if (ehigh < 5.*M_PI/180.) |
||
214 | return; |
||
215 | projectLine(deltax, deltay, std::max(offsetz, 0.), r, elow, al1, al2); |
||
216 | modifyAngleRect(elow, al1, al2, ehigh, ah1, ah2, mode, value); |
||
217 | } |
||
218 | |||
219 | |||
25 | Werner | 220 | void HemiGrid::paintGrid(QImage &image) const |
221 | { |
||
222 | int dx = image.width(); |
||
223 | int dy = image.height(); |
||
224 | int ix,iy; |
||
225 | double x,y; |
||
226 | int maxsize = std::min(dx,dy); |
||
753 | werner | 227 | double mmin=0, mmax=0; // min and max values of matrix |
228 | //if (mmax==0) mmax=1; |
||
25 | Werner | 229 | matrixMinMax(mmin, mmax); |
230 | QColor col; |
||
231 | double phi, r, elevation, value; |
||
232 | for (ix=0;ix<maxsize;ix++){ |
||
233 | for (iy=0;iy<maxsize;iy++){ |
||
234 | // to -1..1 |
||
235 | x = 2*(ix-maxsize/2.) / maxsize; |
||
236 | y = 2*(iy-maxsize/2.) / maxsize; |
||
237 | // get phi,r (polar coords) |
||
238 | if (x==0 && y==0) |
||
239 | continue; |
||
15 | Werner | 240 | |
25 | Werner | 241 | r = sqrt(x*x + y*y); |
242 | if (r>=1) |
||
243 | continue; |
||
402 | werner | 244 | phi = atan2(y,x); |
25 | Werner | 245 | elevation = M_PI_2 - (r * M_PI_2); |
246 | value = rGet(phi, elevation); |
||
247 | value /= mmax; |
||
248 | col = QColor::fromHsvF((1.-value)*0.666666 ,0.9, 0.9); // hue from 0..240 = red to blue |
||
40 | Werner | 249 | image.setPixel(ix,maxsize-iy,col.rgb()); |
25 | Werner | 250 | } |
251 | } |
||
252 | } |
||
253 | |||
254 | QString HemiGrid::dumpGrid() const |
||
255 | { |
||
256 | QString text; |
||
257 | text="rows: azimuth steps, cols: elevation. (first value in row: index of azimuth)\n"; |
||
258 | for (int i=0;i<mMatrixCountAzimuth;i++) { |
||
259 | text+=QString::number(i); |
||
260 | for (int j=0;j<mMatrixCountElevation;j++) { |
||
261 | text+=";"+QString::number(rGetByIndex(i,j)); |
||
262 | } |
||
263 | text+="\n"; |
||
264 | } |
||
265 | return text; |
||
266 | } |
||
267 | |||
268 |