1 /***************************************************************************
2 * This file is part of Tecorrec. *
3 * Copyright 2008 James Hogan <james@albanarts.com> *
5 * Tecorrec is free software: you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation, either version 2 of the License, or *
8 * (at your option) any later version. *
10 * Tecorrec is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with Tecorrec. If not, write to the Free Software Foundation, *
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ***************************************************************************/
21 * @file tcShadowDepth.cpp
22 * @brief 2D depth into shadow along light direction.
25 #include "tcShadowDepth.h"
30 * Constructors + destructor
33 /// Primary constructor.
34 tcShadowDepth::tcShadowDepth(tcChannel
* lit
, tcSrtmModel
* dem
, tcGeoImageData
* imagery
, bool exitDepth
)
35 : tcChannelDem(dem
, imagery
,
37 tr("2D depth into shadows along light direction."))
39 , m_exitDepth(exitDepth
)
41 m_litChannel
->addDerivitive(this);
45 tcShadowDepth::~tcShadowDepth()
47 m_litChannel
->removeDerivitive(this);
51 * Interface for derived class to implement
54 void tcShadowDepth::roundPortion(double* x1
, double* y1
, double* x2
, double* y2
)
56 m_litChannel
->roundPortion(x1
,y1
,x2
,y2
);
59 tcAbstractPixelData
* tcShadowDepth::loadPortion(double x1
, double y1
, double x2
, double y2
)
61 Reference
<tcAbstractPixelData
> channelData
= m_litChannel
->loadPortion(x1
, y1
, x2
, y2
);
62 int width
= channelData
->width();
63 int height
= channelData
->height();
65 // Create a new pixel buffer
66 tcPixelData
<float>* data
= new tcPixelData
<float>(width
, height
);
67 startProcessing(tr("Depthing shadows"));
68 /*for (int i = 0; i < width*height; ++i)
70 data->buffer()[i] = -2.0f;
80 temp
.lit
= channelData
;
81 temp
.shadowDepths
= data
;
83 int maxWidthHeight
= qMax(width
, height
);
84 double minXY12
= qMin(x2
-x1
, y2
-y1
);
86 Reference
<tcPixelData
<float> > litData
= dynamicCast
<tcPixelData
<float>*>(channelData
);
88 for (int j
= 0; j
< height
; ++j
)
90 progress((float)j
/(height
-1));
91 for (int i
= 0; i
< width
; ++i
)
93 //pixelShadowDepth(&data, i, j);
95 int index
= j
*width
+ i
;
97 // Not actually in shadow
98 if (litData
->buffer()[index
] > 0.5f
)
100 data
->buffer()[index
] = 0.0f
;
105 maths::Vector
<2,float> coord ( x1
+ (x2
-x1
)*i
/ (width
- 1),
106 1.0f
- y1
- (y2
-y1
)*j
/ (height
- 1));
111 * Ty=(1-y1-Cy)/(y2-y1)
114 // Find local light direction
115 tcGeo geoCoord
= geoAt(coord
);
116 maths::Vector
<3,float> light
= lightDirectionAt(geoCoord
);
118 // This appears to be almost accurate: the light vector in texture space
119 // Perhaps this is the size of the texture not being taken into account
120 tcGeo
offset2(geoAt(coord
+ maths::Vector
<2,float>(light
[0]/(maxWidthHeight
-1)*minXY12
,
121 light
[1]/(maxWidthHeight
-1)*minXY12
)));
123 // This doesn't appear to be accurate: the light vector in geographical space
124 //float magn = maths::Vector<2,float>(offset1.lon()-geoCoord.lon(), offset1.lat()-geoCoord.lat()).mag();
125 //tcGeo offset2(geoCoord + tcGeo(light[0]*magn,
128 // Trace in sun direction until we reach non shadow.
129 tcGeo pos
= geoCoord
;
133 delta
= offset2
- geoCoord
;
137 delta
= geoCoord
- offset2
;
140 maths::Vector
<2,float> tex
= coord
;
141 while (tex
[0] >= x1
&& tex
[0] <= x2
&& tex
[1] >= 1.0f
-y2
&& tex
[1] <= 1.0f
-y1
)
143 if (channelData
->sampleFloat((tex
[0]-x1
)/(x2
-x1
), (1.0f
-tex
[1]-y1
)/(y2
-y1
)) > 0.5f
)
148 tex
= textureAt(pos
);
150 data
->buffer()[index
] = (tex
-coord
).mag()*200;
162 /// Calculate the shadow depth of a pixel, recursively as necessary.
163 float tcShadowDepth::pixelShadowDepth(const tempData
* data
, int i
, int j
)
165 int index
= j
*data
->width
+ i
;
166 float& depth
= data
->shadowDepths
->buffer()[index
];
168 // Already set, just return that
174 // Not actually in shadow
175 if (data
->lit
->sampleFloat(i
, j
) > 0.5f
)
180 // In shadow, not yet calculated depth
182 // Find local light direction
183 maths::Vector
<2,float> coord ( data
->x1
+ (data
->x2
-data
->x1
)*i
/ (data
->width
- 1),
184 1.0f
- data
->y1
- (data
->y2
-data
->y1
)*j
/ (data
->height
- 1));
185 tcGeo geoCoord
= geoAt(coord
);
186 maths::Vector
<3,float> light
= lightDirectionAt(geoCoord
);
191 // Pick an axis direction
192 if (light
[1] < light
[0]) // SE
194 if (-light
[1] < light
[0]) // E
196 coords
[0][0] = i
+1; coords
[0][1] = j
;
197 weights
[1] = fabs(light
[1]/light
[0]);
201 coords
[0][0] = i
; coords
[0][1] = j
+1;
202 weights
[1] = fabs(light
[0]/light
[1]);
207 if (-light
[1] < light
[0]) // W
209 coords
[0][0] = i
-1; coords
[0][1] = j
;
210 weights
[1] = fabs(light
[1]/light
[0]);
214 coords
[0][0] = i
; coords
[0][1] = j
-1;
215 weights
[1] = fabs(light
[0]/light
[1]);
219 // Pick a diagonal direction
220 if (light
[0] > 0.0f
) // E (NE,SE)
222 if (light
[1] > 0.0f
) // NE
224 coords
[1][0] = i
+1; coords
[1][1] = j
-1;
228 coords
[1][0] = i
+1; coords
[1][1] = j
+1;
233 if (light
[1] > 0.0f
) // NW
235 coords
[1][0] = i
-1; coords
[1][1] = j
+1;
239 coords
[1][0] = i
-1; coords
[1][1] = j
+1;
242 weights
[0] = 1.0f
- weights
[1];
244 // Get depths of two points.
246 for (int ii
= 0; ii
< 2; ++ii
)
248 if (coords
[ii
][0] >= 0 && coords
[ii
][0] < data
->width
&&
249 coords
[ii
][1] >= 0 && coords
[ii
][1] < data
->height
)
251 depths
[ii
] = pixelShadowDepth(data
, coords
[ii
][0], coords
[ii
][1]);
259 // Each depth can be:
260 // -1 (out of range or unknown)
262 // positive (unlit, x 2d distance from boundary)
264 // If both are unknown, result is unknown
265 if (depths
[0] == -1.0f
&& depths
[1] == -1.0f
)
269 // If one is unknown, use whichever has highest weight
270 else if (depths
[0] == -1.0f
|| depths
[1] == -1.0f
)
277 depth
= depths
[0]*weights
[0] + depths
[1]*weights
[1];