Tatooine
render_line.h
Go to the documentation of this file.
1#ifndef TATOOINE_RENDERING_RENDER_LINE_H
2#define TATOOINE_RENDERING_RENDER_LINE_H
3//==============================================================================
6#include <tatooine/vec.h>
7//==============================================================================
8namespace tatooine::rendering {
9//==============================================================================
10template <typename Real>
11auto render(Vec2<Real> p0, Vec2<Real> p1, int const line_width,
14 auto nearest_neighbor_grid = uniform_rectilinear_grid<Real, 2>{};
15 auto const& ax_x = grid.template dimension<0>();
16 auto nn_ax_x = ax_x;
17 nn_ax_x.front() -= ax_x.spacing() / 2;
18 nn_ax_x.back() -= ax_x.spacing() / 2;
19 nn_ax_x.push_back();
20 auto const& ax_y = grid.template dimension<1>();
21 auto nn_ax_y = ax_y;
22 nn_ax_y.front() -= ax_y.spacing() / 2;
23 nn_ax_y.back() -= ax_y.spacing() / 2;
24 nn_ax_y.push_back();
25
26 if ((p0.x() < nn_ax_x.front() && p1.x() < nn_ax_x.front()) ||
27 (p0.x() > nn_ax_x.back() && p1.x() > nn_ax_x.back()) ||
28 (p0.y() < nn_ax_y.front() && p1.y() < nn_ax_y.front()) ||
29 (p0.y() > nn_ax_y.back() && p1.y() > nn_ax_y.back())) {
30 return;
31 }
32
33 auto get_t = [](auto const a, auto const b, auto const c) {
34 return (c - a) / (b - a);
35 };
36 // clamp p0.x()
37 if (p0.x() < nn_ax_x.front()) {
38 auto const t = get_t(p0.x(), p1.x(), nn_ax_x.front());
39 p0 = vec{nn_ax_x.front(), p0.y() * (1 - t) + p1.y() * t};
40 } else if (p0.x() > nn_ax_x.back()) {
41 auto const t = get_t(p0.x(), p1.x(), nn_ax_x.back());
42 p0 = vec{nn_ax_x.back(), p0.y() * (1 - t) + p1.y() * t};
43 }
44 // clamp p1.x()
45 if (p1.x() <= nn_ax_x.front()) {
46 auto const t = get_t(p0.x(), p1.x(), nn_ax_x.front());
47 p1 = vec{nn_ax_x.front(), p0.y() * (1 - t) + p1.y() * t};
48 } else if (p1.x() > nn_ax_x.back()) {
49 auto const t = get_t(p0.x(), p1.x(), nn_ax_x.back());
50 p1 = vec{nn_ax_x.back(), p0.y() * (1 - t) + p1.y() * t};
51 }
52 // clamp p0.y()
53 if (p0.y() < nn_ax_y.front()) {
54 auto const t = get_t(p0.y(), p1.y(), nn_ax_y.front());
55 p0 = vec{p0.x() * (1 - t) + p1.x() * t, nn_ax_y.front()};
56 } else if (p0.y() > nn_ax_y.back()) {
57 auto const t = get_t(p0.y(), p1.y(), nn_ax_y.back());
58 p0 = vec{p0.x() * (1 - t) + p1.x() * t, nn_ax_y.back()};
59 }
60 // clamp p1.y()
61 if (p1.y() < nn_ax_y.front()) {
62 auto const t = get_t(p0.y(), p1.y(), nn_ax_y.front());
63 p1 = vec{p0.x() * (1 - t) + p1.x() * t, nn_ax_y.front()};
64 } else if (p1.y() > nn_ax_y.back()) {
65 auto const t = get_t(p0.y(), p1.y(), nn_ax_y.back());
66 p1 = vec{p0.x() * (1 - t) + p1.x() * t, nn_ax_y.back()};
67 }
68 auto ip0 = Vec2<std::size_t>{};
69 auto ip1 = Vec2<std::size_t>{};
70 // find ip0.x
71 for (std::size_t i = 0; i < size(nn_ax_x) - 1; ++i) {
72 if (nn_ax_x[i] <= p0.x() && p0.x() <= nn_ax_x[i + 1]) {
73 ip0.x() = i;
74 break;
75 }
76 }
77 // find ip1.x
78 for (std::size_t i = 0; i < size(nn_ax_x) - 1; ++i) {
79 if (nn_ax_x[i] <= p1.x() && p1.x() <= nn_ax_x[i + 1]) {
80 ip1.x() = i;
81 break;
82 }
83 }
84 // find ip0.y
85 for (std::size_t i = 0; i < size(nn_ax_y) - 1; ++i) {
86 if (nn_ax_y[i] <= p0.y() && p0.y() <= nn_ax_y[i + 1]) {
87 ip0.y() = i;
88 break;
89 }
90 }
91 // find ip1.y
92 for (std::size_t i = 0; i < size(nn_ax_y) - 1; ++i) {
93 if (nn_ax_y[i] <= p1.y() && p1.y() <= nn_ax_y[i + 1]) {
94 ip1.y() = i;
95 break;
96 }
97 }
98 auto const dist =
99 vec{std::max(ip0.x(), ip1.x()) - std::min(ip0.x(), ip1.x()),
100 std::max(ip0.y(), ip1.y()) - std::min(ip0.y(), ip1.y())};
101
102 auto dx = std::abs((long long)(ip1.x()) - (long long)(ip0.x()));
103 auto sx = ip0.x() < ip1.x() ? 1 : -1;
104 auto dy = -std::abs((long long)(ip1.y()) - (long long)(ip0.y()));
105 auto sy = ip0.y() < ip1.y() ? 1 : -1;
106 auto err = dx + dy;
107 auto e2 = (long long)(0); // error value e_xy
108 auto c = [&](auto const t, auto const ix, auto const iy) {
109 if (line_width == 1) {
110 callback(t, ix, iy);
111 } else {
112 auto const half_line_width = line_width / 2;
113 auto const m = 1 - line_width % 2;
114 if (dist.x() < dist.y()) {
115 for (int i = -half_line_width + m; i <= half_line_width; ++i) {
116 if (ix >= std::abs(i) &&
117 std::size_t(ix + i) < grid.template size<0>() - 1) {
118 callback(t, ix + i, iy);
119 }
120 }
121 } else {
122 for (int i = -half_line_width + m; i <= half_line_width; ++i) {
123 if (iy >= std::abs(i) &&
124 std::size_t(iy + i) < grid.template size<1>() - 1) {
125 callback(t, ix, iy + i);
126 }
127 }
128 }
129 }
130 };
131
132 auto const t_offset = Real(1) / (std::max(dist.x(), dist.y()) - 1);
133 auto i = std::size_t(0);
134 while (ip0.x() != ip1.x() || ip0.y() != ip1.y()) {
135 c(i++ * t_offset, ip0.x(), ip0.y());
136 e2 = 2 * err;
137 if (e2 > dy) {
138 err += dy;
139 ip0.x() += sx;
140 } // e_xy+e_x > 0
141 if (e2 < dx) {
142 err += dx;
143 ip0.y() += sy;
144 } // e_xy+e_y < 0
145 }
146 c(i++ * t_offset, ip1.x(), ip1.y());
147}
148//------------------------------------------------------------------------------
149template <typename Real, invocable<Real, std::size_t, std::size_t> Callback>
150auto render(Vec2<Real> const& p0, Vec2<Real> const& p1,
151 UniformRectilinearGrid2<Real> const& grid, Callback&& callback) {
152 render(p0, p1, 1, grid, std::forward<Callback>(callback));
153}
154//------------------------------------------------------------------------------
155template <typename Real, invocable<Real, std::size_t, std::size_t> Callback>
156auto render(Vec4<Real> p0, Vec4<Real> p1, int const line_width,
157 UniformRectilinearGrid2<Real> const& grid, camera auto const& cam,
158 Callback&& callback) {
159 render(cam.project(p0).xy(), cam.project(p1).xy(), line_width, grid,
160 std::forward<Callback>(callback));
161}
162//==============================================================================
163} // namespace tatooine::rendering
164//==============================================================================
165#endif
Definition: grid_edge.h:16
Definition: concepts.h:121
Definition: camera.h:312
Definition: camera.h:12
auto render(AABB3< Real > const &aabb, int const line_width, UniformRectilinearGrid2< Real > const &grid, camera auto const &cam, invocable< Real, typename AABB3< Real >::pos_type, typename AABB3< Real >::pos_type, std::size_t, std::size_t > auto &&callback)
Definition: render_axis_aligned_bounding_box.h:11
uniform_rectilinear_grid< Real, 2 > UniformRectilinearGrid2
Definition: rectilinear_grid.h:1912
detail::rectilinear_grid::creator_t< linspace< Real >, N > uniform_rectilinear_grid
Definition: rectilinear_grid.h:1904
auto size(vec< ValueType, N > const &v)
Definition: vec.h:148
Definition: vec.h:12
auto constexpr x() const -> auto const &requires(N >=1)
Definition: vec.h:102
auto constexpr y() const -> auto const &requires(N >=2)
Definition: vec.h:106