Blackchirp Plot Curve Classes

This page documents the five curve classes that form the plot-curve hierarchy used by ZoomPanPlot and its subclasses. All five are defined in src/gui/plot/blackchirpplotcurve.h.

  • BlackchirpPlotCurveBase — abstract root of the hierarchy.

  • BlackchirpPlotCurve — concrete, general-purpose point-cloud curve.

  • BCEvenSpacedCurveBase — abstract base for uniformly-spaced data.

  • BlackchirpFTCurve — concrete curve for Fourier-transform spectra.

  • BlackchirpFIDCurve — concrete curve for free-induction decay waveforms.

Curve objects are created exclusively through CurveFactory, which injects the appropriate storage backend. The appearance fields of every curve (color, line style, thickness, marker, visibility, autoscale, y-axis) are bundled into CurveAppearanceWidget::CurveAppearance and surfaced for editing via CurveAppearanceWidget embedded in the ZoomPanPlot context menu.

Curve hierarchy

QwtPlotCurve
└── BlackchirpPlotCurveBase       (abstract)
    ├── BlackchirpPlotCurve       (concrete — arbitrary x spacing)
    └── BCEvenSpacedCurveBase     (abstract — uniform x spacing)
        ├── BlackchirpFTCurve     (concrete — Ft spectrum)
        └── BlackchirpFIDCurve    (concrete — FID waveform)

Storage backend abstraction

BlackchirpPlotCurveBase does not inherit from SettingsStorage directly. Instead, it owns a std::unique_ptr<CurveStorageInterface> that is injected at construction by CurveFactory. Two concrete backends are provided in curvefactory.h:

  • SettingsStorageWrapper — wraps SettingsStorage (QSettings-backed) so that appearance settings persist across sessions under the curve’s key. Used for standard curves that live on persistent plots (FT view, tracking plots, etc.).

  • OverlayMetadataStorage — stores appearance settings as metadata inside an OverlayBase object. Used for overlay curves; settings travel with the overlay rather than being written to the global settings file.

The StorageType enum (Settings or OverlayMetadata) is detected automatically at construction by dynamic-casting the injected storage pointer. Callers that need to retrieve the associated overlay can call getOverlay(), which returns a std::shared_ptr<OverlayBase> or nullptr for Settings-backend curves.

This indirection keeps the curve classes free of knowledge about where their settings live; only CurveFactory and the overlay system need to reason about which backend to use.

Settings keys

The following keys are stored in the curve’s active CurveStorageInterface backend.

Key

Type

Description

BC::Key::bcCurveColor

QColor

Pen and symbol color.

BC::Key::bcCurveCurveStyle

int (QwtPlotCurve::CurveStyle)

Drawing mode (Lines, Dots, Sticks, etc.).

BC::Key::bcCurveLineStyle

int (Qt::PenStyle)

Pen dash pattern.

BC::Key::bcCurveThickness

double

Pen width in pixels (default 1.0).

BC::Key::bcCurveMarker

int (QwtSymbol::Style)

Point-marker shape.

BC::Key::bcCurveMarkerSize

int

Marker diameter in pixels (default 5).

BC::Key::bcCurveAxisX

int (QwtPlot::Axis)

X axis assignment (default xBottom).

BC::Key::bcCurveAxisY

int (QwtPlot::Axis)

Y axis assignment (default yLeft).

BC::Key::bcCurveVisible

bool

Curve visibility (default true).

BC::Key::bcCurveAutoscale

bool

Whether the curve participates in autoscale (default true).

BC::Key::bcCurvePlotIndex

int

Index of the ZoomPanPlot panel that owns this curve (default -1).

Setter family and visibility persistence

BlackchirpPlotCurveBase provides two overlapping ways to control visibility. The setCurve* family (setCurveVisible, setCurveAutoscale, setCurveAxisX, setCurveAxisY, setCurvePlotIndex) writes to the CurveStorageInterface backend so the curve’s state is restored across sessions, whereas the inherited QwtPlotItem::setVisible() and the lower-level appearance setters (setColor, etc.) are for transient changes that do not need to survive a restart. See the setCurveVisible note in the rendered API below for details.

Attaching and detaching curves

QwtPlotItem::attach and QwtPlotItem::detach are made private inside BlackchirpPlotCurveBase via using-declarations. Calling curve->attach(plot) or curve->detach() from anywhere outside ZoomPanPlot (the only friend) is a hard compile error.

