MayaFlux 0.2.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
PointCloudNetwork.cpp
Go to the documentation of this file.
2
4
5#include <glm/gtc/constants.hpp>
6
8
10 : m_init_mode(Kinesis::SpatialDistribution::EMPTY)
11{
14
16 "Created empty PointCloudNetwork");
17}
18
20 size_t num_points,
21 const glm::vec3& bounds_min,
22 const glm::vec3& bounds_max,
24 : m_num_points(num_points)
25 , m_bounds(bounds_min, bounds_max)
26 , m_init_mode(init_mode)
27{
30
32 "Created PointCloudNetwork with {} points, bounds [{:.2f}, {:.2f}, {:.2f}] to [{:.2f}, {:.2f}, {:.2f}]",
33 num_points,
34 bounds_min.x, bounds_min.y, bounds_min.z,
35 bounds_max.x, bounds_max.y, bounds_max.z);
36}
37
39{
40 if (m_initialized) {
41 return;
42 }
43
46
47 if (!m_operator) {
48 auto topology = std::make_unique<TopologyOperator>();
49 topology->initialize(m_cached_vertices);
50 m_operator = std::move(topology);
51 }
52 }
53
54 m_initialized = true;
55
57 "Initialized PointCloudNetwork: {} points, operator={}",
58 m_cached_vertices.size(),
59 m_operator ? m_operator->get_type_name() : "none");
60}
61
63 size_t count,
64 const glm::vec3& bounds_min,
65 const glm::vec3& bounds_max,
67{
68 m_bounds = { .min = bounds_min, .max = bounds_max };
70 m_init_mode = mode;
71
72 reset();
73
74 if (!m_operator) {
75 auto topology = std::make_unique<TopologyOperator>();
76 topology->initialize(m_cached_vertices);
77 m_operator = std::move(topology);
78 }
79}
80
81void PointCloudNetwork::set_operator(std::unique_ptr<NetworkOperator> op)
82{
83 if (!op) {
85 "Cannot set null operator");
86 return;
87 }
88
89 std::vector<LineVertex> vertices;
90
91 if (auto* old_path = dynamic_cast<PathOperator*>(m_operator.get())) {
92 vertices = old_path->extract_vertices();
93 } else if (auto* old_topo = dynamic_cast<TopologyOperator*>(m_operator.get())) {
94 vertices = old_topo->extract_vertices();
95 } else if (!m_operator) {
96 vertices = !m_cached_vertices.empty()
99 }
100
101 if (auto* new_path = dynamic_cast<PathOperator*>(op.get())) {
102 new_path->initialize(vertices);
103 } else if (auto* new_topo = dynamic_cast<TopologyOperator*>(op.get())) {
104 new_topo->initialize(vertices);
105 } else {
107 "PointCloudNetwork only supports LineVertex operators (PathOperator, TopologyOperator)");
108 return;
109 }
110
111 m_operator = std::move(op);
112}
113
115{
118
119 if (m_operator) {
120 if (auto* topo_op = dynamic_cast<TopologyOperator*>(m_operator.get())) {
121 topo_op->initialize(m_cached_vertices);
122 } else if (auto* path_op = dynamic_cast<PathOperator*>(m_operator.get())) {
123 path_op->initialize(m_cached_vertices);
124 }
125 }
126 }
127
129 "Reset PointCloudNetwork: {} points reinitialized", m_cached_vertices.size());
130}
131
132void PointCloudNetwork::process_batch(unsigned int num_samples)
133{
134 if (!is_enabled() || !m_operator) {
135 return;
136 }
137
139
140 for (unsigned int frame = 0; frame < num_samples; ++frame) {
141 m_operator->process(0.0F);
142 }
143
145 "PointCloudNetwork processed {} frames with {} operator",
146 num_samples, m_operator->get_type_name());
147}
148
153
155{
156 if (!m_operator) {
157 return m_cached_vertices.size();
158 }
159
160 if (auto* graphics_op = dynamic_cast<const GraphicsOperator*>(m_operator.get())) {
161 return graphics_op->get_point_count();
162 }
163
164 return m_cached_vertices.size();
165}
166
167std::optional<double> PointCloudNetwork::get_node_output(size_t index) const
168{
169 if (index >= get_node_count()) {
170 return std::nullopt;
171 }
172
173 return static_cast<double>(index);
174}
175
176std::unordered_map<std::string, std::string> PointCloudNetwork::get_metadata() const
177{
178 auto metadata = NodeNetwork::get_metadata();
179
180 metadata["point_count"] = std::to_string(get_node_count());
181 metadata["operator"] = std::string(m_operator ? m_operator->get_type_name() : "none");
182 metadata["bounds_min"] = std::format("({:.2f}, {:.2f}, {:.2f})",
184 metadata["bounds_max"] = std::format("({:.2f}, {:.2f}, {:.2f})",
186
187 if (auto* topology_op = dynamic_cast<const TopologyOperator*>(m_operator.get())) {
188 if (auto connections = topology_op->query_state("connection_count")) {
189 metadata["connection_count"] = std::to_string(static_cast<size_t>(*connections));
190 }
191 if (auto topology_count = topology_op->query_state("topology_count")) {
192 metadata["topology_count"] = std::to_string(static_cast<size_t>(*topology_count));
193 }
194 }
195
196 if (auto* path_op = dynamic_cast<const PathOperator*>(m_operator.get())) {
197 if (auto vertex_count = path_op->query_state("vertex_count")) {
198 metadata["vertex_count"] = std::to_string(static_cast<size_t>(*vertex_count));
199 }
200 if (auto path_count = path_op->query_state("path_count")) {
201 metadata["path_count"] = std::to_string(static_cast<size_t>(*path_count));
202 }
203 }
204
205 return metadata;
206}
207
208void PointCloudNetwork::set_vertices(const std::vector<LineVertex>& vertices)
209{
210 m_cached_vertices = vertices;
211 m_num_points = vertices.size();
212
213 if (m_operator) {
214 if (auto* graphics_op = dynamic_cast<TopologyOperator*>(m_operator.get())) {
215 graphics_op->initialize(m_cached_vertices);
216 } else if (auto* graphics_op = dynamic_cast<PathOperator*>(m_operator.get())) {
217 graphics_op->initialize(m_cached_vertices);
218 }
219 } else {
221 "No operator to set vertices on; vertices cached but not applied");
222 }
223
225 "Updated PointCloudNetwork vertices: {} points", vertices.size());
226}
227
228void PointCloudNetwork::apply_color_gradient(const glm::vec3& start_color, const glm::vec3& end_color)
229{
230 const size_t count = m_cached_vertices.size();
231
232 for (size_t i = 0; i < count; ++i) {
233 const float t = count > 1 ? static_cast<float>(i) / static_cast<float>(count - 1) : 0.0F;
234 m_cached_vertices[i].color = glm::mix(start_color, end_color, t);
235 }
236
238
240 "Applied linear color gradient to {} points", count);
241}
242
244 const glm::vec3& center_color,
245 const glm::vec3& edge_color,
246 const glm::vec3& center)
247{
248 const size_t count = m_cached_vertices.size();
249
250 float max_distance = 0.0F;
251 for (const auto& v : m_cached_vertices) {
252 const float dist = glm::length(v.position - center);
253 max_distance = std::max(max_distance, dist);
254 }
255
256 for (size_t i = 0; i < count; ++i) {
257 const float dist = glm::length(m_cached_vertices[i].position - center);
258 const float t = max_distance > 0.0F ? dist / max_distance : 0.0F;
259 m_cached_vertices[i].color = glm::mix(center_color, edge_color, t);
260 }
261
263
265 "Applied radial color gradient to {} points", count);
266}
267
268std::vector<LineVertex> PointCloudNetwork::get_vertices() const
269{
270 if (m_operator) {
271 if (auto* topo_op = dynamic_cast<const TopologyOperator*>(m_operator.get())) {
272 return topo_op->extract_vertices();
273 }
274
275 if (auto* path_op = dynamic_cast<const PathOperator*>(m_operator.get())) {
276 return path_op->extract_vertices();
277 }
278 }
279
280 return m_cached_vertices;
281}
282
283void PointCloudNetwork::update_vertex(size_t index, const LineVertex& vertex)
284{
285 if (index >= m_cached_vertices.size()) {
287 "Vertex index {} out of range (count: {})", index, m_cached_vertices.size());
288 return;
289 }
290
291 m_cached_vertices[index] = vertex;
292
293 if (m_operator) {
294 if (auto* topo_op = dynamic_cast<TopologyOperator*>(m_operator.get())) {
295 topo_op->initialize(m_cached_vertices);
296 } else if (auto* path_op = dynamic_cast<PathOperator*>(m_operator.get())) {
297 path_op->initialize(m_cached_vertices);
298 }
299 }
300}
301
303{
304 if (auto* topology_op = dynamic_cast<TopologyOperator*>(m_operator.get())) {
305 topology_op->set_connection_radius(radius);
306 } else {
308 "set_connection_radius requires TopologyOperator");
309 }
310}
311
313{
314 if (auto* topology_op = dynamic_cast<TopologyOperator*>(m_operator.get())) {
315 topology_op->set_parameter("k_neighbors", static_cast<double>(k));
316 } else {
318 "set_k_neighbors requires TopologyOperator");
319 }
320}
321
323{
324 if (auto* topology_op = dynamic_cast<TopologyOperator*>(m_operator.get())) {
325 topology_op->set_global_line_thickness(thickness);
326 } else if (auto* path_op = dynamic_cast<PathOperator*>(m_operator.get())) {
327 path_op->set_global_thickness(thickness);
328 }
329}
330
331void PointCloudNetwork::set_line_color(const glm::vec3& color)
332{
333 if (auto* topology_op = dynamic_cast<TopologyOperator*>(m_operator.get())) {
334 topology_op->set_global_line_color(color);
335 } else if (auto* path_op = dynamic_cast<PathOperator*>(m_operator.get())) {
336 path_op->set_global_color(color);
337 }
338}
339
341{
342 if (auto* path_op = dynamic_cast<PathOperator*>(m_operator.get())) {
343 path_op->set_samples_per_segment(static_cast<Eigen::Index>(samples));
344 } else {
346 "set_samples_per_segment requires PathOperator");
347 }
348}
349
351{
352 if (auto* path_op = dynamic_cast<PathOperator*>(m_operator.get())) {
353 path_op->set_tension(tension);
354 } else {
356 "set_tension requires PathOperator");
357 }
358}
359
361{
362 if (!m_operator) {
363 return;
364 }
365
366 for (const auto& mapping : m_parameter_mappings) {
367 if (mapping.mode == MappingMode::BROADCAST && mapping.broadcast_source) {
368 double value = mapping.broadcast_source->get_last_output();
369 m_operator->set_parameter(mapping.param_name, value);
370
371 } else if (mapping.mode == MappingMode::ONE_TO_ONE && mapping.network_source) {
372 m_operator->apply_one_to_one(mapping.param_name, mapping.network_source);
373 }
374 }
375}
376
378{
380 return Kinesis::to_line_vertices(samples, { 1.0F, 2.0F });
381}
382
383} // namespace MayaFlux::Nodes::Network
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_RT_TRACE(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
Eigen::Index count
Operator that produces GPU-renderable geometry.
std::vector< ParameterMapping > m_parameter_mappings
virtual void set_topology(Topology topology)
Set the network's topology.
bool is_enabled() const
Check if network is enabled.
virtual std::unordered_map< std::string, std::string > get_metadata() const
Get network metadata for debugging/visualization.
void set_output_mode(OutputMode mode)
Set the network's output routing mode.
size_t get_node_count() const override
Get the number of nodes in the network.
void apply_radial_gradient(const glm::vec3 &center_color, const glm::vec3 &edge_color, const glm::vec3 &center=glm::vec3(0.0F))
Apply radial color gradient from center.
void update_mapped_parameters()
Update mapped parameters before path/topology processing.
void set_topology(Topology topology) override
Set the network's topology.
std::unique_ptr< NetworkOperator > m_operator
void set_operator(std::unique_ptr< NetworkOperator > op)
void apply_color_gradient(const glm::vec3 &start_color, const glm::vec3 &end_color)
Set colors for all points.
void process_batch(unsigned int num_samples) override
Process the network for the given number of samples.
PointCloudNetwork()
Create empty point cloud network.
void set_line_thickness(float thickness)
Set line thickness for topology/path rendering.
void set_connection_radius(float radius)
Set connection radius for topology generation (TopologyOperator only)
std::vector< LineVertex > generate_initial_positions()
void set_vertices(const std::vector< LineVertex > &vertices)
Set all point vertices.
std::vector< LineVertex > get_vertices() const
Get all point vertices.
void set_k_neighbors(size_t k)
Set K value for K-nearest neighbors (TopologyOperator only)
std::unordered_map< std::string, std::string > get_metadata() const override
Get network metadata for debugging/visualization.
Kinesis::Stochastic::Stochastic m_random_gen
void reinitialize(size_t count, const glm::vec3 &bounds_min, const glm::vec3 &bounds_max, Kinesis::SpatialDistribution mode)
Reinitialize point cloud with new parameters.
void set_samples_per_segment(size_t samples)
Set samples per segment for path interpolation (PathOperator only)
void reset() override
Reset network to initial state.
std::optional< double > get_node_output(size_t index) const override
Get output of specific internal node (for ONE_TO_ONE mapping)
void set_line_color(const glm::vec3 &color)
Set global line color for topology/path rendering.
void update_vertex(size_t index, const LineVertex &vertex)
Update single vertex completely.
void initialize() override
Called once before first process_batch()
void set_tension(double tension)
Set tension for Catmull-Rom interpolation (PathOperator only)
@ NodeProcessing
Node graph processing (Nodes::NodeGraphManager)
@ Nodes
DSP Generator and Filter Nodes, graph pipeline, node management.
std::vector< Nodes::LineVertex > to_line_vertices(std::span< const SampleResult > samples, glm::vec2 thickness_range)
Batch-project SampleResult vector to LineVertex.
SpatialDistribution
Spatial distribution mode for point cloud and particle generation.
std::vector< SampleResult > generate_samples(SpatialDistribution dist, size_t count, const SamplerBounds &bounds, Stochastic::Stochastic &rng)
Generate a batch of spatially distributed samples.
Topology
Defines the structural relationships between nodes in the network.
@ INDEPENDENT
No connections, nodes process independently.
@ ONE_TO_ONE
Node array/network → network nodes (must match count)
@ BROADCAST
One node → all network nodes.
@ GRAPHICS_BIND
State available for visualization (read-only)