MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
PlotSpec.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "AxisRange.hpp"
4
7
9class Surface;
10}
11
12namespace MayaFlux::Kakshya {
13class PlotContainer;
14}
15
17
18/**
19 * @brief Edge along which tick labels are placed.
20 */
21enum class TickEdge : uint8_t {
22 Bottom, ///< Labels below bounds, values mapped from range.min (left) to range.max (right).
23 Top, ///< Labels above bounds.
24 Left, ///< Labels left of bounds, values mapped from range.min (bottom) to range.max (top).
25 Right, ///< Labels right of bounds.
26};
27
28/**
29 * @brief Construction-free text label description.
30 *
31 * This is only a layout/style spec. It does not own a FormaBuffer, VKImage,
32 * Element, Surface, or Window. Forma is responsible for turning this into
33 * a textured Element via Element::with_text().
34 */
35struct LabelSpec {
36 std::string text;
38 glm::vec4 color { 0.85F, 0.85F, 0.85F, 1.F };
39
40 /**
41 * @brief Optional logical name for the eventual Element.
42 */
43 std::string name;
44
45 /**
46 * @brief Whether the eventual Element should participate in hit testing.
47 * Plot labels default to passive/non-interactive.
48 */
49 bool interactive { false };
50
51 /**
52 * @brief Optional text pixel/render size override.
53 *
54 * When zero, Forma should derive render_bounds from bounds + window size.
55 */
56 glm::uvec2 render_bounds {};
57};
58
59/**
60 * @brief Lightweight filled rectangle description.
61 *
62 * Used for plot adornments such as legend swatches. Construction-free:
63 * Forma turns this into a buffer/Element later.
64 */
65struct RectSpec {
67 glm::vec3 color { 1.F };
68 std::string name;
69 bool interactive { false };
70};
71
72/**
73 * @brief Config for generating numeric tick labels on one plot edge.
74 */
78 uint32_t count { 2 };
80 glm::vec4 color { 0.65F, 0.65F, 0.65F, 1.F };
81 uint8_t decimal_places { 2 };
82
83 /**
84 * @brief NDC height of each label strip for Bottom/Top ticks.
85 */
86 float label_h { 0.055F };
87
88 /**
89 * @brief NDC width of each label strip for Left/Right ticks.
90 */
91 float label_w { 0.12F };
92
93 std::string name_prefix { "tick" };
94};
95
96/**
97 * @brief One legend row.
98 */
100 std::string label;
101 glm::vec3 color { 1.F };
102};
103
104/**
105 * @brief Construction-free vertical legend configuration.
106 */
108 glm::vec2 origin { 0.F };
109 std::vector<LegendEntry> entries;
110
111 float row_h { 0.07F };
112 float swatch_w { 0.04F };
113 float gap { 0.012F };
114 float text_w { 0.35F };
115
116 glm::vec4 text_color { 0.85F, 0.85F, 0.85F, 1.F };
117
118 std::string name_prefix { "legend" };
119 bool interactive { false };
120};
121
122/**
123 * @brief Expanded construction-free legend layout.
124 *
125 * Forma should build one rectangle Element per swatch and one text Element
126 * per label, then relate all produced elements to the plot root/data id.
127 */
129 std::vector<RectSpec> swatches;
130 std::vector<LabelSpec> labels;
131};
132
133// =============================================================================
134// series_by_role
135// =============================================================================
136
137/**
138 * @brief Collect all series from processed_data whose DataDimension role
139 * matches @p role.
140 *
141 * Returns spans pointing directly into the DataVariant storage — no copy.
142 * Returns an empty vector if no series carry the role or if any matching
143 * variant does not hold vector<double>.
144 *
145 * @param container PlotContainer after process_default() has been called.
146 * @param role DataDimension::Role to match.
147 */
148[[nodiscard]] MAYAFLUX_API std::vector<std::span<const double>> series_by_role(
149 const Kakshya::PlotContainer& container,
151
152/**
153 * @brief Compute [min, max] over a scalar series.
154 *
155 * Returns {0, 1} for an empty span.
156 */
157[[nodiscard]] MAYAFLUX_API std::pair<float, float> data_range(std::span<const double> series);
158
159/**
160 * @brief Apply auto-scaling to an AxisRange from a set of series.
161 *
162 * Computes the union [min, max] over all provided series and updates
163 * @p range in place. No-op if series is empty or range.auto_scale is false.
164 */
165MAYAFLUX_API void apply_auto_scale(AxisRange& range,
166 const std::vector<std::span<const double>>& series);
167
168// =============================================================================
169// Palette
170// =============================================================================
171
172/**
173 * @brief Resolve a per-series color from a palette.
174 *
175 * Wraps @p palette cyclically: palette[index % palette.size()].
176 * Returns white if @p palette is empty.
177 *
178 * @param palette Per-series base colors. Size 1 = uniform color.
179 * @param index Series index.
180 */
181[[nodiscard]] MAYAFLUX_API glm::vec3 palette_color(const std::vector<glm::vec3>& palette,
182 size_t index) noexcept;
183
184// =============================================================================
185// Geometry function factories
186// =============================================================================
187
188/**
189 * @brief TRIANGLE_STRIP background quad for a plot area.
190 *
191 * Produces a solid-color or textured full-screen quad covering @p bounds.
192 * Intended to be added to the same Layer as a plot element via Layer::relate,
193 * rendered before it.
194 *
195 * When @p texture is non-null the quad uses the textured vertex path and
196 * the caller must pass a matching FormaBuffer with a texture binding. When
197 * null the quad is filled with @p color.
198 *
199 * T is float (a dummy tick value — the background is static unless the
200 * caller drives it). Write any float to state->write() to refresh.
201 *
202 * @param bounds Plot area in NDC.
203 * @param color Fill color when no texture is provided.
204 * @param texture Optional GPU image. nullptr = solid color.
205 */
206[[nodiscard]] MAYAFLUX_API GeometryFn<float> background(
207 Kinesis::AABB2D bounds,
208 glm::vec3 color = glm::vec3(1.F),
209 const std::shared_ptr<Core::VKImage>& texture = nullptr);
210
211// =============================================================================
212// Grid
213//
214// Static LINE_LIST geometry for NDC-space grid lines. Produces x_divisions
215// vertical lines and y_divisions horizontal lines within bounds. Use as a
216// static FormaBuffer submitted once and related behind the data element.
217//
218// Caller pattern:
219// auto grid_buf = FormaTarget::slice_of(
220// Portal::Forma::create_buffer(surface.render_config()),
221// Portal::Graphics::PrimitiveTopology::LINE_LIST);
222// grid_buf.submit(Plot::plot_grid(bounds, 8, 6));
223// surface.layer().add(
224// Portal::Forma::Element{}.non_interactive().with_buffer(grid_buf))
225// .relate_to(data_el.element.id).to_back();
226// =============================================================================
227
228/**
229 * @brief LINE_LIST grid geometry for a plot area.
230 *
231 * Produces @p x_divisions vertical lines and @p y_divisions horizontal lines
232 * evenly distributed within @p bounds. Intended as a static background buffer.
233 *
234 * @param bounds Plot area in NDC.
235 * @param x_divisions Vertical line count (columns). 0 = no vertical lines.
236 * @param y_divisions Horizontal line count (rows). 0 = no horizontal lines.
237 * @param color Line color.
238 * @param thickness LineVertex::thickness value.
239 */
240[[nodiscard]] MAYAFLUX_API std::vector<Kakshya::LineVertex> plot_grid(
241 Kinesis::AABB2D bounds,
242 uint32_t x_divisions,
243 uint32_t y_divisions,
244 glm::vec3 color = glm::vec3(0.12F),
245 float thickness = 1.F);
246
247// =============================================================================
248// Cursor / playhead
249//
250// GeometryFn<float>. Value in [0, 1] maps to a normalised position within
251// bounds along the active axis. vertical=true draws a vertical line (X axis
252// position); vertical=false draws a horizontal line (Y axis position).
253//
254// Produces two LINE_LIST LineVertex pairs. Topology: LINE_LIST.
255//
256// Caller pattern:
257// auto cursor = Portal::Forma::create_element<float>(
258// surface,
259// Plot::plot_cursor(bounds),
260// 0.F,
261// Portal::Graphics::PrimitiveTopology::LINE_LIST);
262// // drive from a metro or bridge binding
263// cursor.state->write(playhead_position);
264// =============================================================================
265
266/**
267 * @brief GeometryFn<float> for a cursor or playhead line within a plot area.
268 *
269 * Value in [0, 1] maps to a position within @p bounds. When @p vertical is
270 * true the line is vertical and the value maps to the X axis; when false the
271 * line is horizontal and the value maps to the Y axis.
272 *
273 * @note Pass @c PrimitiveTopology::LINE_LIST explicitly to create_element.
274 *
275 * @param bounds Plot area in NDC. The line spans the full perpendicular extent.
276 * @param vertical True for a vertical playhead (X position), false for horizontal.
277 * @param color Line color.
278 * @param thickness LineVertex::thickness value.
279 */
280[[nodiscard]] MAYAFLUX_API GeometryFn<float> plot_cursor(
281 Kinesis::AABB2D bounds,
282 bool vertical = true,
283 glm::vec3 color = glm::vec3(0.75F),
284 float thickness = 1.F);
285
286// =============================================================================
287// Label / tick / legend spec helpers
288// =============================================================================
289
290/**
291 * @brief Create a single construction-free label spec.
292 */
293[[nodiscard]] MAYAFLUX_API LabelSpec plot_label(
294 std::string text,
295 Kinesis::AABB2D bounds,
296 glm::vec4 color = { 0.85F, 0.85F, 0.85F, 1.F },
297 std::string name = {});
298
299/**
300 * @brief Generate construction-free tick label specs.
301 *
302 * Values are evenly interpolated across spec.range. Label bounds are placed
303 * adjacent to spec.plot_bounds according to spec.edge.
304 */
305[[nodiscard]] MAYAFLUX_API std::vector<LabelSpec> plot_tick_labels(
306 const TickLabelsSpec& spec);
307
308/**
309 * @brief Convenience overload for generating tick label specs directly.
310 */
311[[nodiscard]] MAYAFLUX_API std::vector<LabelSpec> plot_tick_labels(
312 Kinesis::AABB2D bounds,
313 const AxisRange& range,
314 uint32_t count,
316 glm::vec4 color = { 0.65F, 0.65F, 0.65F, 1.F },
317 uint8_t decimal_places = 2,
318 float label_h = 0.055F,
319 float label_w = 0.12F);
320
321/**
322 * @brief Create a construction-free legend spec from labels and colors.
323 */
324[[nodiscard]] MAYAFLUX_API LegendSpec plot_legend(
325 glm::vec2 origin,
326 std::span<const std::string> labels,
327 std::span<const glm::vec3> colors,
328 float row_h = 0.07F,
329 float swatch_w = 0.04F,
330 glm::vec4 text_color = { 0.85F, 0.85F, 0.85F, 1.F });
331
332/**
333 * @brief Expand a legend spec into swatch rectangle specs and text label specs.
334 */
335[[nodiscard]] MAYAFLUX_API LegendLayout layout_legend(
336 const LegendSpec& spec);
337
338} // namespace MayaFlux::Portal::Forma::Plot
glm::vec3 color
Definition Decoder.cpp:97
std::string name
Definition VKDevice.cpp:123
uint32_t index
Definition VKDevice.cpp:122
size_t count
SignalSourceContainer holding N named scalar series for plotting and signal use.
glm::vec3 palette_color(const std::vector< glm::vec3 > &palette, size_t index) noexcept
Resolve a per-series color from a palette.
Definition PlotSpec.cpp:76
TickEdge
Edge along which tick labels are placed.
Definition PlotSpec.hpp:21
@ Bottom
Labels below bounds, values mapped from range.min (left) to range.max (right).
@ Left
Labels left of bounds, values mapped from range.min (bottom) to range.max (top).
std::vector< Kakshya::LineVertex > plot_grid(Kinesis::AABB2D bounds, uint32_t x_divisions, uint32_t y_divisions, glm::vec3 color, float thickness)
LINE_LIST grid geometry for a plot area.
Definition PlotSpec.cpp:143
LegendLayout layout_legend(const LegendSpec &spec)
Expand a legend spec into swatch rectangle specs and text label specs.
Definition PlotSpec.cpp:346
Series series()
Begin a Series chain.
Definition Plot.hpp:108
void apply_auto_scale(AxisRange &range, const std::vector< std::span< const double > > &series)
Apply auto-scaling to an AxisRange from a set of series.
Definition PlotSpec.cpp:53
std::vector< LabelSpec > plot_tick_labels(const TickLabelsSpec &spec)
Generate construction-free tick label specs.
Definition PlotSpec.cpp:237
std::pair< float, float > data_range(std::span< const double > series)
Compute [min, max] over a scalar series.
Definition PlotSpec.cpp:35
LegendSpec plot_legend(glm::vec2 origin, std::span< const std::string > labels, std::span< const glm::vec3 > colors, float row_h, float swatch_w, glm::vec4 text_color)
Create a construction-free legend spec from labels and colors.
Definition PlotSpec.cpp:318
GeometryFn< float > plot_cursor(Kinesis::AABB2D bounds, bool vertical, glm::vec3 color, float thickness)
GeometryFn<float> for a cursor or playhead line within a plot area.
Definition PlotSpec.cpp:182
LabelSpec plot_label(std::string text, Kinesis::AABB2D bounds, glm::vec4 color, std::string name)
Create a single construction-free label spec.
Definition PlotSpec.cpp:222
std::vector< std::span< const double > > series_by_role(const Kakshya::PlotContainer &container, Kakshya::DataDimension::Role role)
Collect all series from processed_data whose DataDimension role matches role.
Definition PlotSpec.cpp:12
GeometryFn< float > background(Kinesis::AABB2D bounds, glm::vec3 color, const std::shared_ptr< Core::VKImage > &texture)
TRIANGLE_STRIP background quad for a plot area.
Definition PlotSpec.cpp:88
std::function< void(T value, std::vector< uint8_t > &out_bytes, Element &element)> GeometryFn
Geometry function signature.
Definition Mapped.hpp:71
Role
Semantic role of the dimension.
Definition NDData.hpp:204
Axis-aligned bounding rectangle in a 2D coordinate space.
Definition Bounds.hpp:63
Scalar domain extent for one plot axis.
Definition AxisRange.hpp:22
std::string name
Optional logical name for the eventual Element.
Definition PlotSpec.hpp:43
glm::uvec2 render_bounds
Optional text pixel/render size override.
Definition PlotSpec.hpp:56
bool interactive
Whether the eventual Element should participate in hit testing.
Definition PlotSpec.hpp:49
Construction-free text label description.
Definition PlotSpec.hpp:35
Expanded construction-free legend layout.
Definition PlotSpec.hpp:128
std::vector< LegendEntry > entries
Definition PlotSpec.hpp:109
Construction-free vertical legend configuration.
Definition PlotSpec.hpp:107
Lightweight filled rectangle description.
Definition PlotSpec.hpp:65
float label_h
NDC height of each label strip for Bottom/Top ticks.
Definition PlotSpec.hpp:86
float label_w
NDC width of each label strip for Left/Right ticks.
Definition PlotSpec.hpp:91
Config for generating numeric tick labels on one plot edge.
Definition PlotSpec.hpp:75