The supported entry points are ZoomPanPlot::attachCurve and ZoomPanPlot::detachCurve, which drain the asynchronous filter worker before mutating the plot’s curve registry. See the Curve registry and thread safety section of ZoomPanPlot for the full rationale.

Curves held in std::unique_ptr do not need an explicit detachCurve before destruction. ~BlackchirpPlotCurveBase calls ZoomPanPlot::_unregisterCurve (a private helper friended to this class) which drains the worker and removes the pointer from the registry before ~QwtPlotItem performs its own detach. This makes container clearing patterns such as d_overlayCurves.clear() and unique_ptr::reset() safe with respect to the worker.

Downsampling filter

BlackchirpPlotCurveBase::filter() is called from a QtConcurrent worker dispatched by ZoomPanPlot whenever the x range changes. The worker iterates an immutable snapshot of the plot’s curve registry that was built under the plot’s mutex; it never touches the live registry, the QwtPlot item list, or any widget state. filter() delegates to the protected pure-virtual _filter(int w, const QwtScaleMap map) and stores the result in the Qwt sample buffer under a mutex so that the paint thread always reads a consistent snapshot.

Each implementation compresses the visible portion of the data to at most \(2w\) points using min/max compression per pixel column: for each pixel column, if more than one data point maps to that column, both the minimum and maximum y values are emitted so that vertical features (peaks, noise spikes) are preserved at all zoom levels.

BlackchirpPlotCurve::_filter iterates over the QVector<QPointF> data. BCEvenSpacedCurveBase::_filter (sealed final) computes pixel boundaries analytically from xFirst(), spacing(), and the scale map, avoiding a linear search.

curveData() and boundingRect() are the two pure-virtual methods that every concrete class must implement:

  • curveData() returns the full (non-downsampled) data as QVector<QPointF>; used for CSV export and context-menu Export XY.

  • boundingRect() returns the data extent in plot coordinates; used by ZoomPanPlot::replot() for autoscale. Return an invalid rect (width < 0 or height < 0) when no data is available.

BCEvenSpacedCurveBase extension hooks

Subclasses of BCEvenSpacedCurveBase implement four protected methods to describe their data:

  • xFirst() — x coordinate of the first data point.

  • spacing() — uniform x increment between consecutive points.

  • numPoints() — total number of data points.

  • yData() — y values as QVector<double>; called once per filter pass and should return a detached copy so the filter loop can read without holding a lock.

The _filter implementation in BCEvenSpacedCurveBase is declared final to prevent accidental re-overriding in leaf classes.

API Reference

class BlackchirpPlotCurveBase : public QwtPlotCurve

Abstract base class for all Blackchirp plot curves.

BlackchirpPlotCurveBase extends QwtPlotCurve with a storage-backend abstraction (CurveStorageInterface) that persists appearance settings to either QSettings (via SettingsStorageWrapper) or overlay metadata (via OverlayMetadataStorage). The concrete storage object is injected at construction by CurveFactory, keeping the curve classes independent of the persistence mechanism.

Subclasses must implement curveData(), boundingRect(), and the protected _filter() template method. The base class calls _filter() asynchronously (from ZoomPanPlot’s filter pass) and marshals the result into the Qwt sample buffer under a mutex.

Subclassed by BCEvenSpacedCurveBase, BlackchirpPlotCurve

Public Types

enum class StorageType

Selects which storage backend the curve uses.

Values:

enumerator Settings

Appearance settings are stored in QSettings via SettingsStorageWrapper.

enumerator OverlayMetadata

Appearance settings are stored as metadata in an OverlayBase object.

Public Functions

BlackchirpPlotCurveBase(std::unique_ptr<CurveStorageInterface> storage, const QString key, const QString title = QString(""), Qt::PenStyle defaultLineStyle = Qt::SolidLine, QwtSymbol::Style defaultMarker = QwtSymbol::NoSymbol, QwtPlotCurve::CurveStyle defaultStyle = QwtPlotCurve::Lines)

Constructs the curve with an injected storage backend.

If title is empty, the curve’s Qwt title is set to key. Default appearance values are written to storage only when no existing value is found for that key.

Parameters:
  • storage – Heap-allocated storage backend; ownership is transferred.

  • key – Unique identifier for this curve within its storage namespace.

  • title – Display title (shown in legends and menus).

  • defaultLineStyle – Initial Qt::PenStyle if not already in storage.

  • defaultMarker – Initial QwtSymbol::Style if not already in storage.

  • defaultStyle – Initial QwtPlotCurve::CurveStyle if not already in storage.

