/src/gdal/alg/viewshed/viewshed_executor.h
Line | Count | Source |
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 | 0 | { |
46 | 0 | } |
47 | | |
48 | | /// Constructor that initializes to line length |
49 | | /// \param lineLen Line length. |
50 | | explicit Lines(size_t lineLen) |
51 | 0 | : cur(lineLen), result(lineLen), prev(), pitchMask(), prevTmp(), sd() |
52 | 0 | { |
53 | 0 | } |
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 | | bool hasFoundNoData() const |
85 | 0 | { |
86 | 0 | return m_hasFoundNoData; |
87 | 0 | } |
88 | | |
89 | | private: |
90 | | CPLWorkerThreadPool m_pool; |
91 | | DummyBand m_dummyBand; |
92 | | GDALRasterBand &m_srcBand; |
93 | | GDALRasterBand &m_sdBand; |
94 | | GDALRasterBand &m_dstBand; |
95 | | const bool m_hasSdBand; |
96 | | double m_noDataValue = 0; |
97 | | bool m_hasNoData = false; |
98 | | bool m_emitWarningIfNoData = false; |
99 | | bool m_hasFoundNoData = false; |
100 | | const Window oOutExtent; |
101 | | const Window oCurExtent; |
102 | | const int m_nX; |
103 | | const int m_nY; |
104 | | const Options oOpts; |
105 | | Progress &oProgress; |
106 | | double m_dfHeightAdjFactor{0}; |
107 | | double m_dfMinDistance2; |
108 | | double m_dfMaxDistance2; |
109 | | double m_dfZObserver{0}; |
110 | | std::mutex iMutex{}; |
111 | | std::mutex oMutex{}; |
112 | | GDALGeoTransform m_gt{}; |
113 | | std::array<double, 5> m_testAngle{}; |
114 | | double m_lowTanPitch{std::numeric_limits<double>::quiet_NaN()}; |
115 | | double m_highTanPitch{std::numeric_limits<double>::quiet_NaN()}; |
116 | | double (*oZcalc)(int, int, double, double, double){}; |
117 | | |
118 | | double calcHeightAdjFactor(); |
119 | | |
120 | | void setOutputNormal(Lines &lines, int pos, double dfZ); |
121 | | void setOutputSd(Lines &lines, int pos, double dfZ); |
122 | | |
123 | | bool readLine(int nLine, Lines &lines); |
124 | | bool writeLine(int nLine, std::vector<double> &vResult); |
125 | | bool processLine(int nLine, Lines &lines); |
126 | | bool processFirstLine(Lines &lines); |
127 | | void processFirstLineLeft(const LineLimits &ll, Lines &lines, bool sdCalc); |
128 | | void processFirstLineRight(const LineLimits &ll, Lines &lines, bool sdCalc); |
129 | | void processFirstLineTopOrBottom(const LineLimits &ll, Lines &lines); |
130 | | void processLineLeft(int nYOffset, LineLimits &ll, Lines &lines, |
131 | | bool sdCalc); |
132 | | void processLineRight(int nYOffset, LineLimits &ll, Lines &lines, |
133 | | bool sdCalc); |
134 | | LineLimits adjustHeight(int iLine, Lines &lines); |
135 | | bool maskInitial(std::vector<double> &vResult, const LineLimits &ll, |
136 | | int nLine); |
137 | | bool maskAngleLeft(std::vector<double> &vResult, int nLine); |
138 | | bool maskAngleRight(std::vector<double> &vResult, int nLine); |
139 | | void maskLineLeft(std::vector<double> &vResult, const LineLimits &ll, |
140 | | int nLine); |
141 | | void maskLineRight(std::vector<double> &vResult, const LineLimits &ll, |
142 | | int nLine); |
143 | | void calcPitchMask(double dfZ, double dfDist, double dfResult, |
144 | | double &maskVal); |
145 | | void applyPitchMask(std::vector<double> &vResult, |
146 | | const std::vector<double> &vPitchMaskVal); |
147 | | void calcTestAngles(); |
148 | | |
149 | | inline bool sdMode() const |
150 | 0 | { |
151 | 0 | return m_hasSdBand; |
152 | 0 | } |
153 | | }; |
154 | | |
155 | | } // namespace viewshed |
156 | | } // namespace gdal |