2#ifndef UFO_VIZ_TRIANGULATE_HPP
3#define UFO_VIZ_TRIANGULATE_HPP
10#include <ufo/geometry/cone.hpp>
11#include <ufo/geometry/cylinder.hpp>
12#include <ufo/geometry/line_segment.hpp>
13#include <ufo/geometry/sphere.hpp>
14#include <ufo/numeric/vec3.hpp>
15#include <ufo/plan/graph.hpp>
16#include <ufo/plan/path.hpp>
19 Vertex(
float x,
float y,
float z,
float nx,
float ny,
float nz)
20 : pos{x, y, z}, _pad0(0.0f), normal{nx, ny, nz}, _pad1(0.0f)
24 : pos(pos), _pad0(0.0f), normal(normal), _pad1(0.0f)
34template <
class Vertex>
36 std::vector<Vertex> vertices;
37 std::vector<std::uint32_t> indices;
40template <
class Vertex>
51 for (
int i = 0; i <= num_stacks; ++i) {
52 float phi = M_PI * i / num_stacks;
53 for (
int j = 0; j <= num_slices; ++j) {
54 float theta = 2 * M_PI * j / num_slices;
56 float x = sphere.radius * std::sin(phi) * std::cos(theta) + sphere.center.x;
57 float y = sphere.radius * std::sin(phi) * std::sin(theta) + sphere.center.y;
58 float z = sphere.radius * std::cos(phi) + sphere.center.z;
60 float nx = (x - sphere.center.x) / sphere.radius;
61 float ny = (y - sphere.center.y) / sphere.radius;
62 float nz = (z - sphere.center.z) / sphere.radius;
64 result.vertices.push_back({x, y, z, nx, ny, nz});
69 for (
int i = 0; i < num_stacks; ++i) {
70 for (
int j = 0; j < num_slices; ++j) {
71 int first = i * (num_slices + 1) + j;
72 int second = first + num_slices + 1;
74 result.indices.push_back(first);
75 result.indices.push_back(second);
76 result.indices.push_back(first + 1);
78 result.indices.push_back(second);
79 result.indices.push_back(second + 1);
80 result.indices.push_back(first + 1);
94 for (
int i = 0; i <= num_stacks; ++i) {
95 float phi = M_PI * i / num_stacks;
96 for (
int j = 0; j <= num_slices; ++j) {
97 float theta = 2 * M_PI * j / num_slices;
99 float x = sphere.radius * std::sin(phi) * std::cos(theta) + sphere.center.x;
100 float y = sphere.radius * std::sin(phi) * std::sin(theta) + sphere.center.y;
101 float z = sphere.radius * std::cos(phi) + sphere.center.z;
103 result.vertices.push_back({x, y, z});
108 for (
int i = 0; i < num_stacks; ++i) {
109 for (
int j = 0; j < num_slices; ++j) {
110 int first = i * (num_slices + 1) + j;
111 int second = first + num_slices + 1;
113 result.indices.push_back(first);
114 result.indices.push_back(second);
115 result.indices.push_back(first + 1);
117 result.indices.push_back(second);
118 result.indices.push_back(second + 1);
119 result.indices.push_back(first + 1);
126template <
class Vertex>
135 ufo::Vec3f direction = cylinder.center_2 - cylinder.center_1;
140 if (std::abs(
dot(axis, up)) > 0.99f) {
147 result.vertices.push_back({cylinder.center_1, -direction});
148 result.vertices.push_back({cylinder.center_2, direction});
150 float angle_step = 2 * M_PI / segments;
153 for (
int i = 0; i <= segments; ++i) {
154 float angle = i * angle_step;
155 float x = cylinder.
radius * std::cos(angle);
156 float y = cylinder.
radius * std::sin(angle);
161 ufo::Vec3f top_vertex = cylinder.center_1 + p;
162 result.vertices.push_back({top_vertex, p / cylinder.
radius});
165 ufo::Vec3f bottom_vertex = cylinder.center_2 + p;
166 result.vertices.push_back({bottom_vertex, p / cylinder.
radius});
171 for (
int i = 0; i <= segments; ++i) {
172 result.indices.push_back(0);
173 result.indices.push_back(2 * i);
174 result.indices.push_back(2 * i + 2);
176 result.indices.push_back(1);
177 result.indices.push_back(2 * i + 1);
178 result.indices.push_back(2 * i + 3);
182 for (
int i = 0; i < segments; ++i) {
183 int top_index = 2 * i + 2;
184 int bottom_index = top_index + 1;
186 result.indices.push_back(top_index);
187 result.indices.push_back(bottom_index);
188 result.indices.push_back(top_index + 2);
190 result.indices.push_back(bottom_index);
191 result.indices.push_back(bottom_index + 2);
192 result.indices.push_back(top_index + 2);
204 ufo::Vec3f direction = cylinder.center_2 - cylinder.center_1;
209 if (std::abs(
dot(axis, up)) > 0.99f) {
216 result.vertices.push_back(cylinder.center_1);
217 result.vertices.push_back(cylinder.center_2);
219 float angle_step = 2 * M_PI / segments;
222 for (
int i = 0; i <= segments; ++i) {
223 float angle = i * angle_step;
224 float x = cylinder.
radius * std::cos(angle);
225 float y = cylinder.
radius * std::sin(angle);
230 ufo::Vec3f top_vertex = cylinder.center_1 + p;
231 result.vertices.push_back(top_vertex);
234 ufo::Vec3f bottom_vertex = cylinder.center_2 + p;
235 result.vertices.push_back(bottom_vertex);
240 for (
int i = 0; i <= segments; ++i) {
241 result.indices.push_back(0);
242 result.indices.push_back(2 * i);
243 result.indices.push_back(2 * i + 2);
245 result.indices.push_back(1);
246 result.indices.push_back(2 * i + 1);
247 result.indices.push_back(2 * i + 3);
251 for (
int i = 0; i < segments; ++i) {
252 int top_index = 2 * i + 2;
253 int bottom_index = top_index + 1;
255 result.indices.push_back(top_index);
256 result.indices.push_back(bottom_index);
257 result.indices.push_back(top_index + 2);
259 result.indices.push_back(bottom_index);
260 result.indices.push_back(bottom_index + 2);
261 result.indices.push_back(top_index + 2);
267template <
class Vertex>
275 auto dir =
normalize(cone.tip - cone.base_center);
277 result.vertices.push_back({cone.base_center, -dir});
278 result.vertices.push_back({cone.tip, dir});
282 if (std::abs(
dot(dir, up)) > 0.99f) {
290 float angle_step = 2 * M_PI / segments;
293 for (
int i = 0; i <= segments; ++i) {
294 float angle = i * angle_step;
295 float x = cone.radius * std::cos(angle);
296 float y = cone.radius * std::sin(angle);
298 auto p = x * right + y * forward;
299 result.vertices.push_back({cone.base_center + p, p / cone.radius});
303 for (
int i = 2; i <= segments + 1; ++i) {
304 result.indices.push_back(0);
305 result.indices.push_back(i);
306 result.indices.push_back(i + 1);
310 for (
int i = 2; i <= segments + 1; ++i) {
311 result.indices.push_back(1);
312 result.indices.push_back(i);
313 result.indices.push_back(i + 1);
324 auto dir =
normalize(cone.tip - cone.base_center);
326 result.vertices.push_back(cone.base_center);
327 result.vertices.push_back(cone.tip);
331 if (std::abs(
dot(dir, up)) > 0.99f) {
339 float angle_step = 2 * M_PI / segments;
342 for (
int i = 0; i <= segments; ++i) {
343 float angle = i * angle_step;
344 float x = cone.radius * std::cos(angle);
345 float y = cone.radius * std::sin(angle);
347 auto p = x * right + y * forward;
348 result.vertices.push_back(cone.base_center + p);
352 for (
int i = 2; i <= segments + 1; ++i) {
353 result.indices.push_back(0);
354 result.indices.push_back(i);
355 result.indices.push_back(i + 1);
359 for (
int i = 2; i <= segments + 1; ++i) {
360 result.indices.push_back(1);
361 result.indices.push_back(i);
362 result.indices.push_back(i + 1);
368template <
class Vertex>
373 return triangulate<Vertex>(cylinder, segments);
376template <
class Vertex>
378 float radius,
float tip_height,
384 auto b = tip_end - dir * tip_height;
386 auto cylinder = triangulate<Vertex>(
ufo::Cylinder(start, b, radius), num_slices);
387 auto cone = triangulate<Vertex>(ufo::Cone(b, tip_end, 2 * radius), num_slices);
388 for (std::size_t i{}; i < cone.indices.size(); ++i) {
389 cone.indices[i] += cylinder.vertices.size();
392 result.vertices.insert(result.vertices.end(), cylinder.vertices.begin(),
393 cylinder.vertices.
end());
394 result.indices.insert(result.indices.end(), cylinder.indices.begin(),
395 cylinder.indices.
end());
397 result.vertices.insert(result.vertices.end(), cone.vertices.begin(),
398 cone.vertices.end());
399 result.indices.insert(result.indices.end(), cone.indices.begin(), cone.indices.end());
404template <
class Vertex>
406 float node_radius,
float edge_radius,
407 int segments,
bool edge_as_arrow =
false,
408 float arrow_head_length = 0.0f)
413 for (
auto [p, n] : graph) {
418 triangulate<Vertex>(ufo::BS3(center, node_radius), segments, segments / 2);
419 for (std::size_t i{}; i < sphere.indices.size(); ++i) {
420 sphere.indices[i] += result.vertices.size();
423 result.vertices.insert(result.vertices.end(), sphere.vertices.begin(),
424 sphere.vertices.end());
425 result.indices.insert(result.indices.end(), sphere.indices.begin(),
426 sphere.indices.end());
430 for (
auto e : n->edges) {
431 auto start =
static_cast<ufo::Vec3f>(*(e.from));
433 auto t = edge_as_arrow ? triangulateArrow<Vertex>(start, end, edge_radius,
434 arrow_head_length, segments)
436 ufo::Cylinder3(start, end, edge_radius), segments);
437 for (std::size_t i{}; i < t.indices.size(); ++i) {
438 t.indices[i] += result.vertices.size();
441 result.vertices.insert(result.vertices.end(), t.vertices.begin(), t.vertices.end());
442 result.indices.insert(result.indices.end(), t.indices.begin(), t.indices.end());
449template <
class Vertex>
451 int segments,
bool use_arrow =
true,
452 float arrow_head_height = 0.5f)
456 for (std::size_t i{}; i < path.size() - 1; ++i) {
461 ? triangulateArrow<Vertex>(a, b, radius, arrow_head_height, segments)
462 : triangulate<
Vertex>(
ufo::Cylinder3(
a,
b, radius), segments);
463 for (std::size_t i{}; i < t.indices.size(); ++i) {
464 t.indices[i] += result.vertices.size();
467 result.vertices.insert(result.vertices.end(), t.vertices.begin(), t.vertices.end());
468 result.indices.insert(result.indices.end(), t.indices.begin(), t.indices.end());
T angle(Quat< T > const &q) noexcept
Extracts the rotation angle (in radians) from a unit quaternion.
constexpr T dot(Quat< T > const &a, Quat< T > const &b) noexcept
Computes the four-component dot product a.w*b.w + a.x*b.x + a.y*b.y + a.z*b.z.
All vision-related classes and functions.
constexpr T b(Lab< T, Flags > color) noexcept
Returns the un-weighted blue–yellow axis value.
constexpr T a(Lab< T, Flags > color) noexcept
Returns the un-weighted green–red axis value.
constexpr Quat< T > normalize(Quat< T > const &q) noexcept
Returns a unit quaternion in the same direction as q.
constexpr Quat< T > cross(Quat< T > const &q1, Quat< T > const &q2) noexcept
Computes the Hamilton cross product of two quaternions.
Vec< 3, T > axis(Quat< T > const &q) noexcept
Extracts the unit rotation axis from a unit quaternion.
Cylinder in Dim-dimensional space.
T radius
The radius of the cylinder.
Vec< Dim, T > end
The end point of the second cap of the cylinder.
Line segment in Dim-dimensional space.
Vec< Dim, T > start
The start point of the line segment.
Vec< Dim, T > end
The end point of the line segment.