virtual ~BlackchirpPlotCurveBase()
void setColor(const QColor c)

Sets the curve color and updates both the pen and the symbol brush.

Parameters:

c – New color; persisted to storage.

void setCurveStyle(CurveStyle s)

Sets the Qwt drawing style (Lines, Dots, Sticks, etc.) and persists it.

Parameters:

s – New QwtPlotCurve::CurveStyle value.

void setLineThickness(double t)

Sets the pen line width and persists it.

Parameters:

t – Line width in pixels.

void setLineStyle(Qt::PenStyle s)

Sets the pen dash pattern and persists it.

Parameters:

s – Qt::PenStyle value.

void setMarkerStyle(QwtSymbol::Style s)

Sets the point-marker symbol shape and persists it.

Parameters:

s – QwtSymbol::Style value.

void setMarkerSize(int s)

Sets the point-marker diameter and persists it.

Parameters:

s – Diameter in pixels.

void setName(const QString &t)

Sets the curve’s display title (shown in legends and context menus).

Parameters:

t – New title string.

inline QString name() const

Returns the curve’s display title.

inline QString key() const

Returns the storage key passed at construction.

inline StorageType getStorageType() const

Returns which storage backend this curve uses.

std::shared_ptr<OverlayBase> getOverlay() const

Returns the associated OverlayBase when the storage type is OverlayMetadata, or nullptr.

virtual QVector<QPointF> curveData() const = 0

Returns the full curve data as a point vector.

The returned vector reflects the canonical data set before any downsampling; it is used for CSV export and bounding-rect calculations.

void setCurveVisible(bool v)

Sets curve visibility and persists the state to storage.

Note

Use QwtPlotItem::setVisible() directly if persistence is not desired (for example when temporarily hiding a curve in a view-only context). This method is intended for user-driven visibility changes on tracking and logging plots where the setting should survive a session restart.

Parameters:

vtrue to show the curve.

void setCurveAutoscale(bool enabled)

Enables or disables autoscale participation and persists the choice.

A curve with autoscale disabled contributes to the legend but its bounding rect is excluded from ZoomPanPlot’s axis range calculations.

Parameters:

enabledtrue to include in autoscale.

void setCurveAxisX(QwtPlot::Axis a)

Sets the x axis and persists the assignment.

Parameters:

a – QwtPlot::Axis value (xBottom or xTop).

void setCurveAxisY(QwtPlot::Axis a)

Sets the y axis and persists the assignment.

Parameters:

a – QwtPlot::Axis value (yLeft or yRight).

void setCurvePlotIndex(int i)

Sets the owning plot-panel index and persists it.

The plot index identifies which ZoomPanPlot panel this curve belongs to when a view holds multiple panels (e.g. the rolling-data view).

Parameters:

i – Zero-based panel index; -1 means unassigned.

int plotIndex() const

Returns the stored plot-panel index, or -1 if not set.

void updateFromSettings()

Re-applies all appearance settings from storage to the Qwt curve.

Call after a storage backend is refreshed externally (e.g. when an overlay’s metadata is reloaded from disk).

void filter(int w, const QwtScaleMap map)

Computes a downsampled sample set and stores it in the Qwt sample buffer.

Called by ZoomPanPlot’s concurrent filter pass. The canvas width w and scale map map are used to limit the rendered sample count to approximately 2×w points via min/max compression per pixel column.

Parameters:
  • w – Canvas width in pixels.

  • map – Current x-axis scale map.

virtual QRectF boundingRect() const override = 0

Returns the data bounding rect in plot coordinates.

Must reflect the full (non-downsampled) data range so that ZoomPanPlot can compute correct autoscale limits. Return an invalid rect (width < 0 or height < 0) when no data is available.

void draw(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) const override

Protected Functions

virtual QVector<QPointF> _filter(int w, const QwtScaleMap map) = 0

Produces a downsampled point vector for the current view.

Called by filter(). Implementations should return at most 2×w points, using min/max compression to preserve peak fidelity when multiple data points map to the same pixel column.

Parameters:
  • w – Canvas width in pixels.

  • map – Current x-axis scale map used to determine pixel boundaries.

Returns:

Downsampled point vector to pass to the Qwt sample buffer.

template<typename It>
inline void increment(It i)

Private Functions

void configurePen()
void configureSymbol()
void configureCurveStyle()
void setSamples(const QVector<QPointF> d)

Private Members

