Initial commit

This commit is contained in:
Martino Ferrari committed 2026-10-01 15:42:48 +02:00
commit 8059b90de7
29 files changed
+7893

No files matched your search

+59
View File
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2026 Martino Ferrari
#pragma once
#include "model.hpp"
#include "plot_host.hpp"
#include <string>
#include <vector>
namespace udpscope {
/// What the plots are showing, as a table: one row per sample of the visible x window,
/// one column per plotted signal.
///
/// The samples are the *stored* ones, never the LOD pyramid's buckets: the pyramid is
/// what makes a million samples drawable in a few hundred pixels, and exporting it would
/// hand back the envelope the renderer drew rather than the acquisition. So an export is
/// at the full rate the ring holds, however far the view is zoomed out.
struct ExportTable {
struct Column {
std::string name; ///< the legend name, sanitised for a column label
std::vector<f32> values; ///< `rows()` long, the ring's own `f32`
};
/// The x the plot shows and the crosshair reads: stream seconds in live mode,
/// edge-relative seconds in `[-pre, +post]` while an event is held.
std::vector<f64> time;
/// The stream's own clock, so two exports taken in different modes line up. Equal to
/// `time` in live mode; `time + trigger_time` while an event is held, which is the one
/// case where the visible x is not the stream's.
std::vector<f64> stream_time;
std::vector<Column> columns;
std::size_t rows() const noexcept { return time.size(); }
bool empty() const noexcept { return columns.empty() || time.empty(); }
};
/// Collects every signal bound to a visible row, over the shared x window, at the stored
/// rate. A signal on several rows is one column; the columns come out in channel order,
/// which is the signal list's order.
///
/// Takes `model.mutex()` for the live cut, so call it from the GTK thread like any other
/// model access. In trigger mode nothing is locked: the `EventSnapshot` is immutable.
ExportTable collect_export(ScopeModel& model, RowSet& rows);
/// Writes a NumPy `.npy` file holding one structured array: `time` and `stream_time` as
/// `<f8`, every signal as `<f4` -- the width the ring actually stores, so the file is
/// about half the size of an all-`f8` one and invents no precision.
///
/// `pd.DataFrame(np.load(path))` is the whole reader.
bool write_npy(const std::string& path, const ExportTable& table, std::string& error);
/// Writes the same table as CSV: a header row of column names, then `%.*g` fields --
/// enough digits to round-trip each column's own type and no more.
bool write_csv(const std::string& path, const ExportTable& table, std::string& error);
} // namespace udpscope