Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Viewshed Generation
4 : * Purpose: Core algorithm implementation for viewshed generation.
5 : * Author: Tamas Szekeres, szekerest@gmail.com
6 : *
7 : * (c) 2024 info@hobu.co
8 : *
9 : ******************************************************************************
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #pragma once
15 :
16 : #include <array>
17 : #include <limits>
18 : #include <mutex>
19 :
20 : #include "gdal_priv.h"
21 : #include "cpl_worker_thread_pool.h"
22 :
23 : #include "viewshed_types.h"
24 :
25 : namespace gdal
26 : {
27 : namespace viewshed
28 : {
29 :
30 : /**
31 : * Container for lines necessary for processing.
32 : */
33 : struct Lines
34 : {
35 : std::vector<double> cur; //!< Current line being processed
36 : std::vector<double> result; //!< Result values for current line
37 : std::vector<double> prev; //!< Height values for previous line
38 : std::vector<double>
39 : pitchMask; //!< Height/indicator values for pitch masking.
40 : std::vector<double> prevTmp; //!< Saved prev values when in SD mode.
41 : std::vector<double> sd; //!< SD mask.
42 :
43 : /// Constructor
44 : Lines() : cur(), result(), prev(), pitchMask(), prevTmp(), sd()
45 : {
46 : }
47 :
48 : /// Constructor that initializes to line length
49 : /// \param lineLen Line length.
50 732 : explicit Lines(size_t lineLen)
51 732 : : cur(lineLen), result(lineLen), prev(), pitchMask(), prevTmp(), sd()
52 : {
53 732 : }
54 : };
55 :
56 : /// Dummy raster band.
57 : //! @cond Doxygen_Suppress
58 : class DummyBand : public GDALRasterBand
59 : {
60 : CPLErr IReadBlock(int, int, void *) override;
61 : };
62 : //! @endcond
63 :
64 : class Progress;
65 :
66 : /// Executes a viewshed computation on a source band, placing the result
67 : /// in the destination band.
68 : class ViewshedExecutor
69 : {
70 : public:
71 : ViewshedExecutor(GDALRasterBand &srcBand, GDALRasterBand &sdBand,
72 : GDALRasterBand &dstBand, int nX, int nY,
73 : const Window &oOutExtent, const Window &oCurExtent,
74 : const Options &opts, Progress &oProgress,
75 : bool emitWarningIfNoData);
76 :
77 : ViewshedExecutor(GDALRasterBand &srcBand, GDALRasterBand &dstBand, int nX,
78 : int nY, const Window &oOutExtent, const Window &oCurExtent,
79 : const Options &opts, Progress &oProgress,
80 : bool emitWarningIfNoData);
81 : bool run();
82 :
83 : /** Return whether an input pixel is at the nodata value. */
84 196 : bool hasFoundNoData() const
85 : {
86 196 : return m_hasFoundNoData;
87 : }
88 :
89 : private:
90 : CPLWorkerThreadPool m_pool;
91 : DummyBand m_dummyBand;
92 : GDALRasterBand &m_srcBand;
93 : GDALRasterBand &m_sdBand;
94 : GDALRasterBand &m_dstBand;
95 : double m_noDataValue = 0;
96 : bool m_hasNoData = false;
97 : bool m_emitWarningIfNoData = false;
98 : bool m_hasFoundNoData = false;
99 : const Window oOutExtent;
100 : const Window oCurExtent;
101 : const int m_nX;
102 : const int m_nY;
103 : const Options oOpts;
104 : Progress &oProgress;
105 : double m_dfHeightAdjFactor{0};
106 : double m_dfMinDistance2;
107 : double m_dfMaxDistance2;
108 : double m_dfZObserver{0};
109 : std::mutex iMutex{};
110 : std::mutex oMutex{};
111 : GDALGeoTransform m_gt{};
112 : std::array<double, 5> m_testAngle{};
113 : double m_lowTanPitch{std::numeric_limits<double>::quiet_NaN()};
114 : double m_highTanPitch{std::numeric_limits<double>::quiet_NaN()};
115 : double (*oZcalc)(int, int, double, double, double){};
116 :
117 : double calcHeightAdjFactor();
118 :
119 : void setOutputNormal(Lines &lines, int pos, double dfZ);
120 : void setOutputSd(Lines &lines, int pos, double dfZ);
121 :
122 : bool readLine(int nLine, Lines &lines);
123 : bool writeLine(int nLine, std::vector<double> &vResult);
124 : bool processLine(int nLine, Lines &lines);
125 : bool processFirstLine(Lines &lines);
126 : void processFirstLineLeft(const LineLimits &ll, Lines &lines, bool sdCalc);
127 : void processFirstLineRight(const LineLimits &ll, Lines &lines, bool sdCalc);
128 : void processFirstLineTopOrBottom(const LineLimits &ll, Lines &lines);
129 : void processLineLeft(int nYOffset, LineLimits &ll, Lines &lines,
130 : bool sdCalc);
131 : void processLineRight(int nYOffset, LineLimits &ll, Lines &lines,
132 : bool sdCalc);
133 : LineLimits adjustHeight(int iLine, Lines &lines);
134 : bool maskInitial(std::vector<double> &vResult, const LineLimits &ll,
135 : int nLine);
136 : bool maskAngleLeft(std::vector<double> &vResult, int nLine);
137 : bool maskAngleRight(std::vector<double> &vResult, int nLine);
138 : void maskLineLeft(std::vector<double> &vResult, const LineLimits &ll,
139 : int nLine);
140 : void maskLineRight(std::vector<double> &vResult, const LineLimits &ll,
141 : int nLine);
142 : void calcPitchMask(double dfZ, double dfDist, double dfResult,
143 : double &maskVal);
144 : void applyPitchMask(std::vector<double> &vResult,
145 : const std::vector<double> &vPitchMaskVal);
146 : void calcTestAngles();
147 : bool sdMode() const;
148 : };
149 :
150 : } // namespace viewshed
151 : } // namespace gdal
|