std::unique_ptr<CurveStorageInterface> d_storage
const QString d_key
QMutex *p_samplesMutex
StorageType d_storageType
OverlayMetadataStorage *p_overlayMetadataStorage

Friends

friend class ZoomPanPlot
class BlackchirpPlotCurve : public BlackchirpPlotCurveBase

Concrete BlackchirpPlotCurveBase for arbitrary (x, y) point-cloud data.

BlackchirpPlotCurve stores its data as a QVector<QPointF> and supports both bulk replacement (setCurveData()) and incremental appending (appendPoint()). It is the general-purpose curve type used for tracking plots, aux-data traces, and any other non-uniform x-spacing data.

Public Functions

BlackchirpPlotCurve(std::unique_ptr<CurveStorageInterface> storage, const QString key, const QString title = QString(""), Qt::PenStyle defaultLineStyle = Qt::SolidLine, QwtSymbol::Style defaultMarker = QwtSymbol::NoSymbol, QwtPlotCurve::CurveStyle defaultStyle = QwtPlotCurve::Lines)

Constructs the curve with an injected storage backend.

~BlackchirpPlotCurve()
void setCurveData(const QVector<QPointF> d)

Replaces the stored data and recomputes the bounding rect.

Parameters:

d – New point vector; the bounding rect height is computed from all y values.

void setCurveData(const QVector<QPointF> d, double min, double max)

Replaces the stored data with a pre-computed bounding rect height.

Use this overload when the caller already knows the y-range to avoid a second pass over the data.

Parameters:
  • d – New point vector.

  • min – Minimum y value (bounding rect top).

  • max – Maximum y value (bounding rect bottom).

void appendPoint(const QPointF p)

Appends a single point and extends the bounding rect.

Parameters:

p – Point to append.

virtual QRectF boundingRect() const override

Returns the data bounding rect in plot coordinates.

Must reflect the full (non-downsampled) data range so that ZoomPanPlot can compute correct autoscale limits. Return an invalid rect (width < 0 or height < 0) when no data is available.

virtual QVector<QPointF> curveData() const override

Returns the full curve data as a point vector.

The returned vector reflects the canonical data set before any downsampling; it is used for CSV export and bounding-rect calculations.

Protected Functions

virtual QVector<QPointF> _filter(int w, const QwtScaleMap map) override

Produces a downsampled point vector for the current view.

Called by filter(). Implementations should return at most 2×w points, using min/max compression to preserve peak fidelity when multiple data points map to the same pixel column.

Parameters:
  • w – Canvas width in pixels.

  • map – Current x-axis scale map used to determine pixel boundaries.

Returns:

Downsampled point vector to pass to the Qwt sample buffer.

Private Functions

void calcBoundingRectHeight()

Private Members

QRectF d_boundingRect
QVector<QPointF> d_curveData
QMutex *p_dataMutex
class BCEvenSpacedCurveBase : public BlackchirpPlotCurveBase

Abstract base for evenly spaced curves (constant x increment).

BCEvenSpacedCurveBase provides a closed-form _filter() implementation that avoids iterating over all data points to find pixel boundaries — it computes array indices directly from xFirst(), spacing(), and the scale map. Subclasses supply the three geometric hooks and the y-data vector; the filter logic is sealed (final) and cannot be further overridden.

Subclassed by BlackchirpEvenSpacedCurve, BlackchirpFIDCurve, BlackchirpFTCurve

Public Functions

BCEvenSpacedCurveBase(std::unique_ptr<CurveStorageInterface> storage, const QString key, const QString title = QString(""), Qt::PenStyle defaultLineStyle = Qt::SolidLine, QwtSymbol::Style defaultMarker = QwtSymbol::NoSymbol, QwtPlotCurve::CurveStyle defaultStyle = QwtPlotCurve::Lines)

Constructs the curve with an injected storage backend.

virtual ~BCEvenSpacedCurveBase()
double xVal(int i) const

Returns the x coordinate of data point i.

Parameters:

i – Zero-based data index.

int indexBefore(double xVal) const

Returns the index of the last data point with x < xVal.

Parameters:

xVal – X coordinate to search for.

Protected Functions

virtual double xFirst() const = 0

Returns the x coordinate of the first data point.

virtual double spacing() const = 0

Returns the uniform x spacing between consecutive data points.

virtual int numPoints() const = 0

Returns the total number of data points.

virtual QVector<double> yData() = 0

Returns the y-data vector; called once per filter pass.

