Skip to content

Commit c9750c9

Browse files
committed
Checkpoint.
1 parent 5d557ca commit c9750c9

File tree

7 files changed

+269
-30
lines changed

7 files changed

+269
-30
lines changed

alg/viewshed/util.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
****************************************************************************/
66

77
#include <array>
8+
#include <iostream>
89

910
#include "gdal_priv.h"
1011
#include "util.h"
@@ -15,6 +16,81 @@ namespace gdal
1516
namespace viewshed
1617
{
1718

19+
/// Normalize a masking angle. Change from clockwise with 0 north (up) to counterclockwise
20+
/// with 0 to the east (right) and change to radians.
21+
double normalizeAngle(double maskAngle)
22+
{
23+
maskAngle = 90 - maskAngle;
24+
if (maskAngle < 0)
25+
maskAngle += 360;
26+
return maskAngle * (M_PI / 180);
27+
}
28+
29+
/// Compute the X intersect position on the line Y = y with a ray extending
30+
/// from (nX, nY) along `angle`.
31+
///ABELL doc args
32+
double horizontalIntersect(double angle, int nX, int nY, int y)
33+
{
34+
double x = std::numeric_limits<double>::quiet_NaN();
35+
36+
if (nY == y)
37+
x = nX;
38+
else if (nY > y)
39+
{
40+
if (ARE_REAL_EQUAL(angle, M_PI / 2))
41+
x = nX;
42+
else if (angle > 0 && angle < M_PI)
43+
x = nX + (nY - y) / std::tan(angle);
44+
}
45+
else // nY < y
46+
{
47+
if (ARE_REAL_EQUAL(angle, 3 * M_PI / 2))
48+
x = nX;
49+
else if (angle > M_PI)
50+
x = nX - (y - nY) / std::tan(angle);
51+
}
52+
return x;
53+
}
54+
55+
/// Compute the Y intersect position on the line X = x with a ray extending
56+
/// from (nX, nY) along `angle`.
57+
///ABELL doc args
58+
double verticalIntersect(double angle, int nX, int nY, int x)
59+
{
60+
double y = std::numeric_limits<double>::quiet_NaN();
61+
62+
if (nX == x)
63+
y = nY;
64+
else if (nX < x)
65+
{
66+
if (ARE_REAL_EQUAL(angle, 0))
67+
y = nY;
68+
else if (angle < M_PI / 2 || angle > M_PI * 3 / 2)
69+
y = nY + (nX - x) * std::tan(angle);
70+
}
71+
else // nX > x
72+
{
73+
if (ARE_REAL_EQUAL(angle, M_PI))
74+
y = nY;
75+
else if (angle > M_PI / 2 && angle < M_PI * 3 / 2)
76+
y = nY - (x - nX) * std::tan(angle);
77+
}
78+
return y;
79+
}
80+
81+
// Determine if ray is in the slice between two rays starting at `start` and
82+
// going clockwise to `end`.
83+
bool rayBetween(double start, double end, double test)
84+
{
85+
// Our angles go counterclockwise, so swap start and end
86+
std::swap(start, end);
87+
if (start < end)
88+
return (test > start && test < end);
89+
else if (start > end)
90+
return (test > start || test < end);
91+
return false;
92+
}
93+
1894
/// Get the band size
1995
///
2096
/// @param band Raster band

alg/viewshed/util.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ namespace gdal
1414
namespace viewshed
1515
{
1616

17+
double normalizeAngle(double maskAngle);
18+
double horizontalIntersect(double angle, int nX, int nY, int y);
19+
double verticalIntersect(double angle, int nX, int nY, int x);
20+
bool rayBetween(double start, double end, double test);
1721
size_t bandSize(GDALRasterBand &band);
1822

1923
DatasetPtr createOutputDataset(GDALRasterBand &srcBand, const Options &opts,

alg/viewshed/viewshed.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
****************************************************************************/
1313

1414
#include <algorithm>
15+
//ABELL
16+
#include <iostream>
17+
#include <iomanip>
1518

1619
#include "gdal_alg.h"
1720
#include "gdal_priv_templates.hpp"
@@ -216,6 +219,77 @@ bool getTransforms(GDALRasterBand &band, double *pFwdTransform,
216219
return true;
217220
}
218221

222+
void shrinkWindowForAngles(Window &oOutExtent, int nX, int nY,
223+
double startAngle, double endAngle)
224+
{
225+
if (startAngle == endAngle)
226+
return;
227+
228+
Window win = oOutExtent;
229+
230+
// Set the X boundaries for the angles
231+
//ABELL - Verify for out-of-raster.
232+
double xStart = horizontalIntersect(startAngle, nX, nY, win.yStart);
233+
if (isnan(xStart))
234+
xStart = horizontalIntersect(startAngle, nX, nY, win.yStop);
235+
236+
double xStop = horizontalIntersect(endAngle, nX, nY, win.yStart);
237+
if (isnan(xStop))
238+
xStop = horizontalIntersect(endAngle, nX, nY, win.yStop);
239+
240+
double xmax = nX;
241+
if (!rayBetween(startAngle, endAngle, 0))
242+
{
243+
if (!isnan(xStart))
244+
xmax = std::max(xmax, static_cast<double>(xStart));
245+
if (!isnan(xStop))
246+
xmax = std::max(xmax, static_cast<double>(xStop));
247+
oOutExtent.xStop =
248+
std::min(oOutExtent.xStop, static_cast<int>(std::round(xmax)));
249+
}
250+
double xmin = nX;
251+
if (!rayBetween(startAngle, endAngle, M_PI))
252+
{
253+
if (!isnan(xStart))
254+
xmin = std::min(xmin, xStart);
255+
if (!isnan(xStop))
256+
xmin = std::min(xmin, xStop);
257+
oOutExtent.xStart =
258+
std::max(oOutExtent.xStart, static_cast<int>(std::round(xmin)));
259+
}
260+
261+
// Set the Y boundaries for the angles
262+
//ABELL - Verify for out-of-raster.
263+
double yStart = verticalIntersect(startAngle, nX, nY, win.xStart);
264+
if (isnan(yStart))
265+
yStart = verticalIntersect(startAngle, nX, nY, win.xStop);
266+
267+
double yStop = verticalIntersect(endAngle, nX, nY, win.xStart);
268+
if (isnan(yStop))
269+
yStop = verticalIntersect(endAngle, nX, nY, win.xStop);
270+
271+
double ymin = nY;
272+
if (!rayBetween(startAngle, endAngle, M_PI / 2))
273+
{
274+
if (!isnan(yStart))
275+
ymin = std::min(ymin, static_cast<double>(yStart));
276+
if (!isnan(yStop))
277+
ymin = std::min(ymin, static_cast<double>(yStop));
278+
oOutExtent.yStart =
279+
std::max(oOutExtent.yStart, static_cast<int>(std::round(ymin)));
280+
}
281+
double ymax = nY;
282+
if (!rayBetween(startAngle, endAngle, 3 * M_PI / 2))
283+
{
284+
if (!isnan(yStart))
285+
ymax = std::max(ymax, static_cast<double>(yStart));
286+
if (!isnan(yStop))
287+
ymax = std::max(ymax, static_cast<double>(yStop));
288+
oOutExtent.yStop =
289+
std::min(oOutExtent.yStop, static_cast<int>(std::round(ymax)));
290+
}
291+
}
292+
219293
} // unnamed namespace
220294

221295
Viewshed::Viewshed(const Options &opts) : oOpts{opts}
@@ -284,6 +358,8 @@ bool Viewshed::calcExtents(int nX, int nY,
284358
return false;
285359
}
286360

361+
shrinkWindowForAngles(oOutExtent, nX, nY, oOpts.startAngle, oOpts.endAngle);
362+
287363
// normalize horizontal index to [ 0, oOutExtent.xSize() )
288364
oCurExtent = oOutExtent;
289365
oCurExtent.shiftX(-oOutExtent.xStart);
@@ -325,6 +401,17 @@ bool Viewshed::run(GDALRasterBandH band, GDALProgressFunc pfnProgress,
325401
int nX = static_cast<int>(dfX);
326402
int nY = static_cast<int>(dfY);
327403

404+
if (oOpts.startAngle < 0 || oOpts.startAngle >= 360)
405+
CPLError(CE_Failure, CPLE_AppDefined,
406+
"Start angle out of range. Must be [0, 360).");
407+
if (oOpts.endAngle < 0 || oOpts.endAngle >= 360)
408+
CPLError(CE_Failure, CPLE_AppDefined,
409+
"End angle out of range. Must be [0, 360).");
410+
411+
// Normalize angle to radians and standard math arrangement.
412+
oOpts.startAngle = normalizeAngle(oOpts.startAngle);
413+
oOpts.endAngle = normalizeAngle(oOpts.endAngle);
414+
328415
// Must calculate extents in order to make the output dataset.
329416
if (!calcExtents(nX, nY, adfInvTransform))
330417
return false;
@@ -370,5 +457,11 @@ double adjustCurveCoeff(double curveCoeff, GDALDatasetH hSrcDS)
370457
return curveCoeff;
371458
}
372459

460+
void testShrinkWindowForAngles(Window &oOutExtent, int nX, int nY,
461+
double startAngle, double endAngle)
462+
{
463+
shrinkWindowForAngles(oOutExtent, nX, nY, startAngle, endAngle);
464+
}
465+
373466
} // namespace viewshed
374467
} // namespace gdal

0 commit comments

Comments
 (0)