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 58 : 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 58 : levelGenerator_(levelGenerator)
38 : {
39 58 : previousLine_.resize(width_);
40 58 : std::fill(previousLine_.begin(), previousLine_.end(), NaN);
41 58 : }
42 :
43 5166 : CPLErr feedLine(const double *line)
44 : {
45 5166 : if (lineIdx_ <= height_)
46 : {
47 5166 : feedLine_(line);
48 5166 : if (lineIdx_ == height_)
49 : {
50 : // last line
51 57 : feedLine_(nullptr);
52 : }
53 : }
54 5166 : 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 10446 : ExtendedLine(const double *line, size_t size, bool hasNoData,
74 : double noDataValue)
75 : : line_(line), size_(size), hasNoData_(hasNoData),
76 10446 : noDataValue_(noDataValue)
77 : {
78 10446 : }
79 :
80 3131604 : double value(int idx) const
81 : {
82 3131604 : if (line_ == nullptr)
83 10446 : return NaN;
84 3121156 : if (idx < 0 || idx >= int(size_))
85 20778 : return NaN;
86 3100382 : double v = line_[idx];
87 3100382 : if (hasNoData_ && v == noDataValue_)
88 0 : return NaN;
89 3100382 : return v;
90 : }
91 :
92 : private:
93 : const double *line_;
94 : size_t size_;
95 : bool hasNoData_;
96 : double noDataValue_;
97 : };
98 :
99 5223 : void feedLine_(const double *line)
100 : {
101 5223 : writer_.beginningOfLine();
102 :
103 5223 : ExtendedLine previous(&previousLine_[0], width_, hasNoData_,
104 : noDataValue_);
105 5223 : ExtendedLine current(line, width_, hasNoData_, noDataValue_);
106 788125 : for (int colIdx = -1; colIdx < int(width_); colIdx++)
107 : {
108 782902 : const ValuedPoint upperLeft(colIdx + 1 - .5, lineIdx_ - .5,
109 : previous.value(colIdx));
110 782902 : const ValuedPoint upperRight(colIdx + 1 + .5, lineIdx_ - .5,
111 : previous.value(colIdx + 1));
112 782902 : const ValuedPoint lowerLeft(colIdx + 1 - .5, lineIdx_ + .5,
113 : current.value(colIdx));
114 782902 : const ValuedPoint lowerRight(colIdx + 1 + .5, lineIdx_ + .5,
115 : current.value(colIdx + 1));
116 :
117 1565802 : Square(upperLeft, upperRight, lowerLeft, lowerRight)
118 782902 : .process(levelGenerator_, writer_);
119 : }
120 5223 : if (line != nullptr)
121 5166 : std::copy(line, line + width_, previousLine_.begin());
122 5223 : lineIdx_++;
123 :
124 5223 : writer_.endOfLine();
125 5223 : }
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 41 : ContourGeneratorFromRaster(const GDALRasterBandH band, bool hasNoData,
144 : double noDataValue, ContourWriter &writer,
145 : LevelGenerator &levelGenerator)
146 : : ContourGenerator<ContourWriter, LevelGenerator>(
147 123 : GDALGetRasterBandXSize(band), GDALGetRasterBandYSize(band),
148 : hasNoData, noDataValue, writer, levelGenerator),
149 41 : band_(band)
150 : {
151 41 : }
152 :
153 41 : bool process(GDALProgressFunc progressFunc = nullptr,
154 : void *progressData = nullptr)
155 : {
156 41 : size_t width = GDALGetRasterBandXSize(band_);
157 41 : size_t height = GDALGetRasterBandYSize(band_);
158 82 : std::vector<double> line;
159 41 : line.resize(width);
160 :
161 5177 : for (size_t lineIdx = 0; lineIdx < height; lineIdx++)
162 : {
163 10274 : if (progressFunc &&
164 5137 : progressFunc(double(lineIdx) / height, "Processing line",
165 : progressData) == FALSE)
166 0 : return false;
167 :
168 : CPLErr error =
169 5137 : GDALRasterIO(band_, GF_Read, 0, int(lineIdx), int(width), 1,
170 5137 : &line[0], int(width), 1, GDT_Float64, 0, 0);
171 5137 : if (error != CE_None)
172 : {
173 1 : CPLDebug("CONTOUR", "failed fetch %d %d", int(lineIdx),
174 : int(width));
175 1 : return false;
176 : }
177 5136 : this->feedLine(&line[0]);
178 : }
179 40 : if (progressFunc)
180 40 : progressFunc(1.0, "", progressData);
181 40 : 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
|