olp-cpp-sdk  1.23.1
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 <boost/optional/optional.hpp>
30 
31 namespace olp {
32 namespace geo {
33 
34 namespace 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 
181 template <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 
234 template <typename TilingScheme, typename InputIterator>
235 auto MakeTilingIterator(InputIterator iterator, uint32_t tile_level = 0)
236  -> TilingIterator<InputIterator, TilingScheme> {
237  return TilingIterator<InputIterator, TilingScheme>(iterator, tile_level);
238 }
239 
244 template <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  */
302 template <typename InputIterator>
303 auto 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  */
316 template <typename InputIterator,
317  typename ValueType = typename InputIterator::value_type>
318 auto 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  */
331 template <typename InputIterator,
332  typename IteratorType = AdjacentPairIterator<InputIterator>>
333 auto 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 
350 template <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_ = boost::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  boost::optional<detail::LineEvaluator::State> line_state_;
401 };
402 
410 template <typename InputIterator>
411 auto MakeLineSliceIterator(InputIterator iterator, const uint32_t line_width)
412  -> LineSliceIterator<InputIterator> {
413  return LineSliceIterator<InputIterator>(iterator, line_width);
414 }
415 
423 template <typename InputIterator, typename TilingScheme>
424 using TiledPathIterator = LineSliceIterator<
425  AdjacentPairIterator<TilingIterator<InputIterator, TilingScheme>>>;
426 
447 template <typename TilingScheme, typename InputIterator>
448 auto 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:219
constexpr std::uint32_t Row() const
Gets the tile row.
Definition: TileKey.h:200
constexpr std::uint32_t Level() const
Gets the tile level.
Definition: TileKey.h:191
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