MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
PointCloudNetwork.cpp
Go to the documentation of this file.
2
4
6
8
10 : m_init_mode(Kinesis::SpatialDistribution::EMPTY)
11{
14 m_operator_chain = std::make_shared<OperatorChain>();
15
17 "Created empty PointCloudNetwork");
18}
19
21 size_t num_points,
22 const glm::vec3& bounds_min,
23 const glm::vec3& bounds_max,
25 : m_num_points(num_points)
26 , m_bounds(bounds_min, bounds_max)
27 , m_init_mode(init_mode)
28{
31 m_operator_chain = std::make_shared<OperatorChain>();
32
34 "Created PointCloudNetwork with {} points, bounds [{:.2f}, {:.2f}, {:.2f}] to [{:.2f}, {:.2f}, {:.2f}]",
35 num_points,
36 bounds_min.x, bounds_min.y, bounds_min.z,
37 bounds_max.x, bounds_max.y, bounds_max.z);
38}
39
41{
42 if (m_initialized) {
43 return;
44 }
45
48
49 if (!m_operator) {
50 auto topology = std::make_unique<TopologyOperator>();
51 topology->initialize(m_cached_vertices);
52 m_operator = std::move(topology);
53 }
54 }
55
56 m_initialized = true;
57
59 "Initialized PointCloudNetwork: {} points, operator={}",
60 m_cached_vertices.size(),
61 m_operator ? m_operator->get_type_name() : "none");
62}
63
65 size_t count,
66 const glm::vec3& bounds_min,
67 const glm::vec3& bounds_max,
69{
70 m_bounds = { .min = bounds_min, .max = bounds_max };
72 m_init_mode = mode;
73
74 reset();
75
76 if (!m_operator) {
77 auto topology = std::make_unique<TopologyOperator>();
78 topology->initialize(m_cached_vertices);
79 m_operator = std::move(topology);
80 }
81}
82
83void PointCloudNetwork::set_operator(std::unique_ptr<NetworkOperator> op)
84{
85 if (!op) {
87 "Cannot set null operator");
88 return;
89 }
90
91 std::vector<LineVertex> vertices;
92
93 if (auto* old_path = dynamic_cast<PathOperator*>(m_operator.get())) {
94 vertices = old_path->extract_vertices();
95 } else if (auto* old_topo = dynamic_cast<TopologyOperator*>(m_operator.get())) {
96 vertices = old_topo->extract_vertices();
97 } else if (auto* old_field = dynamic_cast<FieldOperator*>(m_operator.get())) {
98 vertices = old_field->extract_line_vertices();
99 } else if (!m_operator) {
100 vertices = !m_cached_vertices.empty()
103 }
104
105 if (auto* new_path = dynamic_cast<PathOperator*>(op.get())) {
106 new_path->initialize(vertices);
107 } else if (auto* new_topo = dynamic_cast<TopologyOperator*>(op.get())) {
108 new_topo->initialize(vertices);
109 } else if (auto* new_field = dynamic_cast<FieldOperator*>(op.get())) {
110 new_field->initialize(vertices);
111 } else {
113 "PointCloudNetwork: unsupported operator type '{}'", op->get_type_name());
114 return;
115 }
116
117 m_operator = std::move(op);
118}
119
121{
124
125 if (m_operator) {
126 if (auto* topo_op = dynamic_cast<TopologyOperator*>(m_operator.get())) {
127 topo_op->initialize(m_cached_vertices);
128 } else if (auto* path_op = dynamic_cast<PathOperator*>(m_operator.get())) {
129 path_op->initialize(m_cached_vertices);
130 } else if (auto* field_op = dynamic_cast<FieldOperator*>(m_operator.get())) {
131 field_op->initialize(m_cached_vertices);
132 }
133 }
134 }
135
137 "Reset PointCloudNetwork: {} points reinitialized", m_cached_vertices.size());
138}
139
140void PointCloudNetwork::process_batch(unsigned int num_samples)
141{
142 if (!is_enabled() || !m_operator) {
143 return;
144 }
145
147
148 for (unsigned int frame = 0; frame < num_samples; ++frame) {
149 m_operator->process(0.0F);
150 }
151
152 if (m_operator_chain && !m_operator_chain->empty()) {
153 for (unsigned int frame = 0; frame < num_samples; ++frame) {
154 m_operator_chain->process(0.0F, m_operator.get());
155 }
156 }
157
159 "PointCloudNetwork processed {} frames with {} operator",
160 num_samples, m_operator->get_type_name());
161}
162
167
169{
170 if (auto* gfx = dynamic_cast<const GraphicsOperator*>(m_operator.get()))
171 return gfx->get_point_count();
172 return 0;
173}
174
175std::optional<double> PointCloudNetwork::get_node_output(size_t index) const
176{
177 if (index >= get_node_count()) {
178 return std::nullopt;
179 }
180
181 return static_cast<double>(index);
182}
183
184std::unordered_map<std::string, std::string> PointCloudNetwork::get_metadata() const
185{
186 auto metadata = NodeNetwork::get_metadata();
187
188 metadata["point_count"] = std::to_string(get_node_count());
189 metadata["operator"] = std::string(m_operator ? m_operator->get_type_name() : "none");
190 metadata["bounds_min"] = std::format("({:.2f}, {:.2f}, {:.2f})",
192 metadata["bounds_max"] = std::format("({:.2f}, {:.2f}, {:.2f})",
194
195 if (auto* topology_op = dynamic_cast<const TopologyOperator*>(m_operator.get())) {
196 if (auto connections = topology_op->query_state("connection_count")) {
197 metadata["connection_count"] = std::to_string(static_cast<size_t>(*connections));
198 }
199 if (auto topology_count = topology_op->query_state("topology_count")) {
200 metadata["topology_count"] = std::to_string(static_cast<size_t>(*topology_count));
201 }
202 }
203
204 if (auto* path_op = dynamic_cast<const PathOperator*>(m_operator.get())) {
205 if (auto vertex_count = path_op->query_state("vertex_count")) {
206 metadata["vertex_count"] = std::to_string(static_cast<size_t>(*vertex_count));
207 }
208 if (auto path_count = path_op->query_state("path_count")) {
209 metadata["path_count"] = std::to_string(static_cast<size_t>(*path_count));
210 }
211 }
212
213 return metadata;
214}
215
216void PointCloudNetwork::set_vertices(const std::vector<LineVertex>& vertices)
217{
218 m_cached_vertices = vertices;
219 m_num_points = vertices.size();
220
221 if (auto* topo = dynamic_cast<TopologyOperator*>(m_operator.get())) {
222 topo->initialize(vertices);
223 } else if (auto* path = dynamic_cast<PathOperator*>(m_operator.get())) {
224 path->initialize(vertices);
225 } else if (auto* field = dynamic_cast<FieldOperator*>(m_operator.get())) {
226 field->initialize(vertices);
227 } else {
229 "set_vertices: no operator to apply to; seed cached only");
230 }
231
233 "PointCloudNetwork reseeded: {} points", vertices.size());
234}
235
236void PointCloudNetwork::apply_color_gradient(const glm::vec3& start_color, const glm::vec3& end_color)
237{
238 auto verts = get_vertices();
239 const size_t count = verts.size();
240 for (size_t i = 0; i < count; ++i) {
241 const float t = count > 1 ? static_cast<float>(i) / static_cast<float>(count - 1) : 0.0F;
242 verts[i].color = glm::mix(start_color, end_color, t);
243 }
244
245 set_vertices(verts);
246
248 "Applied linear color gradient to {} points", count);
249}
250
252 const glm::vec3& center_color,
253 const glm::vec3& edge_color,
254 const glm::vec3& center)
255{
256 auto verts = get_vertices();
257 const size_t count = verts.size();
258
259 float max_dist = 0.0F;
260 for (const auto& v : verts)
261 max_dist = std::max(max_dist, glm::length(v.position - center));
262
263 for (size_t i = 0; i < count; ++i) {
264 const float t = max_dist > 0.0F ? glm::length(verts[i].position - center) / max_dist : 0.0F;
265 verts[i].color = glm::mix(center_color, edge_color, t);
266 }
267
268 set_vertices(verts);
269
271 "Applied radial color gradient to {} points", count);
272}
273
274std::vector<LineVertex> PointCloudNetwork::get_vertices() const
275{
276 if (auto* topo = dynamic_cast<const TopologyOperator*>(m_operator.get()))
277 return topo->extract_vertices();
278
279 if (auto* path = dynamic_cast<const PathOperator*>(m_operator.get()))
280 return path->extract_vertices();
281
282 if (auto* field = dynamic_cast<const FieldOperator*>(m_operator.get()))
283 return field->extract_line_vertices();
284
285 return {};
286}
287
288void PointCloudNetwork::update_vertex([[maybe_unused]] size_t index, [[maybe_unused]] const LineVertex& vertex)
289{
291 "update_vertex is not supported; use get_vertices/set_vertices");
292}
293
295{
296 if (auto* topology_op = dynamic_cast<TopologyOperator*>(m_operator.get())) {
297 topology_op->set_connection_radius(radius);
298 } else {
300 "set_connection_radius requires TopologyOperator");
301 }
302}
303
305{
306 if (auto* topology_op = dynamic_cast<TopologyOperator*>(m_operator.get())) {
307 topology_op->set_parameter("k_neighbors", static_cast<double>(k));
308 } else {
310 "set_k_neighbors requires TopologyOperator");
311 }
312}
313
315{
316 if (auto* topology_op = dynamic_cast<TopologyOperator*>(m_operator.get())) {
317 topology_op->set_global_line_thickness(thickness);
318 } else if (auto* path_op = dynamic_cast<PathOperator*>(m_operator.get())) {
319 path_op->set_global_thickness(thickness);
320 }
321}
322
323void PointCloudNetwork::set_line_color(const glm::vec3& color)
324{
325 if (auto* topology_op = dynamic_cast<TopologyOperator*>(m_operator.get())) {
326 topology_op->set_global_line_color(color);
327 } else if (auto* path_op = dynamic_cast<PathOperator*>(m_operator.get())) {
328 path_op->set_global_color(color);
329 }
330}
331
333{
334 if (auto* path_op = dynamic_cast<PathOperator*>(m_operator.get())) {
335 path_op->set_samples_per_segment(static_cast<Eigen::Index>(samples));
336 } else if (auto* topo_op = dynamic_cast<TopologyOperator*>(m_operator.get())) {
337 topo_op->set_samples_per_segment(samples);
338 } else {
340 "set_samples_per_segment requires PathOperator or TopologyOperator");
341 }
342}
343
345{
346 if (auto* path_op = dynamic_cast<PathOperator*>(m_operator.get())) {
347 path_op->set_tension(tension);
348 } else {
350 "set_tension requires PathOperator");
351 }
352}
353
355{
356 if (!m_operator) {
357 return;
358 }
359
360 for (const auto& mapping : m_parameter_mappings) {
361 if (mapping.mode == MappingMode::BROADCAST && mapping.broadcast_source) {
362 double value = mapping.broadcast_source->get_last_output();
363 m_operator->set_parameter(mapping.param_name, value);
364
365 } else if (mapping.mode == MappingMode::ONE_TO_ONE && mapping.network_source) {
366 m_operator->apply_one_to_one(mapping.param_name, mapping.network_source);
367 }
368 }
369}
370
372{
374 return Kakshya::to_line_vertices(samples, { 1.0F, 2.0F });
375}
376
377} // 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,...)
size_t count
Pure field-driven vertex manipulation via Tendency evaluation.
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.
std::shared_ptr< OperatorChain > m_operator_chain
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< LineVertex > to_line_vertices(std::span< const Vertex > vertices, glm::vec2 thickness_range)
Batch-project raw Vertex vector to LineVertex.
std::vector< Vertex > generate_samples(SpatialDistribution dist, size_t count, const SamplerBounds &bounds, Stochastic::Stochastic &rng)
Generate a batch of spatially distributed samples.
SpatialDistribution
Spatial distribution mode for point cloud and particle generation.
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)
Vertex type for line primitives (LINE_LIST / LINE_STRIP topology)