olp-cpp-sdk 1.24.0
Loading...
Searching...
No Matches
PathTiling.h
1/*
2 * Copyright (C) 2025 HERE Europe B.V.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * SPDX-License-Identifier: Apache-2.0
17 * License-Filename: LICENSE
18 */
19
20#pragma once
21
22#include <memory>
23#include <utility>
24#include <vector>
25
26#include <olp/core/geo/coordinates/GeoCoordinates.h>
27#include <olp/core/geo/tiling/TileKey.h>
28#include <olp/core/geo/tiling/TileKeyUtils.h>
29#include <olp/core/porting/optional.h>
30
31namespace olp {
32namespace geo {
33
34namespace detail {
35
44 public:
49 struct State {
50 int32_t x_end;
51 bool is_slope_reversed;
52 int32_t sliding_window_half_size;
53 int32_t delta_x;
54 int32_t delta_y;
55 int32_t y_step;
56 int32_t x;
57 int32_t y;
58 int32_t error;
59 int32_t sliding_offset_x;
60 int32_t sliding_offset_y;
61 uint32_t tile_level;
62
63 bool operator==(const State& other) const {
64 return x_end == other.x_end &&
65 is_slope_reversed == other.is_slope_reversed &&
66 sliding_window_half_size == other.sliding_window_half_size &&
67 delta_x == other.delta_x && delta_y == other.delta_y &&
68 y_step == other.y_step && x == other.x && y == other.y &&
69 error == other.error &&
70 sliding_offset_x == other.sliding_offset_x &&
71 sliding_offset_y == other.sliding_offset_y &&
72 tile_level == other.tile_level;
73 }
74 };
75
83 static TileKey Value(const State& state) {
84 int tile_x = state.x + state.sliding_offset_x;
85 int tile_y = state.y + state.sliding_offset_y;
86
87 if (state.is_slope_reversed)
88 std::swap(tile_x, tile_y);
89
90 return TileKey::FromRowColumnLevel(tile_y, tile_x, state.tile_level);
91 }
92
100 static bool Iterate(State& state) { // NOLINT
101 if (state.x > state.x_end) {
102 return false;
103 }
104
105 if (++state.sliding_offset_y > state.sliding_window_half_size) {
106 state.sliding_offset_y = -state.sliding_window_half_size;
107 if (++state.sliding_offset_x > state.sliding_window_half_size) {
108 state.sliding_offset_x = -state.sliding_window_half_size;
109
110 state.error += state.delta_y;
111 if (state.error * 2 >= state.delta_x) {
112 state.y += state.y_step;
113 state.error -= state.delta_x;
114 }
115
116 ++state.x;
117 }
118 }
119
120 return true;
121 }
122
132 static State Init(const TileKey start_tile, const TileKey end_tile,
133 const int32_t sliding_window_half_size) {
134 int32_t x0 = static_cast<int32_t>(start_tile.Column());
135 int32_t y0 = static_cast<int32_t>(start_tile.Row());
136 int32_t x1 = static_cast<int32_t>(end_tile.Column());
137 int32_t y1 = static_cast<int32_t>(end_tile.Row());
138
139 const uint32_t tile_level = start_tile.Level();
140
141 const bool should_reverse_slope = std::abs(y1 - y0) > std::abs(x1 - x0);
142
143 if (should_reverse_slope) {
144 std::swap(x0, y0);
145 std::swap(x1, y1);
146 }
147
148 if (x0 > x1) {
149 std::swap(x0, x1);
150 std::swap(y0, y1);
151 }
152
153 const int32_t line_end = x1;
154 const int32_t delta_x = x1 - x0;
155 const int32_t delta_y = std::abs(y1 - y0);
156 const int32_t y_step = y0 > y1 ? -1 : 1;
157 const int32_t initial_x = x0;
158 const int32_t initial_y = y0;
159
160 return State{line_end,
161 should_reverse_slope,
162 sliding_window_half_size,
163 delta_x,
164 delta_y,
165 y_step,
166 initial_x,
167 initial_y,
168 0,
169 -sliding_window_half_size,
170 -sliding_window_half_size,
171 tile_level};
172 }
173};
174} // namespace detail
175
181template <typename InputIterator, typename TilingScheme>
183 public:
184 using value_type = TileKey;
185 using difference_type = std::ptrdiff_t;
186 using pointer = TileKey*;
187 using reference = TileKey&;
188 using iterator_category = std::forward_iterator_tag;
189
196 explicit TilingIterator(InputIterator iterator, const uint32_t tile_level = 0)
197 : iterator_(iterator), tiling_scheme_(), tile_level_(tile_level) {}
198
206 tiling_scheme_, static_cast<GeoCoordinates>(*iterator_), tile_level_);
207 }
208
209 TilingIterator& operator++() {
210 ++iterator_;
211 return *this;
212 }
213
214 bool operator==(const TilingIterator& other) const {
215 return iterator_ == other.iterator_;
216 }
217
218 bool operator!=(const TilingIterator& other) const {
219 return !(*this == other);
220 }
221
222 private:
223 InputIterator iterator_;
224 TilingScheme tiling_scheme_;
225 uint32_t tile_level_;
226};
227
234template <typename TilingScheme, typename InputIterator>
235auto MakeTilingIterator(InputIterator iterator, uint32_t tile_level = 0)
236 -> TilingIterator<InputIterator, TilingScheme> {
237 return TilingIterator<InputIterator, TilingScheme>(iterator, tile_level);
238}
239
244template <typename InputIterator>
246 public:
247 using value_type = std::pair<typename InputIterator::value_type,
248 typename InputIterator::value_type>;
249 using difference_type = std::ptrdiff_t;
250 using pointer = value_type*;
251 using reference = value_type&;
252 using iterator_category = std::forward_iterator_tag;
253
259 explicit AdjacentPairIterator(InputIterator segment_it)
260 : current_value_(), next_it_(segment_it) {}
261
268 AdjacentPairIterator(typename InputIterator::value_type initial_value,
269 InputIterator segment_it)
270 : current_value_(initial_value), next_it_(segment_it) {}
271
272 value_type operator*() const {
273 return std::make_pair(current_value_, *next_it_);
274 }
275
276 AdjacentPairIterator& operator++() {
277 current_value_ = *next_it_;
278 ++next_it_;
279 return *this;
280 }
281
282 bool operator==(const AdjacentPairIterator& other) const {
283 return next_it_ == other.next_it_;
284 }
285
286 bool operator!=(const AdjacentPairIterator& other) const {
287 return !(*this == other);
288 }
289
290 private:
291 typename InputIterator::value_type current_value_;
292 InputIterator next_it_;
293};
294
295/*
296 * @brief Creates an AdjacentPairIterator from a given iterator.
297 *
298 * @param iterator The input iterator.
299 *
300 * @return An AdjacentPairIterator initialized with the given iterator.
301 */
302template <typename InputIterator>
303auto MakeAdjacentPairIterator(InputIterator iterator)
304 -> AdjacentPairIterator<InputIterator> {
305 return AdjacentPairIterator<InputIterator>(iterator);
306}
307
308/*
309 * @brief Creates an AdjacentPairIterator from a given iterator.
310 *
311 * @param initial_value The initial value for the adjacent pair.
312 * @param iterator The input iterator.
313 *
314 * @return An AdjacentPairIterator initialized with the given iterator.
315 */
316template <typename InputIterator,
317 typename ValueType = typename InputIterator::value_type>
318auto MakeAdjacentPairIterator(ValueType initial_value, InputIterator iterator)
319 -> AdjacentPairIterator<InputIterator> {
320 return AdjacentPairIterator<InputIterator>(initial_value, iterator);
321}
322
323/*
324 * @brief Creates a range of AdjacentPairIterators from the given begin and end
325 * iterators.
326 *
327 * @param begin The beginning of the input range.
328 * @param end The end of the input range.
329 * @return A pair of AdjacentPairIterators representing the range.
330 */
331template <typename InputIterator,
332 typename IteratorType = AdjacentPairIterator<InputIterator>>
333auto MakeAdjacentPairsRange(InputIterator begin, InputIterator end)
334 -> std::pair<IteratorType, IteratorType> {
335 if (begin == end) {
336 return std::make_pair(MakeAdjacentPairIterator(begin),
337 MakeAdjacentPairIterator(end));
338 }
339 return std::make_pair(MakeAdjacentPairIterator(*begin, std::next(begin)),
340 MakeAdjacentPairIterator(end));
341}
342
350template <typename InputIterator>
352 public:
353 using value_type = typename InputIterator::value_type;
354 using difference_type = std::ptrdiff_t;
355 using pointer = value_type*;
356 using reference = value_type&;
357 using iterator_category = std::forward_iterator_tag;
358
365 explicit LineSliceIterator(InputIterator segment_it,
366 const uint32_t line_width)
367 : segment_it_(segment_it),
368 half_line_width_(static_cast<int32_t>(line_width) / 2) {}
369
370 TileKey operator*() {
371 if (!line_state_) {
372 TileKey begin, end;
373 std::tie(begin, end) = *segment_it_;
374 line_state_ = detail::LineEvaluator::Init(begin, end, half_line_width_);
375 }
376 return detail::LineEvaluator::Value(*line_state_);
377 }
378
379 LineSliceIterator& operator++() {
380 if (!line_state_ || !detail::LineEvaluator::Iterate(*line_state_)) {
381 line_state_ = porting::none;
382 ++segment_it_;
383 }
384 return *this;
385 }
386
387 bool operator==(const LineSliceIterator& other) const {
388 return segment_it_ == other.segment_it_ &&
389 half_line_width_ == other.half_line_width_ &&
390 line_state_ == other.line_state_;
391 }
392
393 bool operator!=(const LineSliceIterator& other) const {
394 return !(*this == other);
395 }
396
397 private:
398 InputIterator segment_it_;
399 int32_t half_line_width_;
400 porting::optional<detail::LineEvaluator::State> line_state_;
401};
402
410template <typename InputIterator>
411auto MakeLineSliceIterator(InputIterator iterator, const uint32_t line_width)
412 -> LineSliceIterator<InputIterator> {
413 return LineSliceIterator<InputIterator>(iterator, line_width);
414}
415
423template <typename InputIterator, typename TilingScheme>
424using TiledPathIterator = LineSliceIterator<
425 AdjacentPairIterator<TilingIterator<InputIterator, TilingScheme>>>;
426
447template <typename TilingScheme, typename InputIterator>
448auto MakeTiledPathRange(InputIterator begin, InputIterator end,
449 const uint32_t level, const uint32_t path_width)
450 -> std::pair<TiledPathIterator<InputIterator, TilingScheme>,
451 TiledPathIterator<InputIterator, TilingScheme>> {
452 auto adjacent_pairs_range =
453 MakeAdjacentPairsRange(MakeTilingIterator<TilingScheme>(begin, level),
454 MakeTilingIterator<TilingScheme>(end));
455 return {MakeLineSliceIterator(adjacent_pairs_range.first, path_width),
456 MakeLineSliceIterator(adjacent_pairs_range.second, path_width)};
457}
458
459} // namespace geo
460} // namespace olp
Iterator for iterating over adjacent pairs in a sequence.
Definition PathTiling.h:245
AdjacentPairIterator(InputIterator segment_it)
Constructs an AdjacentPairIterator.
Definition PathTiling.h:259
AdjacentPairIterator(typename InputIterator::value_type initial_value, InputIterator segment_it)
Constructs an AdjacentPairIterator with an initial value.
Definition PathTiling.h:268
A geographic location that uses the WGS84 Coordinate System.
Definition GeoCoordinates.h:38
An iterator that slices a line into tile segments.
Definition PathTiling.h:351
LineSliceIterator(InputIterator segment_it, const uint32_t line_width)
Constructs a LineSliceIterator.
Definition PathTiling.h:365
static TileKey GeoCoordinatesToTileKey(const ITilingScheme &tiling_scheme, const GeoCoordinates &geo_point, const std::uint32_t level)
Gets the key of the tile that contains geographic coordinates.
Addresses a tile in a quadtree.
Definition TileKey.h:63
static TileKey FromRowColumnLevel(std::uint32_t row, std::uint32_t column, std::uint32_t level)
Creates a tile key.
constexpr std::uint32_t Column() const
Gets the tile column.
Definition TileKey.h:224
constexpr std::uint32_t Row() const
Gets the tile row.
Definition TileKey.h:205
constexpr std::uint32_t Level() const
Gets the tile level.
Definition TileKey.h:196
Iterator for transforming input coordinates into TileKeys using a TilingScheme.
Definition PathTiling.h:182
value_type operator*() const
Dereference operator.
Definition PathTiling.h:204
TilingIterator(InputIterator iterator, const uint32_t tile_level=0)
Constructs a TilingIterator.
Definition PathTiling.h:196
Implements Bresenham's line algorithm with a square sliding window.
Definition PathTiling.h:43
static bool Iterate(State &state)
Iterates the state towards the end of the line.
Definition PathTiling.h:100
static State Init(const TileKey start_tile, const TileKey end_tile, const int32_t sliding_window_half_size)
Initializes the line state between two tiles.
Definition PathTiling.h:132
static TileKey Value(const State &state)
Evaluates the current tile key from the given state.
Definition PathTiling.h:83
Rules all the other namespaces.
Definition AppleSignInProperties.h:24
Holds the state of the line traversal.
Definition PathTiling.h:49