MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
TopologyGeneratorNode.cpp
Go to the documentation of this file.
2
4
6
7namespace {
8 bool path_interpolation_viable(Kinesis::InterpolationMode mode, size_t num_points)
9 {
10 switch (mode) {
12 return num_points >= 2;
14 return num_points >= 3;
16 return num_points >= 4;
19 return num_points >= 5;
21 return num_points == 4;
22 default:
23 return false;
24 }
25 }
26}
27
30 bool auto_connect,
31 size_t max_points)
32 : GeometryWriterNode(static_cast<uint32_t>(max_points * max_points))
33 , m_mode(mode)
34 , m_max_points(max_points)
35 , m_auto_connect(auto_connect)
36{
38
39 const auto& stride = sizeof(LineVertex);
40 set_vertex_stride(stride);
41
42 auto layout = Kakshya::VertexLayout::for_lines(stride);
43 layout.vertex_count = 0;
44 set_vertex_layout(layout);
45
46 m_points.reserve(max_points);
47 m_vertices.reserve(max_points * max_points);
48 m_connections.reserve(max_points * max_points);
49
51 "Created TopologyGeneratorNode with mode {}, auto_connect={}, capacity={}",
52 static_cast<int>(mode), auto_connect, max_points);
53}
54
56 CustomConnectionFunction custom_func,
57 bool auto_connect,
58 size_t max_points)
59 : GeometryWriterNode(static_cast<uint32_t>(max_points * max_points))
60 , m_mode(Kinesis::ProximityMode::CUSTOM)
61 , m_custom_func(std::move(custom_func))
62 , m_max_points(max_points)
63 , m_auto_connect(auto_connect)
64{
66
67 const auto& stride = sizeof(LineVertex);
68 set_vertex_stride(stride);
69
70 auto layout = Kakshya::VertexLayout::for_lines(stride);
71 layout.vertex_count = 0;
72 set_vertex_layout(layout);
73
74 m_points.reserve(max_points);
75 m_vertices.reserve(max_points * max_points);
76 m_connections.reserve(max_points * max_points);
77
79 "Created TopologyGeneratorNode with custom function");
80}
81
83{
84 m_positions.resize(3, static_cast<Eigen::Index>(m_points.size()));
85
86 Eigen::Index idx = 0;
87 for (const auto& point : m_points) {
88 m_positions(0, idx) = point.position.x;
89 m_positions(1, idx) = point.position.y;
90 m_positions(2, idx) = point.position.z;
91 ++idx;
92 }
93}
94
96{
97 m_points.insert(m_points.begin(), point);
98 if (m_points.size() > m_max_points) {
99 m_points.pop_back();
100 }
101
102 if (m_auto_connect) {
104 }
105
106 m_geometry_dirty = true;
107 m_vertex_data_dirty = true;
108}
109
110void TopologyGeneratorNode::add_points(std::span<const LineVertex> points)
111{
112 if (points.empty()) {
113 return;
114 }
115
116 for (const auto& pt : points) {
117 m_points.insert(m_points.begin(), pt);
118 if (m_points.size() > m_max_points) {
119 m_points.pop_back();
120 }
121 }
122
123 if (m_auto_connect) {
125 }
126
127 m_geometry_dirty = true;
128 m_vertex_data_dirty = true;
129}
130
132 std::span<const LineVertex> points,
133 size_t num_points)
134{
135 if (num_points < 2 || m_vertices.empty()) {
136 return;
137 }
138
139 const size_t num_segments = num_points - 1;
140 const size_t count = m_vertices.size() / 2 + 1;
141 const auto span = static_cast<float>(count - 1);
142
143 for (size_t i = 0; i + 1 < count; ++i) {
144 const float t0 = static_cast<float>(i) / span;
145 const float t1 = static_cast<float>(i + 1) / span;
146
147 const auto s0 = std::min<size_t>(
148 static_cast<size_t>(t0 * static_cast<float>(num_segments)), num_segments - 1);
149 const auto s1 = std::min<size_t>(
150 static_cast<size_t>(t1 * static_cast<float>(num_segments)), num_segments - 1);
151
152 LineVertex& v0 = m_vertices[i * 2];
153 LineVertex& v1 = m_vertices[i * 2 + 1];
154
157
160 }
161}
162
164{
165 if (m_vertices.empty()) {
166 return;
167 }
168
169 const size_t num_points = m_points.size();
170
172 && path_interpolation_viable(m_path_interpolation_mode, num_points)) {
173 write_path_attributes(m_points, num_points);
174 return;
175 }
176
178}
179
181{
182 if (index >= m_points.size()) {
184 "Point index {} out of range", index);
185 return;
186 }
187
188 m_points.erase(m_points.begin() + static_cast<std::ptrdiff_t>(index));
189
190 if (m_auto_connect) {
192 }
193
194 m_geometry_dirty = true;
195 m_vertex_data_dirty = true;
196}
197
199{
200 if (index >= m_points.size()) {
202 "Point index {} out of range", index);
203 return;
204 }
205
206 m_points[index] = point;
207
208 if (m_auto_connect) {
210 }
211
212 m_geometry_dirty = true;
213 m_vertex_data_dirty = true;
214}
215
216void TopologyGeneratorNode::set_points(const std::vector<LineVertex>& points)
217{
218 m_points.assign(points.rbegin(), points.rend());
219 if (m_points.size() > m_max_points) {
221 "TopologyGeneratorNode: {} points exceed the capacity of {}, keeping the newest {}",
223 m_points.erase(
224 m_points.begin() + static_cast<std::ptrdiff_t>(m_max_points),
225 m_points.end());
226 }
227
228 if (m_auto_connect) {
230 }
231
232 m_geometry_dirty = true;
233 m_vertex_data_dirty = true;
234}
235
237{
238 m_points.clear();
239 m_connections.clear();
240 m_vertices.clear();
241 m_geometry_dirty = true;
242 m_vertex_data_dirty = true;
245}
246
248{
249 m_connections.clear();
250
251 if (m_points.empty()) {
252 m_geometry_dirty = true;
253 m_vertex_data_dirty = true;
254 return;
255 }
256
258
260 config.mode = m_mode;
261 config.k_neighbors = m_k_neighbors;
264
266
267 m_geometry_dirty = true;
268 m_vertex_data_dirty = true;
269}
270
276
278{
279 m_auto_connect = enable;
280}
281
289
297
298void TopologyGeneratorNode::set_line_color(const glm::vec3& color, bool force_uniform)
299{
301 m_force_uniform_color = force_uniform;
302 m_attributes_dirty = true;
303 m_vertex_data_dirty = true;
304}
305
307{
308 m_force_uniform_color = should_force;
309 m_attributes_dirty = true;
310 m_vertex_data_dirty = true;
311}
312
313void TopologyGeneratorNode::set_line_thickness(float thickness, bool force_uniform)
314{
315 m_line_thickness = thickness;
316 m_force_uniform_thickness = force_uniform;
317 m_attributes_dirty = true;
318 m_vertex_data_dirty = true;
319}
320
322{
323 m_force_uniform_thickness = should_force;
324 m_attributes_dirty = true;
325 m_vertex_data_dirty = true;
326}
327
329{
330 if (index >= m_points.size()) {
332 "Point index {} out of range", index);
333 static LineVertex default_point {};
334 return default_point;
335 }
336
337 return m_points[index];
338}
339
340std::vector<LineVertex> TopologyGeneratorNode::get_points() const
341{
342 return m_points;
343}
344
351
353{
354 if (samples >= 2) {
355 m_samples_per_segment = samples;
356 m_geometry_dirty = true;
357 m_vertex_data_dirty = true;
358 }
359}
360
367
369{
370 m_vertices.clear();
371
372 const size_t num_points = m_points.size();
373
375 && path_interpolation_viable(m_path_interpolation_mode, num_points)) {
377 } else {
379 }
380}
381
383{
384 if (m_geometry_dirty) {
386 m_geometry_dirty = false;
387 m_attributes_dirty = false;
388 } else if (m_attributes_dirty) {
390 m_attributes_dirty = false;
391 } else {
392 return;
393 }
394
395 if (m_vertices.empty()) {
397 } else {
398 set_vertices<LineVertex>(std::span { m_vertices.data(), m_vertices.size() });
399 }
400
401 if (auto layout = get_vertex_layout()) {
402 layout->vertex_count = static_cast<uint32_t>(m_vertices.size());
403 set_vertex_layout(*layout);
404 }
405}
406
408 std::span<LineVertex> points,
409 size_t num_points)
410{
412
413 m_control_scratch.resize(num_points * 3);
414 for (size_t i = 0; i < num_points; ++i) {
415 m_control_scratch[i * 3 + 0] = points[i].position.x;
416 m_control_scratch[i * 3 + 1] = points[i].position.y;
417 m_control_scratch[i * 3 + 2] = points[i].position.z;
418 }
419
420 const size_t num_segments = num_points - 1;
421 const auto total_samples = static_cast<Eigen::Index>(
422 1 + num_segments * (m_samples_per_segment - 1));
423
426
427 const std::vector<double>* curve = &m_curve_primary;
428
431 total_samples, total_samples, m_curve_secondary);
432 curve = &m_curve_secondary;
433 }
434
435 const auto count = static_cast<size_t>(total_samples);
436 if (count < 2) {
437 return;
438 }
439
440 m_vertices.resize((count - 1) * 2);
441
442 const double* x = curve->data();
443 const double* y = x + count;
444 const double* z = y + count;
445
448 }
449
450 const double* tx = m_curve_tangents.data();
451 const double* ty = tx + count;
452 const double* tz = ty + count;
453
454 const auto sample = [&](size_t s) {
455 return glm::vec3 {
456 static_cast<float>(x[s]), static_cast<float>(y[s]), static_cast<float>(z[s])
457 };
458 };
459
460 const auto tangent = [&](size_t s) {
461 return glm::vec3 {
462 static_cast<float>(tx[s]), static_cast<float>(ty[s]), static_cast<float>(tz[s])
463 };
464 };
465
466 for (size_t i = 0; i + 1 < count; ++i) {
467 m_vertices[i * 2].position = sample(i);
468 m_vertices[i * 2].tangent = tangent(i);
469 m_vertices[i * 2 + 1].position = sample(i + 1);
470 m_vertices[i * 2 + 1].tangent = tangent(i + 1);
471 }
472
473 write_path_attributes(points, num_points);
474}
475
477 std::span<LineVertex> points,
478 size_t num_points)
479{
480 size_t valid_connections = std::ranges::count_if(m_connections,
481 [num_points](const auto& conn) {
482 return conn.first < num_points && conn.second < num_points;
483 });
484
485 m_vertices.clear();
486 m_vertices.reserve(valid_connections * 2);
487
488 for (const auto& [a, b] : m_connections) {
489 if (a >= num_points || b >= num_points) {
490 continue;
491 }
492
493 glm::vec3 color_a = m_force_uniform_color ? m_line_color : points[a].color;
494 glm::vec3 color_b = m_force_uniform_color ? m_line_color : points[b].color;
495
496 float thick_a = m_force_uniform_thickness ? m_line_thickness : points[a].thickness;
497 float thick_b = m_force_uniform_thickness ? m_line_thickness : points[b].thickness;
498
499 const glm::vec3 edge = points[b].position - points[a].position;
500
501 m_vertices.emplace_back(LineVertex {
502 .position = points[a].position,
503 .color = color_a,
504 .thickness = thick_a,
505 .tangent = edge });
506
507 m_vertices.emplace_back(LineVertex {
508 .position = points[b].position,
509 .color = color_b,
510 .thickness = thick_b,
511 .tangent = edge });
512 }
513}
514
515} // namespace MayaFlux::Nodes::GpuSync
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
glm::vec3 color
Definition Decoder.cpp:97
std::vector< glm::vec2 > * points
float radius
uint32_t mode
uint32_t tangent
size_t a
size_t b
uint32_t index
Definition VKDevice.cpp:122
size_t count
void evaluate_planar(std::span< const double > control_points, size_t dim, Eigen::Index num_samples, std::vector< double > &out, std::vector< double > &tangents)
Evaluate a curve into coordinate-major position and tangent buffers.
void reparameterize_planar(std::span< const double > points, size_t dim, Eigen::Index point_count, Eigen::Index num_samples, std::vector< double > &out)
Resample a polyline to uniform arc length, coordinate-major.
void configure(InterpolationMode mode, double tension)
Re-resolve the kernel.
bool m_vertex_data_dirty
Flag: vertex data or layout changed since last GPU upload.
Portal::Graphics::PrimitiveTopology m_primitive_topology
std::optional< Kakshya::VertexLayout > get_vertex_layout() const
Get cached vertex layout.
void set_vertex_layout(const Kakshya::VertexLayout &layout)
Set cached vertex layout.
void resize_vertex_buffer(uint32_t vertex_count, bool preserve_data=false)
Resize vertex buffer to hold specified number of vertices.
void set_vertex_stride(size_t stride)
Set vertex stride (bytes per vertex)
bool m_needs_layout_update
Flag indicating if layout needs update.
Base class for nodes that generate 3D geometry data.
void set_line_color(const glm::vec3 &color, bool force_uniform=true)
Set line color (applied to all connections)
void force_uniform_color(bool should_force)
Force uniform color for all vertices.
void add_points(std::span< const LineVertex > points)
Append several points, regenerating connections once.
std::function< std::vector< std::pair< size_t, size_t > >(const Eigen::MatrixXd &)> CustomConnectionFunction
void add_point(const LineVertex &point)
Add point to topology.
void set_path_interpolation_mode(Kinesis::InterpolationMode mode)
Set custom connection function (for CUSTOM mode)
void refresh_attributes()
Rewrite colour and thickness over existing positions.
void set_line_thickness(float thickness, bool force_uniform=true)
Set line thickness.
void regenerate_topology()
Manually trigger connection regeneration.
void build_direct_connections(std::span< LineVertex > points, size_t num_points)
std::vector< std::pair< size_t, size_t > > m_connections
void set_samples_per_segment(size_t samples)
Set number of samples per segment for interpolation.
void build_interpolated_path(std::span< LineVertex > points, size_t num_points)
void remove_point(size_t index)
Remove point by index.
void set_arc_length_reparameterization(bool enable)
Enable or disable arc-length reparameterization for interpolation.
void set_k_neighbors(size_t k)
Set K parameter for K_NEAREST mode.
void force_uniform_thickness(bool should_force)
Force uniform thickness for all vertices.
bool m_force_uniform_color
If true, all vertices use m_line_color instead of per-vertex color.
void refresh_positions()
Refill m_positions from m_points, in place.
void set_points(const std::vector< LineVertex > &points)
Set all points at once.
std::vector< LineVertex > m_points
Points, newest first: index 0 is the most recently added.
void compute_frame() override
Compute frame - generates vertex data from points and connections.
TopologyGeneratorNode(Kinesis::ProximityMode mode=Kinesis::ProximityMode::SEQUENTIAL, bool auto_connect=true, size_t max_points=256)
Create topology generator.
void set_connection_mode(Kinesis::ProximityMode mode)
Set connection mode.
void write_path_attributes(std::span< const LineVertex > points, size_t num_points)
Write colour and thickness for the interpolated path.
size_t m_samples_per_segment
Controls smoothness vs performance.
bool m_force_uniform_thickness
If true, all vertices use m_line_thickness instead of per-vertex thickness.
const LineVertex & get_point(size_t index) const
Get point by index.
void update_point(size_t index, const LineVertex &point)
Update point data.
void set_auto_connect(bool enable)
Enable/disable automatic connection regeneration.
void set_connection_radius(float radius)
Set radius for RADIUS_THRESHOLD mode.
std::vector< LineVertex > get_points() const
Get all points.
void clear()
Clear all points and connections.
@ NodeProcessing
Node graph processing (Nodes::NodeGraphManager)
@ Nodes
DSP Generator and Filter Nodes, graph pipeline, node management.
InterpolationMode
Mathematical interpolation methods.
void central_difference_tangents(std::span< const double > points, size_t dim, size_t count, std::vector< double > &tangents)
Tangents of a sampled curve by finite difference, coordinate-major.
EdgeList generate_proximity_graph(const Eigen::MatrixXd &points, const ProximityConfig &config)
Generate proximity graph using specified mode.
Kakshya::LineVertex LineVertex
Definition VertexSpec.hpp:9
Vertex type for line primitives (LINE_LIST / LINE_STRIP topology)
static VertexLayout for_lines(uint32_t stride=60)
Factory: layout for LineVertex (position, color, thickness, uv, normal, tangent)
std::function< EdgeList(const Eigen::MatrixXd &)> custom_function