Implementations should return a detached (copy-on-write) vector so the filter loop can read without holding a lock.

virtual QVector<QPointF> _filter(int w, const QwtScaleMap map) final override

Sealed min/max-compression filter exploiting uniform x spacing.

class BlackchirpFTCurve : public BCEvenSpacedCurveBase

Curve for displaying a Fourier transform (Ft) spectrum.

BlackchirpFTCurve wraps an Ft object and exposes its frequency axis (minFreqMHz / xSpacing) and y-data through the BCEvenSpacedCurveBase hooks. The Ft is set atomically under a mutex so the filter thread always reads a consistent snapshot.

Public Functions

BlackchirpFTCurve(std::unique_ptr<CurveStorageInterface> storage, const QString key, const QString title = QString(""), Qt::PenStyle defaultLineStyle = Qt::SolidLine, QwtSymbol::Style defaultMarker = QwtSymbol::NoSymbol, QwtPlotCurve::CurveStyle defaultStyle = QwtPlotCurve::Lines)

Constructs the curve with an injected storage backend.

~BlackchirpFTCurve()
void setCurrentFt(const Ft f)

Replaces the displayed Ft spectrum.

Thread-safe: the Ft is stored under the internal mutex and the next filter pass picks up the new data.

Parameters:

f – New Ft object to display.

virtual QRectF boundingRect() const override

Returns the data bounding rect in plot coordinates.

Must reflect the full (non-downsampled) data range so that ZoomPanPlot can compute correct autoscale limits. Return an invalid rect (width < 0 or height < 0) when no data is available.

virtual QVector<QPointF> curveData() const override

Returns the full curve data as a point vector.

The returned vector reflects the canonical data set before any downsampling; it is used for CSV export and bounding-rect calculations.

Private Functions

virtual double xFirst() const override

Returns the x coordinate of the first data point.

virtual double spacing() const override

Returns the uniform x spacing between consecutive data points.

virtual int numPoints() const override

Returns the total number of data points.

virtual QVector<double> yData() override

Returns the y-data vector; called once per filter pass.

Implementations should return a detached (copy-on-write) vector so the filter loop can read without holding a lock.

Private Members

QMutex *p_mutex
Ft d_currentFt
class BlackchirpFIDCurve : public BCEvenSpacedCurveBase

Curve for displaying a free-induction decay (FID) waveform.

BlackchirpFIDCurve stores raw FID samples as a QVector<double> with a uniform time spacing. The x axis starts at 0 and extends to spacing * numPoints. Y bounds are supplied explicitly when setCurrentFid() is called to avoid a full-vector scan.

Public Functions

BlackchirpFIDCurve(std::unique_ptr<CurveStorageInterface> storage, const QString key, const QString title = QString(""), Qt::PenStyle defaultLineStyle = Qt::SolidLine, QwtSymbol::Style defaultMarker = QwtSymbol::NoSymbol, QwtPlotCurve::CurveStyle defaultStyle = QwtPlotCurve::Lines)

Constructs the curve with an injected storage backend.

~BlackchirpFIDCurve()
void setCurrentFid(const QVector<double> d, double spacing = 1.0, double min = 0.0, double max = 0.0)

Replaces the displayed FID waveform.

Thread-safe: all fields are updated under the internal mutex.

Parameters:
  • d – Y-value samples.

  • spacing – Uniform time step between samples (in the plot’s x-axis unit).

  • min – Minimum y value; used directly as the bounding rect top.

  • max – Maximum y value; used directly as the bounding rect bottom.

virtual QRectF boundingRect() const override

Returns the data bounding rect in plot coordinates.

Must reflect the full (non-downsampled) data range so that ZoomPanPlot can compute correct autoscale limits. Return an invalid rect (width < 0 or height < 0) when no data is available.

virtual QVector<QPointF> curveData() const override

Returns the full curve data as a point vector.

The returned vector reflects the canonical data set before any downsampling; it is used for CSV export and bounding-rect calculations.

Protected Functions

virtual double xFirst() const override

Returns the x coordinate of the first data point.

virtual double spacing() const override

Returns the uniform x spacing between consecutive data points.

virtual int numPoints() const override

Returns the total number of data points.

virtual QVector<double> yData() override

Returns the y-data vector; called once per filter pass.

Implementations should return a detached (copy-on-write) vector so the filter loop can read without holding a lock.

Private Members

QMutex *p_mutex
QVector<double> d_fidData
double d_spacing = {1.0}
double d_min = {0.0}
double d_max = {1.0}