Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Marching squares
4 : * Purpose: Classes for contour generation
5 : * Author: Hugo Mercier, <hugo dot mercier at oslandia dot com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2018, Oslandia <infos at oslandia dot com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #ifndef MARCHING_SQUARES_CONTOUR_GENERATOR_H
14 : #define MARCHING_SQUARES_CONTOUR_GENERATOR_H
15 :
16 : #include <vector>
17 : #include <algorithm>
18 :
19 : #include "gdal.h"
20 :
21 : #include "utility.h"
22 : #include "point.h"
23 : #include "square.h"
24 :
25 : namespace marching_squares
26 : {
27 :
28 : template <typename ContourWriter, typename LevelGenerator>
29 : class ContourGenerator
30 : {
31 : public:
32 47 : ContourGenerator(size_t width, size_t height, bool hasNoData,
33 : double noDataValue, ContourWriter &writer,
34 : LevelGenerator &levelGenerator)
35 : : width_(width), height_(height), hasNoData_(hasNoData),
36 : noDataValue_(noDataValue), previousLine_(), writer_(writer),
37 47 : levelGenerator_(levelGenerator)
38 : {
39 47 : previousLine_.resize(width_);
40 47 : std::fill(previousLine_.begin(), previousLine_.end(), NaN);
41 47 : }
42 :
43 4020 : CPLErr feedLine(const double *line)
44 : {
45 4020 : if (lineIdx_ <= height_)
46 : {
47 4020 : feedLine_(line);
48 4020 : if (lineIdx_ == height_)
49 : {
50 : // last line
51 46 : feedLine_(nullptr);
52 : }
53 : }
54 4020 : return CE_None;
55 : }
56 :
57 : private:
58 : size_t width_;
59 : size_t height_;
60 : bool hasNoData_;
61 : double noDataValue_;
62 :
63 : size_t lineIdx_ = 0;
64 :
65 : std::vector<double> previousLine_;
66 :
67 : ContourWriter &writer_;
68 : LevelGenerator &levelGenerator_;
69 :
70 : class ExtendedLine
71 : {
72 : public:
73 8132 : ExtendedLine(const double *line, size_t size, bool hasNoData,
74 : double noDataValue)
75 : : line_(line), size_(size), hasNoData_(hasNoData),
76 8132 : noDataValue_(noDataValue)
77 : {
78 8132 : }
79 :
80 2403948 : double value(int idx) const
81 : {
82 2403948 : if (line_ == nullptr)
83 8132 : return NaN;
84 2395816 : if (idx < 0 || idx >= int(size_))
85 16172 : return NaN;
86 2379642 : double v = line_[idx];
87 2379642 : if (hasNoData_ && v == noDataValue_)
88 0 : return NaN;
89 2379642 : return v;
90 : }
91 :
92 : private:
93 : const double *line_;
94 : size_t size_;
95 : bool hasNoData_;
96 : double noDataValue_;
97 : };
98 :
99 4066 : void feedLine_(const double *line)
100 : {
101 4066 : writer_.beginningOfLine();
102 :
103 4066 : ExtendedLine previous(&previousLine_[0], width_, hasNoData_,
104 : noDataValue_);
105 4066 : ExtendedLine current(line, width_, hasNoData_, noDataValue_);
106 605053 : for (int colIdx = -1; colIdx < int(width_); colIdx++)
107 : {
108 600987 : const ValuedPoint upperLeft(colIdx + 1 - .5, lineIdx_ - .5,
109 : previous.value(colIdx));
110 600987 : const ValuedPoint upperRight(colIdx + 1 + .5, lineIdx_ - .5,
111 : previous.value(colIdx + 1));
112 600987 : const ValuedPoint lowerLeft(colIdx + 1 - .5, lineIdx_ + .5,
113 : current.value(colIdx));
114 600987 : const ValuedPoint lowerRight(colIdx + 1 + .5, lineIdx_ + .5,
115 : current.value(colIdx + 1));
116 :
117 1201974 : Square(upperLeft, upperRight, lowerLeft, lowerRight)
118 600987 : .process(levelGenerator_, writer_);
119 : }
120 4066 : if (line != nullptr)
121 4020 : std::copy(line, line + width_, previousLine_.begin());
122 4066 : lineIdx_++;
123 :
124 4066 : writer_.endOfLine();
125 4066 : }
126 : };
127 :
128 : template <typename ContourWriter, typename LevelGenerator>
129 : inline ContourGenerator<ContourWriter, LevelGenerator> *
130 : newContourGenerator(size_t width, size_t height, bool hasNoData,
131 : double noDataValue, ContourWriter &writer,
132 : LevelGenerator &levelGenerator)
133 : {
134 : return new ContourGenerator<ContourWriter, LevelGenerator>(
135 : width, height, hasNoData, noDataValue, writer, levelGenerator);
136 : }
137 :
138 : template <typename ContourWriter, typename LevelGenerator>
139 : class ContourGeneratorFromRaster
140 : : public ContourGenerator<ContourWriter, LevelGenerator>
141 : {
142 : public:
143 31 : ContourGeneratorFromRaster(const GDALRasterBandH band, bool hasNoData,
144 : double noDataValue, ContourWriter &writer,
145 : LevelGenerator &levelGenerator)
146 : : ContourGenerator<ContourWriter, LevelGenerator>(
147 93 : GDALGetRasterBandXSize(band), GDALGetRasterBandYSize(band),
148 : hasNoData, noDataValue, writer, levelGenerator),
149 31 : band_(band)
150 : {
151 31 : }
152 :
153 31 : bool process(GDALProgressFunc progressFunc = nullptr,
154 : void *progressData = nullptr)
155 : {
156 31 : size_t width = GDALGetRasterBandXSize(band_);
157 31 : size_t height = GDALGetRasterBandYSize(band_);
158 62 : std::vector<double> line;
159 31 : line.resize(width);
160 :
161 4023 : for (size_t lineIdx = 0; lineIdx < height; lineIdx++)
162 : {
163 7986 : if (progressFunc &&
164 3993 : progressFunc(double(lineIdx) / height, "Processing line",
165 : progressData) == FALSE)
166 0 : return false;
167 :
168 : CPLErr error =
169 3993 : GDALRasterIO(band_, GF_Read, 0, int(lineIdx), int(width), 1,
170 3993 : &line[0], int(width), 1, GDT_Float64, 0, 0);
171 3993 : if (error != CE_None)
172 : {
173 1 : CPLDebug("CONTOUR", "failed fetch %d %d", int(lineIdx),
174 : int(width));
175 1 : return false;
176 : }
177 3992 : this->feedLine(&line[0]);
178 : }
179 30 : if (progressFunc)
180 30 : progressFunc(1.0, "", progressData);
181 30 : return true;
182 : }
183 :
184 : private:
185 : const GDALRasterBandH band_;
186 :
187 : ContourGeneratorFromRaster(const ContourGeneratorFromRaster &) = delete;
188 : ContourGeneratorFromRaster &
189 : operator=(const ContourGeneratorFromRaster &) = delete;
190 : };
191 :
192 : } // namespace marching_squares
193 :
194 : #endif
|