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 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #ifndef MARCHING_SQUARES_CONTOUR_GENERATOR_H
30 : #define MARCHING_SQUARES_CONTOUR_GENERATOR_H
31 :
32 : #include <vector>
33 : #include <algorithm>
34 :
35 : #include "gdal.h"
36 :
37 : #include "utility.h"
38 : #include "point.h"
39 : #include "square.h"
40 :
41 : namespace marching_squares
42 : {
43 :
44 : template <typename ContourWriter, typename LevelGenerator>
45 : class ContourGenerator
46 : {
47 : public:
48 42 : ContourGenerator(size_t width, size_t height, bool hasNoData,
49 : double noDataValue, ContourWriter &writer,
50 : LevelGenerator &levelGenerator)
51 : : width_(width), height_(height), hasNoData_(hasNoData),
52 : noDataValue_(noDataValue), previousLine_(), writer_(writer),
53 42 : levelGenerator_(levelGenerator)
54 : {
55 42 : previousLine_.resize(width_);
56 42 : std::fill(previousLine_.begin(), previousLine_.end(), NaN);
57 42 : }
58 :
59 2639 : CPLErr feedLine(const double *line)
60 : {
61 2639 : if (lineIdx_ <= height_)
62 : {
63 2639 : feedLine_(line);
64 2635 : if (lineIdx_ == height_)
65 : {
66 : // last line
67 37 : feedLine_(nullptr);
68 : }
69 : }
70 2635 : return CE_None;
71 : }
72 :
73 : private:
74 : size_t width_;
75 : size_t height_;
76 : bool hasNoData_;
77 : double noDataValue_;
78 :
79 : size_t lineIdx_ = 0;
80 :
81 : std::vector<double> previousLine_;
82 :
83 : ContourWriter &writer_;
84 : LevelGenerator &levelGenerator_;
85 :
86 : class ExtendedLine
87 : {
88 : public:
89 5352 : ExtendedLine(const double *line, size_t size, bool hasNoData,
90 : double noDataValue)
91 : : line_(line), size_(size), hasNoData_(hasNoData),
92 5352 : noDataValue_(noDataValue)
93 : {
94 5352 : }
95 :
96 1589640 : double value(int idx) const
97 : {
98 1589640 : if (line_ == nullptr)
99 5344 : return NaN;
100 1584296 : if (idx < 0 || idx >= int(size_))
101 10622 : return NaN;
102 1573674 : double v = line_[idx];
103 1573674 : if (hasNoData_ && v == noDataValue_)
104 12 : return NaN;
105 1573662 : return v;
106 : }
107 :
108 : private:
109 : const double *line_;
110 : size_t size_;
111 : bool hasNoData_;
112 : double noDataValue_;
113 : };
114 :
115 2676 : void feedLine_(const double *line)
116 : {
117 2676 : writer_.beginningOfLine();
118 :
119 2676 : ExtendedLine previous(&previousLine_[0], width_, hasNoData_,
120 : noDataValue_);
121 2676 : ExtendedLine current(line, width_, hasNoData_, noDataValue_);
122 400082 : for (int colIdx = -1; colIdx < int(width_); colIdx++)
123 : {
124 397410 : const ValuedPoint upperLeft(colIdx + 1 - .5, lineIdx_ - .5,
125 : previous.value(colIdx));
126 397410 : const ValuedPoint upperRight(colIdx + 1 + .5, lineIdx_ - .5,
127 : previous.value(colIdx + 1));
128 397410 : const ValuedPoint lowerLeft(colIdx + 1 - .5, lineIdx_ + .5,
129 : current.value(colIdx));
130 397410 : const ValuedPoint lowerRight(colIdx + 1 + .5, lineIdx_ + .5,
131 : current.value(colIdx + 1));
132 :
133 794820 : Square(upperLeft, upperRight, lowerLeft, lowerRight)
134 397410 : .process(levelGenerator_, writer_);
135 : }
136 2672 : if (line != nullptr)
137 2635 : std::copy(line, line + width_, previousLine_.begin());
138 2672 : lineIdx_++;
139 :
140 2672 : writer_.endOfLine();
141 2672 : }
142 : };
143 :
144 : template <typename ContourWriter, typename LevelGenerator>
145 : inline ContourGenerator<ContourWriter, LevelGenerator> *
146 : newContourGenerator(size_t width, size_t height, bool hasNoData,
147 : double noDataValue, ContourWriter &writer,
148 : LevelGenerator &levelGenerator)
149 : {
150 : return new ContourGenerator<ContourWriter, LevelGenerator>(
151 : width, height, hasNoData, noDataValue, writer, levelGenerator);
152 : }
153 :
154 : template <typename ContourWriter, typename LevelGenerator>
155 : class ContourGeneratorFromRaster
156 : : public ContourGenerator<ContourWriter, LevelGenerator>
157 : {
158 : public:
159 26 : ContourGeneratorFromRaster(const GDALRasterBandH band, bool hasNoData,
160 : double noDataValue, ContourWriter &writer,
161 : LevelGenerator &levelGenerator)
162 : : ContourGenerator<ContourWriter, LevelGenerator>(
163 78 : GDALGetRasterBandXSize(band), GDALGetRasterBandYSize(band),
164 : hasNoData, noDataValue, writer, levelGenerator),
165 26 : band_(band)
166 : {
167 26 : }
168 :
169 26 : bool process(GDALProgressFunc progressFunc = nullptr,
170 : void *progressData = nullptr)
171 : {
172 26 : size_t width = GDALGetRasterBandXSize(band_);
173 26 : size_t height = GDALGetRasterBandYSize(band_);
174 52 : std::vector<double> line;
175 26 : line.resize(width);
176 :
177 2633 : for (size_t lineIdx = 0; lineIdx < height; lineIdx++)
178 : {
179 5224 : if (progressFunc &&
180 2612 : progressFunc(double(lineIdx) / height, "Processing line",
181 : progressData) == FALSE)
182 0 : return false;
183 :
184 : CPLErr error =
185 2612 : GDALRasterIO(band_, GF_Read, 0, int(lineIdx), int(width), 1,
186 2612 : &line[0], int(width), 1, GDT_Float64, 0, 0);
187 2612 : if (error != CE_None)
188 : {
189 1 : CPLDebug("CONTOUR", "failed fetch %d %d", int(lineIdx),
190 : int(width));
191 1 : return false;
192 : }
193 2611 : this->feedLine(&line[0]);
194 : }
195 21 : if (progressFunc)
196 21 : progressFunc(1.0, "", progressData);
197 21 : return true;
198 : }
199 :
200 : private:
201 : const GDALRasterBandH band_;
202 :
203 : ContourGeneratorFromRaster(const ContourGeneratorFromRaster &) = delete;
204 : ContourGeneratorFromRaster &
205 : operator=(const ContourGeneratorFromRaster &) = delete;
206 : };
207 :
208 : } // namespace marching_squares
209 :
210 : #endif
|