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."),
40 , m_exitDepth(exitDepth
)
42 m_litChannel
->addDerivitive(this);
46 tcShadowDepth::~tcShadowDepth()
48 m_litChannel
->removeDerivitive(this);
52 * Interface for derived class to implement
56 void tcShadowDepth::roundPortion(double* x1
, double* y1
, double* x2
, double* y2
)
58 m_litChannel
->roundPortion(x1
,y1
,x2
,y2
);
61 tcAbstractPixelData
* tcShadowDepth::loadPortion(double x1
, double y1
, double x2
, double y2
, bool changed
)
63 Reference
<tcAbstractPixelData
> channelData
= m_litChannel
->loadPortion(x1
, y1
, x2
, y2
, changed
);
64 int width
= channelData
->width();
65 int height
= channelData
->height();
67 // Create a new pixel buffer
68 tcPixelData
<float>* data
= new tcPixelData
<float>(width
, height
);
69 startProcessing(tr("Depthing shadows"));
70 /*for (int i = 0; i < width*height; ++i)
72 data->buffer()[i] = -2.0f;
82 temp
.lit
= channelData
;
83 temp
.shadowDepths
= data
;
85 int maxWidthHeight
= qMax(width
, height
);
86 double minXY12
= qMin(x2
-x1
, y2
-y1
);
88 Reference
<tcPixelData
<float> > litData
= dynamicCast
<tcPixelData
<float>*>(channelData
);
90 for (int j
= 0; j
< height
; ++j
)
92 progress((float)j
/(height
-1));
93 for (int i
= 0; i
< width
; ++i
)
95 //pixelShadowDepth(&data, i, j);
97 int index
= j
*width
+ i
;
99 // Not actually in shadow
100 if (litData
->buffer()[index
] > 0.5f
)
102 data
->buffer()[index
] = 0.0f
;
107 maths::Vector
<2,float> coord (x1
+ (x2
-x1
)*i
/ (width
- 1),
108 y1
+ (y2
-y1
)*j
/ (height
- 1));
113 * Ty=(1-y1-Cy)/(y2-y1)
116 // Find local light direction
117 tcGeo geoCoord
= geoAt(coord
);
118 maths::Vector
<3,float> light
= lightDirectionAt(geoCoord
);
120 // This appears to be almost accurate: the light vector in texture space
121 // Perhaps this is the size of the texture not being taken into account
122 tcGeo
offset2(geoAt(coord
+ maths::Vector
<2,float>(-light
[0]/(maxWidthHeight
-1)*minXY12
,
123 light
[1]/(maxWidthHeight
-1)*minXY12
)));
125 // This doesn't appear to be accurate: the light vector in geographical space
126 //float magn = maths::Vector<2,float>(offset1.lon()-geoCoord.lon(), offset1.lat()-geoCoord.lat()).mag();
127 //tcGeo offset2(geoCoord + tcGeo(light[0]*magn,
130 // Trace in sun direction until we reach non shadow.
131 tcGeo pos
= geoCoord
;
135 delta
= offset2
- geoCoord
;
139 delta
= geoCoord
- offset2
;
142 maths::Vector
<2,float> tex
= coord
;
143 while (tex
[0] >= x1
&& tex
[0] <= x2
&& tex
[1] >= y1
&& tex
[1] <= y2
)
145 if (channelData
->sampleFloat((tex
[0]-x1
)/(x2
-x1
), (tex
[1]-y1
)/(y2
-y1
)) > 0.5f
)
150 tex
= textureAt(pos
);
152 data
->buffer()[index
] = (tex
-coord
).mag()*200;
164 /// Calculate the shadow depth of a pixel, recursively as necessary.
165 float tcShadowDepth::pixelShadowDepth(const tempData
* data
, int i
, int j
)
167 int index
= j
*data
->width
+ i
;
168 float& depth
= data
->shadowDepths
->buffer()[index
];
170 // Already set, just return that
176 // Not actually in shadow
177 if (data
->lit
->sampleFloat(i
, j
) > 0.5f
)
182 // In shadow, not yet calculated depth
184 // Find local light direction
185 maths::Vector
<2,float> coord (data
->x1
+ (data
->x2
-data
->x1
)*i
/ (data
->width
- 1),
186 data
->y1
+ (data
->y2
-data
->y1
)*j
/ (data
->height
- 1));
187 tcGeo geoCoord
= geoAt(coord
);
188 maths::Vector
<3,float> light
= lightDirectionAt(geoCoord
);
193 // Pick an axis direction
194 if (light
[1] < light
[0]) // SE
196 if (-light
[1] < light
[0]) // E
198 coords
[0][0] = i
+1; coords
[0][1] = j
;
199 weights
[1] = fabs(light
[1]/light
[0]);
203 coords
[0][0] = i
; coords
[0][1] = j
+1;
204 weights
[1] = fabs(light
[0]/light
[1]);
209 if (-light
[1] < light
[0]) // W
211 coords
[0][0] = i
-1; coords
[0][1] = j
;
212 weights
[1] = fabs(light
[1]/light
[0]);
216 coords
[0][0] = i
; coords
[0][1] = j
-1;
217 weights
[1] = fabs(light
[0]/light
[1]);
221 // Pick a diagonal direction
222 if (light
[0] > 0.0f
) // E (NE,SE)
224 if (light
[1] > 0.0f
) // NE
226 coords
[1][0] = i
+1; coords
[1][1] = j
-1;
230 coords
[1][0] = i
+1; coords
[1][1] = j
+1;
235 if (light
[1] > 0.0f
) // NW
237 coords
[1][0] = i
-1; coords
[1][1] = j
+1;
241 coords
[1][0] = i
-1; coords
[1][1] = j
+1;
244 weights
[0] = 1.0f
- weights
[1];
246 // Get depths of two points.
248 for (int ii
= 0; ii
< 2; ++ii
)
250 if (coords
[ii
][0] >= 0 && coords
[ii
][0] < data
->width
&&
251 coords
[ii
][1] >= 0 && coords
[ii
][1] < data
->height
)
253 depths
[ii
] = pixelShadowDepth(data
, coords
[ii
][0], coords
[ii
][1]);
261 // Each depth can be:
262 // -1 (out of range or unknown)
264 // positive (unlit, x 2d distance from boundary)
266 // If both are unknown, result is unknown
267 if (depths
[0] == -1.0f
&& depths
[1] == -1.0f
)
271 // If one is unknown, use whichever has highest weight
272 else if (depths
[0] == -1.0f
|| depths
[1] == -1.0f
)
279 depth
= depths
[0]*weights
[0] + depths
[1]*weights
[1];