MayaFlux 0.4.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]] 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 = Portal::Forma::create_buffer(window,
220// Plot::plot_grid(bounds, 8, 6),
221// Portal::Graphics::PrimitiveTopology::LINE_LIST);
222// surface.layer().add(
223// Portal::Forma::Element{}.non_interactive().with_buffer(grid_buf))
224// .relate_to(data_el.element.id).to_back();
225// =============================================================================
226
227/**
228 * @brief LINE_LIST grid geometry for a plot area.
229 *
230 * Produces @p x_divisions vertical lines and @p y_divisions horizontal lines
231 * evenly distributed within @p bounds. Intended as a static background buffer.
232 *
233 * @param bounds Plot area in NDC.
234 * @param x_divisions Vertical line count (columns). 0 = no vertical lines.
235 * @param y_divisions Horizontal line count (rows). 0 = no horizontal lines.
236 * @param color Line color.
237 * @param thickness LineVertex::thickness value.
238 */
239[[nodiscard]] MAYAFLUX_API std::vector<Kakshya::LineVertex> plot_grid(
240 Kinesis::AABB2D bounds,
241 uint32_t x_divisions,
242 uint32_t y_divisions,
243 glm::vec3 color = glm::vec3(0.12F),
244 float thickness = 1.F);
245
246// =============================================================================
247// Cursor / playhead
248//
249// GeometryFn<float>. Value in [0, 1] maps to a normalised position within
250// bounds along the active axis. vertical=true draws a vertical line (X axis
251// position); vertical=false draws a horizontal line (Y axis position).
252//
253// Produces two LINE_LIST LineVertex pairs. Topology: LINE_LIST.
254//
255// Caller pattern:
256// auto cursor = Portal::Forma::create_element<float>(
257// surface,
258// Plot::plot_cursor(bounds),
259// 0.F,
260// Portal::Graphics::PrimitiveTopology::LINE_LIST);
261// // drive from a metro or bridge binding
262// cursor.state->write(playhead_position);
263// =============================================================================
264
265/**
266 * @brief GeometryFn<float> for a cursor or playhead line within a plot area.
267 *
268 * Value in [0, 1] maps to a position within @p bounds. When @p vertical is
269 * true the line is vertical and the value maps to the X axis; when false the
270 * line is horizontal and the value maps to the Y axis.
271 *
272 * @note Pass @c PrimitiveTopology::LINE_LIST explicitly to create_element.
273 *
274 * @param bounds Plot area in NDC. The line spans the full perpendicular extent.
275 * @param vertical True for a vertical playhead (X position), false for horizontal.
276 * @param color Line color.
277 * @param thickness LineVertex::thickness value.
278 */
279[[nodiscard]] MAYAFLUX_API GeometryFn<float> plot_cursor(
280 Kinesis::AABB2D bounds,
281 bool vertical = true,
282 glm::vec3 color = glm::vec3(0.75F),
283 float thickness = 1.F);
284
285// =============================================================================
286// Label / tick / legend spec helpers
287// =============================================================================
288
289/**
290 * @brief Create a single construction-free label spec.
291 */
292[[nodiscard]] MAYAFLUX_API LabelSpec plot_label(
293 std::string text,
294 Kinesis::AABB2D bounds,
295 glm::vec4 color = { 0.85F, 0.85F, 0.85F, 1.F },
296 std::string name = {});
297
298/**
299 * @brief Generate construction-free tick label specs.
300 *
301 * Values are evenly interpolated across spec.range. Label bounds are placed
302 * adjacent to spec.plot_bounds according to spec.edge.
303 */
304[[nodiscard]] MAYAFLUX_API std::vector<LabelSpec> plot_tick_labels(
305 const TickLabelsSpec& spec);
306
307/**
308 * @brief Convenience overload for generating tick label specs directly.
309 */
310[[nodiscard]] MAYAFLUX_API std::vector<LabelSpec> plot_tick_labels(
311 Kinesis::AABB2D bounds,
312 const AxisRange& range,
313 uint32_t count,
315 glm::vec4 color = { 0.65F, 0.65F, 0.65F, 1.F },
316 uint8_t decimal_places = 2,
317 float label_h = 0.055F,
318 float label_w = 0.12F);
319
320/**
321 * @brief Create a construction-free legend spec from labels and colors.
322 */
323[[nodiscard]] MAYAFLUX_API LegendSpec plot_legend(
324 glm::vec2 origin,
325 std::span<const std::string> labels,
326 std::span<const glm::vec3> colors,
327 float row_h = 0.07F,
328 float swatch_w = 0.04F,
329 glm::vec4 text_color = { 0.85F, 0.85F, 0.85F, 1.F });
330
331/**
332 * @brief Expand a legend spec into swatch rectangle specs and text label specs.
333 */
334[[nodiscard]] MAYAFLUX_API LegendLayout layout_legend(
335 const LegendSpec& spec);
336
337} // namespace MayaFlux::Portal::Forma::Plot
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
std::pair< float, float > data_range(std::span< const double > series)
Compute [min, max] over a scalar series.
Definition PlotSpec.cpp:35
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:109
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
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:64
Role
Semantic role of the dimension.
Definition NDData.hpp:150
Axis-aligned bounding rectangle in a 2D coordinate space.
Definition Bounds.hpp:21
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