Files @ 71441196d1c5
Branch filter:

Location: tempo-plotter/src/plot.cpp - annotation

Hasan Yavuz ÖZDERYA
Merge with default
bdc33b5c53c6
81bc58c2b941
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
1258272f91d8
1258272f91d8
ceb94a4c22ec
f641cc1fcdd8
ceb94a4c22ec
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
f641cc1fcdd8
f641cc1fcdd8
1258272f91d8
262f56d3e063
bdc33b5c53c6
262f56d3e063
4f8a97f79619
bdc33b5c53c6
bdc33b5c53c6
f641cc1fcdd8
0e27c36ff949
c35baca48756
1c69ffd0aa9d
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
11e2033df414
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bd649e494eb1
1258272f91d8
1258272f91d8
1258272f91d8
1258272f91d8
1258272f91d8
1258272f91d8
1258272f91d8
1258272f91d8
1258272f91d8
f641cc1fcdd8
1258272f91d8
1258272f91d8
bd649e494eb1
bd649e494eb1
bd649e494eb1
bd649e494eb1
bd649e494eb1
2e2a2aff04ea
bd649e494eb1
bd649e494eb1
bd649e494eb1
e7ad6cbfd4a0
e7ad6cbfd4a0
e7ad6cbfd4a0
e7ad6cbfd4a0
e7ad6cbfd4a0
e7ad6cbfd4a0
e7ad6cbfd4a0
e7ad6cbfd4a0
e7ad6cbfd4a0
e7ad6cbfd4a0
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
262f56d3e063
262f56d3e063
262f56d3e063
262f56d3e063
262f56d3e063
2b698ce67e65
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
2b698ce67e65
2b698ce67e65
2b698ce67e65
2b698ce67e65
2b698ce67e65
5974901a8564
2b698ce67e65
2b698ce67e65
2b698ce67e65
39b23673b4d1
347335d8956f
2b698ce67e65
2b698ce67e65
39b23673b4d1
39b23673b4d1
39b23673b4d1
39b23673b4d1
2b698ce67e65
2b698ce67e65
2b698ce67e65
2b698ce67e65
bdc33b5c53c6
bdc33b5c53c6
2b698ce67e65
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
6a233b0c073b
6a233b0c073b
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
eb7eec03607b
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
baaf95cd2089
baaf95cd2089
baaf95cd2089
baaf95cd2089
baaf95cd2089
baaf95cd2089
bd649e494eb1
bd649e494eb1
bd649e494eb1
bd649e494eb1
bd649e494eb1
bd649e494eb1
e7ad6cbfd4a0
e7ad6cbfd4a0
e7ad6cbfd4a0
e7ad6cbfd4a0
e7ad6cbfd4a0
e7ad6cbfd4a0
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
53be69238bdb
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
53be69238bdb
bdc33b5c53c6
60b1d4871c81
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
2f04c80c72e3
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
2f04c80c72e3
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
bdc33b5c53c6
1258272f91d8
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
1c69ffd0aa9d
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
1c69ffd0aa9d
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
1258272f91d8
1258272f91d8
1c69ffd0aa9d
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
73e46f8f1ad6
1258272f91d8
1258272f91d8
1258272f91d8
0e27c36ff949
0e27c36ff949
c35baca48756
c35baca48756
0e27c36ff949
1258272f91d8
f641cc1fcdd8
1258272f91d8
f641cc1fcdd8
1258272f91d8
1258272f91d8
1258272f91d8
f641cc1fcdd8
1258272f91d8
1258272f91d8
1258272f91d8
1258272f91d8
1258272f91d8
1258272f91d8
1258272f91d8
1258272f91d8
1258272f91d8
6049d6835508
1258272f91d8
1258272f91d8
1258272f91d8
f641cc1fcdd8
1258272f91d8
1258272f91d8
60b1d4871c81
1258272f91d8
f641cc1fcdd8
1258272f91d8
1258272f91d8
1258272f91d8
1258272f91d8
1258272f91d8
5d5d3a41557c
5d5d3a41557c
5d5d3a41557c
5d5d3a41557c
5d5d3a41557c
5d5d3a41557c
f641cc1fcdd8
73e46f8f1ad6
f641cc1fcdd8
0e27c36ff949
0e27c36ff949
f641cc1fcdd8
f102fddaeb9f
f102fddaeb9f
f102fddaeb9f
c35baca48756
f102fddaeb9f
f102fddaeb9f
/*
  Copyright © 2018 Hasan Yavuz Özderya

  This file is part of serialplot.

  serialplot is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  serialplot is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <QRectF>
#include <QKeySequence>
#include <QColor>
#include <qwt_symbol.h>
#include <qwt_plot_curve.h>
#include <math.h>
#include <algorithm>

#include "plot.h"
#include "utils.h"

static const int SYMBOL_SHOW_AT_WIDTH = 5;
static const int SYMBOL_SIZE_MAX = 7;

Plot::Plot(QWidget* parent) :
    QwtPlot(parent),
    zoomer(this->canvas(), false),
    sZoomer(this, &zoomer)
{
    isAutoScaled = true;
    symbolSize = 0;
    numOfSamples = 1;
    plotWidth = 1;
    showSymbols = Plot::ShowSymbolsAuto;

    QObject::connect(&zoomer, &Zoomer::unzoomed, this, &Plot::unzoomed);

    zoomer.setZoomBase();
    grid.attach(this);
    legend.attach(this);

    showGrid(false);
    darkBackground(false);

    snapshotOverlay = NULL;

    connect(&zoomer, &QwtPlotZoomer::zoomed,
            [this](const QRectF &rect)
            {
                onXScaleChanged();
            });

    connect(this, &QwtPlot::itemAttached,
            [this](QwtPlotItem *plotItem, bool on)
            {
                if (symbolSize) updateSymbols();
            });

    // init demo indicator
    QwtText demoText(" DEMO RUNNING ");  // looks better with spaces
    demoText.setColor(QColor("white"));
    demoText.setBackgroundBrush(Qt::darkRed);
    demoText.setBorderRadius(4);
    demoText.setRenderFlags(Qt::AlignLeft | Qt::AlignBottom);
    demoIndicator.setText(demoText);
    demoIndicator.hide();
    demoIndicator.attach(this);

    // init no channels are visible indicator
    QwtText noChannelText(" No Visible Channels ");
    noChannelText.setColor(QColor("white"));
    noChannelText.setBackgroundBrush(Qt::darkBlue);
    noChannelText.setBorderRadius(4);
    noChannelText.setRenderFlags(Qt::AlignHCenter | Qt::AlignVCenter);
    noChannelIndicator.setText(noChannelText);
    noChannelIndicator.hide();
    noChannelIndicator.attach(this);
}

Plot::~Plot()
{
    if (snapshotOverlay != NULL) delete snapshotOverlay;
}

void Plot::setDispChannels(QVector<const StreamChannel*> channels)
{
    zoomer.setDispChannels(channels);
}

void Plot::setYAxis(bool autoScaled, double yAxisMin, double yAxisMax)
{
    this->isAutoScaled = autoScaled;

    if (!autoScaled)
    {
        yMin = yAxisMin;
        yMax = yAxisMax;
    }

    zoomer.zoom(0);
    resetAxes();
}

void Plot::setXAxis(double xMin, double xMax)
{
    _xMin = xMin;
    _xMax = xMax;

    zoomer.setXLimits(xMin, xMax);
    zoomer.zoom(0); // unzoom

    // set axis
    // setAxisScale(QwtPlot::xBottom, xMin, xMax);
    replot(); // Note: if we don't replot here scale at startup isn't set correctly

    // reset zoom base
    // auto base = zoomer.zoomBase();
    // base.setLeft(xMin);
    // base.setRight(xMax);
    // zoomer.setZoomBase(base);

    onXScaleChanged();
}

void Plot::resetAxes()
{
    // reset y axis
    if (isAutoScaled)
    {
        setAxisAutoScale(QwtPlot::yLeft);
    }
    else
    {
        setAxisScale(QwtPlot::yLeft, yMin, yMax);
    }

    zoomer.setZoomBase();

    replot();
}

void Plot::unzoomed()
{
    resetAxes();
    onXScaleChanged();
}

void Plot::showGrid(bool show)
{
    grid.enableX(show);
    grid.enableY(show);
    replot();
}

void Plot::showMinorGrid(bool show)
{
    grid.enableXMin(show);
    grid.enableYMin(show);
    replot();
}

void Plot::showLegend(bool show)
{
    legend.setVisible(show);
    replot();
}

void Plot::showDemoIndicator(bool show)
{
    demoIndicator.setVisible(show);
    replot();
}

void Plot::showNoChannel(bool show)
{
    noChannelIndicator.setVisible(show);
    replot();
}

void Plot::unzoom()
{
    zoomer.zoom(0);
}

void Plot::darkBackground(bool enabled)
{
    QColor gridColor;
    if (enabled)
    {
        setCanvasBackground(QBrush(Qt::black));
        gridColor.setHsvF(0, 0, 0.25);
        grid.setPen(gridColor);
        zoomer.setRubberBandPen(QPen(Qt::white));
        zoomer.setTrackerPen(QPen(Qt::white));
        sZoomer.setPickerPen(QPen(Qt::white));
        legend.setTextPen(QPen(Qt::white));
    }
    else
    {
        setCanvasBackground(QBrush(Qt::white));
        gridColor.setHsvF(0, 0, 0.80);
        grid.setPen(gridColor);
        zoomer.setRubberBandPen(QPen(Qt::black));
        zoomer.setTrackerPen(QPen(Qt::black));
        sZoomer.setPickerPen(QPen(Qt::black));
        legend.setTextPen(QPen(Qt::black));
    }
    updateSymbols();
    replot();
}

void Plot::flashSnapshotOverlay(bool light)
{
    if (snapshotOverlay != NULL) delete snapshotOverlay;

    QColor color;
    if(light)
    {
        color = QColor(Qt::white);
    }
    else
    {
        color = QColor(Qt::black);
    }

    snapshotOverlay = new PlotSnapshotOverlay(this->canvas(), color);
    connect(snapshotOverlay, &PlotSnapshotOverlay::done,
            [this]()
            {
                delete snapshotOverlay;
                snapshotOverlay = NULL;
            });
}

void Plot::setSymbols(ShowSymbols shown)
{
    showSymbols = shown;

    if (showSymbols == Plot::ShowSymbolsAuto)
    {
        calcSymbolSize();
    }
    else if (showSymbols == Plot::ShowSymbolsShow)
    {
        symbolSize = SYMBOL_SIZE_MAX;
    }
    else
    {
        symbolSize = 0;
    }

    updateSymbols();
    replot();
}

void Plot::onXScaleChanged()
{
    if (showSymbols == Plot::ShowSymbolsAuto)
    {
        calcSymbolSize();
        updateSymbols();
    }
}

void Plot::calcSymbolSize()
{
    auto sw = axisWidget(QwtPlot::xBottom);
    auto paintDist = sw->scaleDraw()->scaleMap().pDist();
    auto scaleDist = sw->scaleDraw()->scaleMap().sDist();
    auto fullScaleDist = zoomer.zoomBase().width();
    auto zoomRate = fullScaleDist / scaleDist;
    float plotWidthNumSamp = abs(numOfSamples * plotWidth / (_xMax - _xMin));
    float samplesInView = plotWidthNumSamp / zoomRate;
    int symDisPx = round(paintDist / samplesInView);

    if (symDisPx < SYMBOL_SHOW_AT_WIDTH)
    {
        symbolSize = 0;
    }
    else
    {
        symbolSize = std::min(SYMBOL_SIZE_MAX, symDisPx-SYMBOL_SHOW_AT_WIDTH+1);
    }
}

void Plot::updateSymbols()
{
    const QwtPlotItemList curves = itemList( QwtPlotItem::Rtti_PlotCurve );

    if (curves.size() > 0)
    {
        for (int i = 0; i < curves.size(); i++)
        {
            QwtSymbol* symbol = NULL;
            QwtPlotCurve* curve = static_cast<QwtPlotCurve*>(curves[i]);
            if (symbolSize)
            {
                symbol = new QwtSymbol(QwtSymbol::Ellipse,
                                       canvasBackground(),
                                       curve->pen(),
                                       QSize(symbolSize, symbolSize));
            }
            curve->setSymbol(symbol);
        }
    }
}

void Plot::resizeEvent(QResizeEvent * event)
{
    QwtPlot::resizeEvent(event);
    onXScaleChanged();
}

void Plot::setNumOfSamples(unsigned value)
{
    numOfSamples = value;
    onXScaleChanged();
}

void Plot::setPlotWidth(double width)
{
    plotWidth = width;
    zoomer.setHViewSize(width);
}