libtcod
Loading...
Searching...
No Matches
bresenham.hpp
Go to the documentation of this file.
1/* BSD 3-Clause License
2 *
3 * Copyright © 2008-2026, Jice and the libtcod contributors.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * 3. Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
34#pragma once
35#ifndef TCOD_BRESENHAM_HPP_
36#define TCOD_BRESENHAM_HPP_
37
38#include <array>
39#include <functional>
40#include <iterator>
41#include <vector>
42
43#include "bresenham.h"
44
47
48class TCODLIB_API TCODLineListener {
49 public:
50 virtual bool putPoint(int x, int y) = 0;
51 virtual ~TCODLineListener() {}
52};
53// clang-format off
54class TCODLIB_API TCODLine {
55public :
71 static void init(int xFrom, int yFrom, int xTo, int yTo);
72
112 static bool step(int *xCur, int *yCur);
113
153 static bool line(int xFrom, int yFrom, int xTo, int yTo, TCODLineListener *listener);
154};
155// clang-format on
157namespace tcod {
160
165class BresenhamLine {
166 public:
167 using Point2 = std::array<int, 2>;
168 using iterator_category = std::random_access_iterator_tag;
169 using value_type = Point2;
170 using difference_type = int;
171 using pointer = void;
172 using reference = value_type;
178 explicit BresenhamLine(Point2 begin, Point2 end) noexcept
179 : origin_{begin},
180 dest_{end},
181 index_{0},
182 index_end_{get_delta_x() + 1},
183 cursor_{0, 0},
184 y_error_{-get_delta_x() / 2} {}
188 explicit BresenhamLine(Point2 begin, Point2 end, int error) noexcept
189 : origin_{begin},
190 dest_{end},
191 index_{0},
192 index_end_{get_delta_x() + 1},
193 cursor_{0, 0},
194 y_error_{error > 0 ? error % get_delta_x() - get_delta_x() : error % get_delta_x()} {}
195
196 inline BresenhamLine& operator++() noexcept {
197 ++index_;
198 return *this;
199 }
200 inline BresenhamLine operator++(int) noexcept {
201 auto tmp = *this;
202 ++(*this);
203 return tmp;
204 }
205 inline BresenhamLine& operator--() noexcept {
206 --index_;
207 return *this;
208 }
209 inline BresenhamLine operator--(int) noexcept {
210 auto tmp = *this;
211 --(*this);
212 return tmp;
213 }
222 inline value_type operator[](int index) noexcept { return bresenham_get(index_ + index); }
226 inline value_type operator*() noexcept { return (*this)[0]; }
227 inline constexpr bool operator==(const BresenhamLine& rhs) const noexcept { return index_ == rhs.index_; }
228 inline constexpr bool operator!=(const BresenhamLine& rhs) const noexcept { return !(*this == rhs); }
229 inline constexpr difference_type operator-(const BresenhamLine& rhs) const noexcept { return index_ - rhs.index_; }
230
242 inline BresenhamLine adjust_range(int shift_begin, int shift_end) const noexcept {
243 BresenhamLine new_data{*this};
244 new_data.index_ += shift_begin;
245 new_data.index_end_ += shift_end;
246 new_data.index_end_ = std::max(new_data.index_, new_data.index_end_);
247 return new_data;
248 }
258 inline BresenhamLine without_start() const noexcept { return adjust_range(1, 0); }
268 inline BresenhamLine without_end() const noexcept { return adjust_range(0, -1); }
278 inline BresenhamLine without_endpoints() const noexcept { return adjust_range(1, -1); }
282 inline BresenhamLine begin() const noexcept { return {*this}; }
286 inline BresenhamLine end() const noexcept {
287 return BresenhamLine{origin_, dest_, index_end_, index_end_, cursor_, y_error_};
288 }
289
290 private:
294 struct Matrix {
298 inline Point2 transform(const Point2& cursor) const noexcept {
299 return {ax + cursor.at(0) * xx + cursor.at(1) * yx, ay + cursor.at(0) * xy + cursor.at(1) * yy};
300 }
301 int ax; // Affine transformation on X.
302 int ay; // Affine transformation on Y.
303 int_fast8_t xx; // Index to world X.
304 int_fast8_t xy; // Index to world Y.
305 int_fast8_t yx; // Cursor Y to world X.
306 int_fast8_t yy; // Cursor Y to world Y.
307 };
311 inline Matrix get_matrix() const noexcept { return get_matrix(origin_, dest_); }
312 static Matrix get_matrix(const Point2& origin, const Point2& dest) noexcept {
313 const int delta_x = dest.at(0) - origin.at(0);
314 const int delta_y = dest.at(1) - origin.at(1);
315 Matrix matrix{
316 origin.at(0),
317 origin.at(1),
318 1,
319 0,
320 0,
321 1,
322 };
323 if (delta_x < 0) matrix.xx = -1;
324 if (delta_y < 0) matrix.yy = -1;
325 if (std::abs(delta_y) > std::abs(delta_x)) {
326 std::swap(matrix.xx, matrix.yx);
327 std::swap(matrix.xy, matrix.yy);
328 }
329 return matrix;
330 }
331 explicit BresenhamLine(Point2 begin, Point2 end, int index_begin, int index_end, Point2 cursor, int error) noexcept
332 : origin_{begin}, dest_{end}, index_{index_begin}, index_end_{index_end}, cursor_{cursor}, y_error_{error} {}
338 inline Point2 get_normalized_delta() const noexcept { return get_normalized_delta(origin_, dest_); }
339 static Point2 get_normalized_delta(const Point2& origin, const Point2& dest) noexcept {
340 return std::abs(dest.at(0) - origin.at(0)) > std::abs(dest.at(1) - origin.at(1))
341 ? Point2{std::abs(dest.at(0) - origin.at(0)), std::abs(dest.at(1) - origin.at(1))}
342 : Point2{std::abs(dest.at(1) - origin.at(1)), std::abs(dest.at(0) - origin.at(0))};
343 }
349 inline int get_delta_x() const noexcept { return get_normalized_delta().at(0); }
353 inline BresenhamLine& bresenham_next() {
354 const Point2 delta = get_normalized_delta();
355 y_error_ += delta.at(1);
356 if (y_error_ > 0) {
357 ++cursor_.at(1);
358 y_error_ -= delta.at(0);
359 };
360 ++cursor_.at(0);
361 return *this;
362 }
366 inline BresenhamLine& bresenham_prev() {
367 const Point2 delta = get_normalized_delta();
368 y_error_ -= delta.at(1);
369 if (y_error_ <= -delta.at(0)) {
370 --cursor_.at(1);
371 y_error_ += delta.at(0);
372 };
373 --cursor_.at(0);
374 return *this;
375 }
379 inline Point2 bresenham_get(int index) {
380 while (cursor_.at(0) < index) bresenham_next();
381 while (cursor_.at(0) > index) bresenham_prev();
382 return get_matrix().transform(cursor_);
383 }
384 Point2 origin_; // Starting point.
385 Point2 dest_; // Ending point.
386 int index_; // The starting index returned by `begin`.
387 int index_end_; // The past-the-end index returned by `end`.
388 Point2 cursor_; // Normalized Bresenham low-slope position. First axis acts as the current index.
389 int y_error_; // Fractional difference between Y indexes. Is always `-delta[0] < err <= 0`.
390};
392} // namespace tcod
393#endif // TCOD_BRESENHAM_HPP_
Bresenham line module.
Definition bresenham.hpp:54
static void init(int xFrom, int yFrom, int xTo, int yTo)
First, you have to initialize the toolkit with your starting and ending coordinates.
static bool line(int xFrom, int yFrom, int xTo, int yTo, TCODLineListener *listener)
The function returns false if the line has been interrupted by the callback (it returned false before...
static bool step(int *xCur, int *yCur)
You can then step through each cell with this function.
Definition bresenham.hpp:48
The libtcod namespace.
Definition color.hpp:45