|
12 | 12 | ****************************************************************************/ |
13 | 13 |
|
14 | 14 | #include <algorithm> |
| 15 | +//ABELL |
| 16 | +#include <iostream> |
| 17 | +#include <iomanip> |
15 | 18 |
|
16 | 19 | #include "gdal_alg.h" |
17 | 20 | #include "gdal_priv_templates.hpp" |
@@ -216,6 +219,77 @@ bool getTransforms(GDALRasterBand &band, double *pFwdTransform, |
216 | 219 | return true; |
217 | 220 | } |
218 | 221 |
|
| 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 | + |
219 | 293 | } // unnamed namespace |
220 | 294 |
|
221 | 295 | Viewshed::Viewshed(const Options &opts) : oOpts{opts} |
@@ -284,6 +358,8 @@ bool Viewshed::calcExtents(int nX, int nY, |
284 | 358 | return false; |
285 | 359 | } |
286 | 360 |
|
| 361 | + shrinkWindowForAngles(oOutExtent, nX, nY, oOpts.startAngle, oOpts.endAngle); |
| 362 | + |
287 | 363 | // normalize horizontal index to [ 0, oOutExtent.xSize() ) |
288 | 364 | oCurExtent = oOutExtent; |
289 | 365 | oCurExtent.shiftX(-oOutExtent.xStart); |
@@ -325,6 +401,17 @@ bool Viewshed::run(GDALRasterBandH band, GDALProgressFunc pfnProgress, |
325 | 401 | int nX = static_cast<int>(dfX); |
326 | 402 | int nY = static_cast<int>(dfY); |
327 | 403 |
|
| 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 | + |
328 | 415 | // Must calculate extents in order to make the output dataset. |
329 | 416 | if (!calcExtents(nX, nY, adfInvTransform)) |
330 | 417 | return false; |
@@ -370,5 +457,11 @@ double adjustCurveCoeff(double curveCoeff, GDALDatasetH hSrcDS) |
370 | 457 | return curveCoeff; |
371 | 458 | } |
372 | 459 |
|
| 460 | +void testShrinkWindowForAngles(Window &oOutExtent, int nX, int nY, |
| 461 | + double startAngle, double endAngle) |
| 462 | +{ |
| 463 | + shrinkWindowForAngles(oOutExtent, nX, nY, startAngle, endAngle); |
| 464 | +} |
| 465 | + |
373 | 466 | } // namespace viewshed |
374 | 467 | } // namespace gdal |
0 commit comments