MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Geometry2D.cpp
Go to the documentation of this file.
1#include "Geometry2D.hpp"
2
3namespace MayaFlux::Kinesis {
4
5namespace {
6
7 constexpr uint32_t k_min_segments = 3;
8 constexpr uint32_t k_min_sides = 3;
9
10 [[nodiscard]] Kakshya::Vertex vert2(glm::vec2 p, glm::vec3 c) noexcept
11 {
12 return Kakshya::Vertex {
13 .position = { p.x, p.y, 0.F },
14 .color = c,
15 };
16 }
17
18 [[nodiscard]] Kakshya::LineVertex lvert2(glm::vec2 p, glm::vec3 c, float t) noexcept
19 {
20 return Kakshya::LineVertex {
21 .position = { p.x, p.y, 0.F },
22 .color = c,
23 .thickness = t,
24 };
25 }
26
27 [[nodiscard]] glm::vec2 ring_point(glm::vec2 center, float r, float angle) noexcept
28 {
29 return center + r * glm::vec2(std::cos(angle), std::sin(angle));
30 }
31
32} // namespace
33
34// =============================================================================
35// Filled shapes
36// =============================================================================
37
38std::vector<Kakshya::Vertex> filled_circle(
39 glm::vec2 center, float radius, uint32_t segments, glm::vec3 color)
40{
41 segments = std::max<uint32_t>(segments, k_min_segments);
42 const float step = glm::two_pi<float>() / static_cast<float>(segments);
43
44 std::vector<Kakshya::Vertex> out;
45 out.reserve(static_cast<size_t>(segments) * 3);
46
47 for (uint32_t i = 0; i < segments; ++i) {
48 const float a0 = static_cast<float>(i) * step;
49 const float a1 = static_cast<float>(i + 1) * step;
50 out.push_back(vert2(center, color));
51 out.push_back(vert2(ring_point(center, radius, a0), color));
52 out.push_back(vert2(ring_point(center, radius, a1), color));
53 }
54
55 return out;
56}
57
58std::vector<Kakshya::Vertex> filled_ring(
59 glm::vec2 center, float inner_r, float outer_r,
60 uint32_t segments, glm::vec3 color)
61{
62 segments = std::max<uint32_t>(segments, k_min_segments);
63 const float step = glm::two_pi<float>() / static_cast<float>(segments);
64
65 std::vector<Kakshya::Vertex> out;
66 out.reserve(static_cast<size_t>(segments) * 6);
67
68 for (uint32_t i = 0; i < segments; ++i) {
69 const float a0 = static_cast<float>(i) * step;
70 const float a1 = static_cast<float>(i + 1) * step;
71
72 const glm::vec2 oi0 = ring_point(center, inner_r, a0);
73 const glm::vec2 oo0 = ring_point(center, outer_r, a0);
74 const glm::vec2 oi1 = ring_point(center, inner_r, a1);
75 const glm::vec2 oo1 = ring_point(center, outer_r, a1);
76
77 out.push_back(vert2(oi0, color));
78 out.push_back(vert2(oo0, color));
79 out.push_back(vert2(oo1, color));
80
81 out.push_back(vert2(oi0, color));
82 out.push_back(vert2(oo1, color));
83 out.push_back(vert2(oi1, color));
84 }
85
86 return out;
87}
88
89std::vector<Kakshya::Vertex> filled_polygon(
90 glm::vec2 center, float radius, uint32_t sides,
91 float rotation_rad, glm::vec3 color)
92{
93 sides = std::max<uint32_t>(sides, k_min_sides);
94 const float step = glm::two_pi<float>() / static_cast<float>(sides);
95
96 std::vector<Kakshya::Vertex> out;
97 out.reserve((size_t)sides * 3);
98
99 for (uint32_t i = 0; i < sides; ++i) {
100 const float a0 = rotation_rad + static_cast<float>(i) * step;
101 const float a1 = rotation_rad + static_cast<float>(i + 1) * step;
102 out.push_back(vert2(center, color));
103 out.push_back(vert2(ring_point(center, radius, a0), color));
104 out.push_back(vert2(ring_point(center, radius, a1), color));
105 }
106
107 return out;
108}
109
110std::array<Kakshya::Vertex, 4> filled_rect_gradient(
111 AABB2D region,
112 glm::vec3 color_bl, glm::vec3 color_br,
113 glm::vec3 color_tl, glm::vec3 color_tr)
114{
115 return { {
116 { .position = { region.min.x, region.min.y, 0.F }, .color = color_bl },
117 { .position = { region.min.x, region.max.y, 0.F }, .color = color_tl },
118 { .position = { region.max.x, region.min.y, 0.F }, .color = color_br },
119 { .position = { region.max.x, region.max.y, 0.F }, .color = color_tr },
120 } };
121}
122
123std::vector<Kakshya::Vertex> filled_rounded_rect(
124 AABB2D region, float corner_radius,
125 uint32_t corner_segments, glm::vec3 color)
126{
127 corner_segments = std::max<uint32_t>(corner_segments, 1U);
128 const float max_r = std::min(region.width(), region.height()) * 0.5F;
129 const float r = std::min(corner_radius, max_r);
130
131 const glm::vec2 bl { region.min.x + r, region.min.y + r };
132 const glm::vec2 br { region.max.x - r, region.min.y + r };
133 const glm::vec2 tl { region.min.x + r, region.max.y - r };
134 const glm::vec2 tr { region.max.x - r, region.max.y - r };
135
136 std::vector<Kakshya::Vertex> out;
137 // 3 body rects (6 tris each) + 4 corner fans (corner_segments tris each)
138 out.reserve(18 + 4 * (size_t)corner_segments * 3);
139
140 // center rect
141 auto push_quad = [&](glm::vec2 a, glm::vec2 b, glm::vec2 c, glm::vec2 d) {
142 out.push_back(vert2(a, color));
143 out.push_back(vert2(b, color));
144 out.push_back(vert2(c, color));
145 out.push_back(vert2(b, color));
146 out.push_back(vert2(d, color));
147 out.push_back(vert2(c, color));
148 };
149
150 push_quad({ bl.x, region.min.y }, { tl.x, region.max.y }, { tr.x, region.min.y }, { tr.x, region.max.y });
151 push_quad({ region.min.x, bl.y }, { region.min.x, tl.y }, { bl.x, bl.y }, { bl.x, tl.y });
152 push_quad({ tr.x, br.y }, { tr.x, tr.y }, { region.max.x, br.y }, { region.max.x, tr.y });
153
154 // corner fans: BL, BR, TL, TR
155 struct Corner {
156 glm::vec2 c;
157 float a0;
158 };
159 const auto half_pi = glm::half_pi<float>();
160 const Corner corners[4] = {
161 { .c = bl, .a0 = glm::pi<float>() },
162 { .c = br, .a0 = -half_pi },
163 { .c = tl, .a0 = half_pi },
164 { .c = tr, .a0 = 0.F },
165 };
166
167 const float step = half_pi / static_cast<float>(corner_segments);
168 for (const auto& [c, a0] : corners) {
169 for (uint32_t i = 0; i < corner_segments; ++i) {
170 const float a1 = a0 + static_cast<float>(i) * step;
171 const float a2 = a0 + static_cast<float>(i + 1) * step;
172 out.push_back(vert2(c, color));
173 out.push_back(vert2(ring_point(c, r, a1), color));
174 out.push_back(vert2(ring_point(c, r, a2), color));
175 }
176 }
177
178 return out;
179}
180
181std::vector<Kakshya::Vertex> filled_arc(
182 glm::vec2 center, float radius,
183 float angle_start, float angle_end,
184 uint32_t segments, glm::vec3 color)
185{
186 segments = std::max<uint32_t>(segments, 1U);
187 const float step = (angle_end - angle_start) / static_cast<float>(segments);
188
189 std::vector<Kakshya::Vertex> out;
190 out.reserve(static_cast<size_t>(segments) * 3);
191
192 for (uint32_t i = 0; i < segments; ++i) {
193 const float a0 = angle_start + static_cast<float>(i) * step;
194 const float a1 = angle_start + static_cast<float>(i + 1) * step;
195 out.push_back(vert2(center, color));
196 out.push_back(vert2(ring_point(center, radius, a0), color));
197 out.push_back(vert2(ring_point(center, radius, a1), color));
198 }
199
200 return out;
201}
202
203std::vector<glm::vec2> arc_path(
204 glm::vec2 center,
205 float radius_x, float radius_y,
206 float angle_start, float angle_end,
207 uint32_t segments)
208{
209 segments = std::max<uint32_t>(segments, 1U);
210 const float step = (angle_end - angle_start) / static_cast<float>(segments);
211
212 std::vector<glm::vec2> out;
213 out.reserve(static_cast<size_t>(segments) + 1);
214 for (uint32_t i = 0; i <= segments; ++i) {
215 const float a = angle_start + static_cast<float>(i) * step;
216 out.push_back(center + glm::vec2(radius_x * std::cos(a), radius_y * std::sin(a)));
217 }
218 return out;
219}
220
221// =============================================================================
222// Outlines
223// =============================================================================
224
225std::vector<Kakshya::LineVertex> circle_outline(
226 glm::vec2 center, float radius, uint32_t segments,
227 glm::vec3 color, float thickness)
228{
229 segments = std::max<uint32_t>(segments, k_min_segments);
230 const float step = glm::two_pi<float>() / static_cast<float>(segments);
231
232 std::vector<Kakshya::LineVertex> out;
233 out.reserve(static_cast<size_t>(segments) * 2);
234
235 for (uint32_t i = 0; i < segments; ++i) {
236 const float a0 = static_cast<float>(i) * step;
237 const float a1 = static_cast<float>((i + 1) % segments) * step;
238 out.push_back(lvert2(ring_point(center, radius, a0), color, thickness));
239 out.push_back(lvert2(ring_point(center, radius, a1), color, thickness));
240 }
241
242 return out;
243}
244
245std::vector<Kakshya::LineVertex> arc_outline(
246 glm::vec2 center, float radius,
247 float angle_start, float angle_end,
248 uint32_t segments, glm::vec3 color, float thickness)
249{
250 segments = std::max<uint32_t>(segments, 1U);
251 const float step = (angle_end - angle_start) / static_cast<float>(segments);
252
253 std::vector<Kakshya::LineVertex> out;
254 out.reserve(static_cast<size_t>(segments) * 2);
255
256 for (uint32_t i = 0; i < segments; ++i) {
257 const float a0 = angle_start + static_cast<float>(i) * step;
258 const float a1 = angle_start + static_cast<float>(i + 1) * step;
259 out.push_back(lvert2(ring_point(center, radius, a0), color, thickness));
260 out.push_back(lvert2(ring_point(center, radius, a1), color, thickness));
261 }
262
263 return out;
264}
265
266std::array<Kakshya::LineVertex, 8> rect_outline(
267 AABB2D region, glm::vec3 color, float thickness)
268{
269 const glm::vec2 bl { region.min.x, region.min.y };
270 const glm::vec2 br { region.max.x, region.min.y };
271 const glm::vec2 tl { region.min.x, region.max.y };
272 const glm::vec2 tr { region.max.x, region.max.y };
273
274 return { {
275 lvert2(bl, color, thickness),
276 lvert2(br, color, thickness),
277 lvert2(br, color, thickness),
278 lvert2(tr, color, thickness),
279 lvert2(tr, color, thickness),
280 lvert2(tl, color, thickness),
281 lvert2(tl, color, thickness),
282 lvert2(bl, color, thickness),
283 } };
284}
285
286std::vector<Kakshya::LineVertex> polyline(
287 std::span<const glm::vec2> pts, glm::vec3 color, float thickness)
288{
289 if (pts.size() < 2)
290 return {};
291
292 std::vector<Kakshya::LineVertex> out;
293 out.reserve((pts.size() - 1) * 2);
294
295 for (size_t i = 0; i + 1 < pts.size(); ++i) {
296 out.push_back(lvert2(pts[i], color, thickness));
297 out.push_back(lvert2(pts[i + 1], color, thickness));
298 }
299
300 return out;
301}
302
303std::vector<Kakshya::LineVertex> polyline_colored(
304 std::span<const glm::vec2> pts,
305 std::span<const glm::vec3> colors,
306 float thickness)
307{
308 if (pts.size() < 2 || colors.size() != pts.size())
309 return {};
310
311 std::vector<Kakshya::LineVertex> out;
312 out.reserve((pts.size() - 1) * 2);
313
314 for (size_t i = 0; i + 1 < pts.size(); ++i) {
315 out.push_back(lvert2(pts[i], colors[i], thickness));
316 out.push_back(lvert2(pts[i + 1], colors[i + 1], thickness));
317 }
318
319 return out;
320}
321
322std::vector<Kakshya::LineVertex> polygon_outline(
323 glm::vec2 center, float radius, uint32_t sides,
324 float rotation_rad, glm::vec3 color, float thickness)
325{
326 sides = std::max<uint32_t>(sides, k_min_sides);
327 const float step = glm::two_pi<float>() / static_cast<float>(sides);
328
329 std::vector<Kakshya::LineVertex> out;
330 out.reserve((size_t)sides * 2);
331
332 for (uint32_t i = 0; i < sides; ++i) {
333 const float a0 = rotation_rad + static_cast<float>(i) * step;
334 const float a1 = rotation_rad + static_cast<float>((i + 1) % sides) * step;
335 out.push_back(lvert2(ring_point(center, radius, a0), color, thickness));
336 out.push_back(lvert2(ring_point(center, radius, a1), color, thickness));
337 }
338
339 return out;
340}
341
342} // namespace MayaFlux::Kinesis
size_t a
size_t b
std::vector< Kakshya::LineVertex > polygon_outline(glm::vec2 center, float radius, uint32_t sides, float rotation_rad, glm::vec3 color, float thickness)
Regular n-gon outline as a LINE_LIST (closed loop, 2 * sides vertices).
std::vector< Kakshya::Vertex > filled_circle(glm::vec2 center, float radius, uint32_t segments, glm::vec3 color)
Filled circle as a TRIANGLE_LIST triangle fan.
std::vector< Kakshya::Vertex > filled_ring(glm::vec2 center, float inner_r, float outer_r, uint32_t segments, glm::vec3 color)
Filled annulus (ring) as a TRIANGLE_LIST quad strip.
std::array< Kakshya::Vertex, 4 > filled_rect_gradient(AABB2D region, glm::vec3 color_bl, glm::vec3 color_br, glm::vec3 color_tl, glm::vec3 color_tr)
Filled rect with per-corner colors, TRIANGLE_STRIP (4 vertices).
std::array< Kakshya::LineVertex, 8 > rect_outline(AABB2D region, glm::vec3 color, float thickness)
Rectangle outline as a LINE_LIST (4 edges, 8 vertices).
std::vector< Kakshya::LineVertex > arc_outline(glm::vec2 center, float radius, float angle_start, float angle_end, uint32_t segments, glm::vec3 color, float thickness)
Arc outline as a LINE_LIST (open curve, 2 * segments vertices).
std::vector< Kakshya::LineVertex > polyline(std::span< const glm::vec2 > pts, glm::vec3 color, float thickness)
Polyline as a LINE_LIST (open path, 2 * (pts.size() - 1) vertices).
std::vector< Kakshya::LineVertex > circle_outline(glm::vec2 center, float radius, uint32_t segments, glm::vec3 color, float thickness)
Circle outline as a LINE_LIST (closed loop, 2 * segments vertices).
std::vector< Kakshya::Vertex > filled_polygon(glm::vec2 center, float radius, uint32_t sides, float rotation_rad, glm::vec3 color)
Filled regular n-gon as a TRIANGLE_LIST triangle fan.
std::vector< Kakshya::Vertex > filled_arc(glm::vec2 center, float radius, float angle_start, float angle_end, uint32_t segments, glm::vec3 color)
Filled circular arc sector (pie slice) as a TRIANGLE_LIST fan.
std::vector< Kakshya::Vertex > filled_rounded_rect(AABB2D region, float corner_radius, uint32_t corner_segments, glm::vec3 color)
Filled rounded rectangle as a TRIANGLE_LIST mesh.
std::vector< Kakshya::LineVertex > polyline_colored(std::span< const glm::vec2 > pts, std::span< const glm::vec3 > colors, float thickness)
Polyline with per-vertex colors as a LINE_LIST.
std::vector< glm::vec2 > arc_path(glm::vec2 center, float radius_x, float radius_y, float angle_start, float angle_end, uint32_t segments)
Sample a circular arc as ordered NDC positions.
float height() const noexcept
Definition Bounds.hpp:38
float width() const noexcept
Definition Bounds.hpp:37
Axis-aligned bounding rectangle in a 2D coordinate space.
Definition Bounds.hpp:21