mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-04-23 15:00:02 +02:00
589 lines
16 KiB
C++
589 lines
16 KiB
C++
|
|
/**
|
|
* @author Ian Johnson
|
|
* @version 1.0
|
|
*/
|
|
|
|
#include "SlsQt1DPlot.h"
|
|
#include "qwt_symbol.h"
|
|
#include <iostream>
|
|
#include <qwt_legend.h>
|
|
#include <qwt_math.h>
|
|
#include <qwt_painter.h>
|
|
#include <qwt_plot_canvas.h>
|
|
#include <qwt_plot_curve.h>
|
|
#include <qwt_scale_draw.h>
|
|
#include <qwt_scale_engine.h>
|
|
#include <qwt_scale_widget.h>
|
|
#include <stdlib.h>
|
|
|
|
#define QwtLog10ScaleEngine QwtLogScaleEngine // hmm
|
|
|
|
SlsQtH1D::SlsQtH1D(QString title, int n, double min, double max, double *data)
|
|
: QwtPlotCurve(title), x(nullptr), y(nullptr), pen_ptr(nullptr) {
|
|
Initailize();
|
|
SetData(n, min, max, data);
|
|
}
|
|
|
|
SlsQtH1D::SlsQtH1D(QString title, int n, double *data_x, double *data_y)
|
|
: QwtPlotCurve(title) {
|
|
Initailize();
|
|
SetData(n, data_x, data_y);
|
|
}
|
|
|
|
void SlsQtH1D::Initailize() {
|
|
ndata = n_array = 0;
|
|
x = y = nullptr;
|
|
pen_ptr = new QPen();
|
|
SetLineColor();
|
|
}
|
|
|
|
SlsQtH1D::~SlsQtH1D() {
|
|
|
|
delete[] x;
|
|
|
|
delete[] y;
|
|
|
|
delete pen_ptr;
|
|
}
|
|
|
|
void SlsQtH1D::Attach(SlsQt1DPlot *p) {
|
|
attach((QwtPlot *)p);
|
|
p->NewHistogramAttached(this);
|
|
}
|
|
|
|
void SlsQtH1D::Detach(SlsQt1DPlot *p) {
|
|
detach();
|
|
p->HistogramDetached(this);
|
|
}
|
|
|
|
int SlsQtH1D::SetLineColor(int c) {
|
|
static int last_color = 1;
|
|
if (c < 0)
|
|
c = (last_color + 1) % 3;
|
|
|
|
switch (c) {
|
|
case 0:
|
|
pen_ptr->setColor(Qt::black);
|
|
break;
|
|
case 1:
|
|
pen_ptr->setColor(Qt::red);
|
|
break;
|
|
case 2:
|
|
pen_ptr->setColor(Qt::blue);
|
|
break;
|
|
case 3:
|
|
pen_ptr->setColor(Qt::green);
|
|
break;
|
|
case 4:
|
|
pen_ptr->setColor(Qt::magenta);
|
|
break;
|
|
case 5:
|
|
pen_ptr->setColor(Qt::cyan);
|
|
break;
|
|
case 6:
|
|
pen_ptr->setColor(Qt::darkYellow);
|
|
break;
|
|
case 7:
|
|
pen_ptr->setColor(Qt::gray);
|
|
break;
|
|
case 8:
|
|
pen_ptr->setColor(Qt::darkBlue);
|
|
break;
|
|
case 9:
|
|
pen_ptr->setColor(Qt::darkGreen);
|
|
break;
|
|
case 10:
|
|
pen_ptr->setColor(Qt::darkMagenta);
|
|
break;
|
|
}
|
|
/* if(c==0) pen_ptr->setColor(Qt::black);
|
|
else if(c==1) pen_ptr->setColor(Qt::red);
|
|
else pen_ptr->setColor(Qt::blue);*/
|
|
|
|
setPen(*pen_ptr);
|
|
|
|
return last_color = c;
|
|
}
|
|
|
|
int SlsQtH1D::SetLineWidth(int w) {
|
|
pen_ptr->setWidth(w);
|
|
setPen(*pen_ptr);
|
|
return w;
|
|
}
|
|
|
|
void SlsQtH1D::SetLineStyle(int s) {
|
|
if (s == 1)
|
|
pen_ptr->setStyle(Qt::DashLine);
|
|
else if (s == 2)
|
|
pen_ptr->setStyle(Qt::DotLine);
|
|
else if (s == 3)
|
|
pen_ptr->setStyle(Qt::DashDotLine);
|
|
else if (s == 4)
|
|
pen_ptr->setStyle(Qt::DashDotDotLine);
|
|
else if (s == 5)
|
|
pen_ptr->setStyle(Qt::CustomDashLine);
|
|
else
|
|
pen_ptr->setStyle(Qt::SolidLine);
|
|
setPen(*pen_ptr);
|
|
}
|
|
|
|
void SlsQtH1D::setStyleLinesorDots(bool isLines) {
|
|
setStyle(isLines ? QwtPlotCurve::Lines : QwtPlotCurve::Dots);
|
|
}
|
|
|
|
void SlsQtH1D::setSymbolMarkers(bool isMarker) {
|
|
QwtSymbol *marker = new QwtSymbol();
|
|
if (isMarker) {
|
|
marker->setStyle(QwtSymbol::Cross);
|
|
marker->setSize(5, 5);
|
|
}
|
|
setSymbol(marker);
|
|
}
|
|
|
|
void SlsQtH1D::SetData(int n, double xmin, double xmax, double *data) {
|
|
n = SetUpArrays(n);
|
|
|
|
ndata = n;
|
|
if (xmin > xmax) {
|
|
double t = xmin;
|
|
xmin = xmax;
|
|
xmax = t;
|
|
}
|
|
|
|
dx = (xmax - xmin) / n;
|
|
ymin = ymax = data ? data[0] : 0;
|
|
firstXgt0 = -1;
|
|
firstYgt0 = -1;
|
|
|
|
for (int i = 0; i < ndata; i++) {
|
|
x[i] = i ? x[i - 1] + dx : xmin;
|
|
y[i] = data ? data[i] : 0;
|
|
if (data && ymin > y[i])
|
|
ymin = y[i];
|
|
if (data && ymax < y[i])
|
|
ymax = y[i];
|
|
if (x[i] > 0 && (firstXgt0 < 0 || firstXgt0 > x[i]))
|
|
firstXgt0 = x[i];
|
|
if (y[i] > 0 && (firstYgt0 < 0 || firstYgt0 > y[i]))
|
|
firstYgt0 = y[i];
|
|
}
|
|
|
|
setRawSamples(x, y, ndata);
|
|
}
|
|
|
|
void SlsQtH1D::SetData(int n, double *data_x, double *data_y) {
|
|
|
|
int reverse = (data_x && n > 0 && data_x[0] > data_x[n - 1]) ? 1 : 0;
|
|
n = SetUpArrays(n);
|
|
|
|
ndata = n;
|
|
dx = -1; // signifies not regular intervals
|
|
|
|
ymin = ymax = data_y ? data_y[0] : 0;
|
|
|
|
firstXgt0 = -1;
|
|
firstYgt0 = -1;
|
|
|
|
for (int i = 0; i < ndata; i++) {
|
|
int b = reverse ? n - i - 1 : i;
|
|
x[b] = data_x ? data_x[i] : 0;
|
|
y[b] = data_y ? data_y[i] : 0;
|
|
if (data_y && ymin > y[b])
|
|
ymin = y[b];
|
|
if (data_y && ymax < y[b])
|
|
ymax = y[b];
|
|
if (x[b] > 0 && (firstXgt0 < 0 || firstXgt0 > x[b]))
|
|
firstXgt0 = x[b];
|
|
if (y[b] > 0 && (firstYgt0 < 0 || firstYgt0 > y[b]))
|
|
firstYgt0 = y[b];
|
|
}
|
|
setRawSamples(x, y, ndata);
|
|
}
|
|
|
|
int SlsQtH1D::SetUpArrays(int n) {
|
|
n = n < 1 ? 1 : n; // overflow bin
|
|
|
|
if (n + 1 > n_array) {
|
|
n_array = n + 1;
|
|
|
|
delete x;
|
|
|
|
delete y;
|
|
x = new double[n_array];
|
|
y = new double[n_array];
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
double SlsQtH1D::FillBin(int bx, double v) {
|
|
bx = CheckIndex(bx);
|
|
return SetBinContent(bx, y[bx] + v);
|
|
}
|
|
double SlsQtH1D::Fill(double x, double v) {
|
|
return FillBin(FindBinIndex(x), v);
|
|
}
|
|
|
|
double SlsQtH1D::SetBinContent(int bx, double v) {
|
|
bx = CheckIndex(bx);
|
|
y[bx] = v;
|
|
if (bx < ndata) {
|
|
if (y[bx] < ymin)
|
|
ymin = y[bx];
|
|
if (y[bx] > 0 && (firstYgt0 <= 0 || y[bx] < firstYgt0))
|
|
firstYgt0 = y[bx];
|
|
if (y[bx] > ymax)
|
|
ymax = y[bx];
|
|
}
|
|
return y[bx];
|
|
}
|
|
|
|
double SlsQtH1D::SetContent(double x, double v) {
|
|
return SetBinContent(FindBinIndex(x), v);
|
|
}
|
|
|
|
int SlsQtH1D::FindBinIndex(double px) {
|
|
if (dx > 0)
|
|
CheckIndex(int((px - x[0]) / dx));
|
|
|
|
// find closest bin
|
|
int b = 0;
|
|
for (; b < ndata; b++)
|
|
if (x[b] > px)
|
|
break;
|
|
|
|
if (b == 0)
|
|
return 0;
|
|
else if (fabs(px - x[b - 1]) < fabs(px - x[b]))
|
|
return b - 1;
|
|
|
|
return b;
|
|
}
|
|
|
|
int SlsQtH1D::CheckIndex(int bx) {
|
|
return (bx < 0 || bx > ndata) ? ndata : bx;
|
|
} // ndata is the overflow bin
|
|
|
|
SlsQtH1D *SlsQtH1D::Add(double v) {
|
|
for (int bx = 0; bx < ndata; bx++)
|
|
FillBin(bx, v);
|
|
return this;
|
|
}
|
|
|
|
// 1d hist list stuff
|
|
SlsQtH1DList::SlsQtH1DList(SlsQtH1D *hist) {
|
|
the_hist = hist;
|
|
the_next = 0;
|
|
}
|
|
|
|
SlsQtH1DList::~SlsQtH1DList() { delete the_next; }
|
|
|
|
SlsQtH1D *SlsQtH1DList::Add(SlsQtH1D *hist) {
|
|
SlsQtH1DList *hl = this;
|
|
|
|
while (hl) {
|
|
if (hist == hl->the_hist)
|
|
return hist; // already added
|
|
if (!hl->the_next)
|
|
break;
|
|
hl = hl->the_next;
|
|
}
|
|
if (hl->the_hist)
|
|
hl->the_next = new SlsQtH1DList(hist);
|
|
else
|
|
hl->the_hist = hist;
|
|
|
|
// Print();
|
|
|
|
return hist;
|
|
}
|
|
|
|
void SlsQtH1DList::Print() {
|
|
SlsQtH1DList *hl = this;
|
|
int i = 0;
|
|
while (hl) {
|
|
std::cout << " " << i++ << ") " << hl << " " << hl->the_hist << " "
|
|
<< hl->the_next << '\n';
|
|
hl = hl->the_next;
|
|
if (i > 10)
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SlsQtH1DList::Remove(SlsQtH1D *hist) {
|
|
SlsQtH1DList *hl = this;
|
|
while (hl) { // every match will be removed
|
|
if (hl->the_hist != hist)
|
|
hl = hl->the_next;
|
|
else { // match
|
|
if (!hl->the_next)
|
|
hl->the_hist = 0; // first the_hist is zero when there's no next
|
|
else {
|
|
SlsQtH1DList *t = hl->the_next;
|
|
hl->the_hist = t->the_hist;
|
|
hl->the_next = t->the_next;
|
|
t->the_next = 0;
|
|
delete t;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 1d plot stuff
|
|
SlsQt1DPlot::SlsQt1DPlot(QWidget *parent) : QwtPlot(parent) {
|
|
// n_histograms_attached=0;
|
|
hline = vline = 0;
|
|
hist_list = new SlsQtH1DList();
|
|
|
|
UnknownStuff();
|
|
alignScales();
|
|
SetupZoom();
|
|
|
|
// Assign a title
|
|
#ifndef IAN
|
|
insertLegend(new QwtLegend(), QwtPlot::BottomLegend);
|
|
#else
|
|
insertLegend(new QwtLegend(), QwtPlot::RightLegend);
|
|
#endif
|
|
|
|
axisScaleEngine(QwtPlot::yLeft)->setAttribute(QwtScaleEngine::Floating);
|
|
axisScaleEngine(QwtPlot::xBottom)->setAttribute(QwtScaleEngine::Floating);
|
|
}
|
|
|
|
SlsQt1DPlot::~SlsQt1DPlot() {
|
|
|
|
delete hist_list;
|
|
|
|
delete hline;
|
|
|
|
delete vline;
|
|
|
|
delete zoomer;
|
|
|
|
delete panner;
|
|
}
|
|
|
|
void SlsQt1DPlot::CalculateNResetZoomBase() {
|
|
if (hist_list->Hist())
|
|
zoomer->SetZoomBase(hist_list->Hist());
|
|
SlsQtH1DList *hl = hist_list->Next();
|
|
while (hl) {
|
|
if (hl->Hist())
|
|
zoomer->ExtendZoomBase(hl->Hist());
|
|
hl = hl->Next();
|
|
}
|
|
}
|
|
|
|
void SlsQt1DPlot::NewHistogramAttached(SlsQtH1D *h) {
|
|
hist_list->Add(h);
|
|
CalculateNResetZoomBase();
|
|
// commented out by dhanya to take off zooming every hist in 1d plots
|
|
// if(!hist_list->Next()) UnZoom();
|
|
Update();
|
|
}
|
|
|
|
void SlsQt1DPlot::HistogramDetached(SlsQtH1D *h) {
|
|
hist_list->Remove(h);
|
|
CalculateNResetZoomBase();
|
|
Update();
|
|
}
|
|
|
|
void SlsQt1DPlot::Update() { replot(); }
|
|
|
|
void SlsQt1DPlot::SetTitle(QString title) { setTitle(title); }
|
|
|
|
void SlsQt1DPlot::SetXTitle(QString title) {
|
|
setAxisTitle(QwtPlot::xBottom, title);
|
|
}
|
|
|
|
void SlsQt1DPlot::SetYTitle(QString title) {
|
|
setAxisTitle(QwtPlot::yLeft, title);
|
|
}
|
|
|
|
void SlsQt1DPlot::SetTitleFont(const QFont &f) {
|
|
QwtText t("");
|
|
t.setFont(f);
|
|
t.setRenderFlags(Qt::AlignLeft | Qt::AlignVCenter);
|
|
setTitle(t);
|
|
}
|
|
|
|
void SlsQt1DPlot::SetXFont(const QFont &f) {
|
|
QwtText t("");
|
|
t.setFont(f);
|
|
setAxisTitle(QwtPlot::xBottom, t);
|
|
}
|
|
|
|
void SlsQt1DPlot::SetYFont(const QFont &f) {
|
|
QwtText t("");
|
|
t.setFont(f);
|
|
setAxisTitle(QwtPlot::yLeft, t);
|
|
}
|
|
|
|
void SlsQt1DPlot::SetLogX(bool yes) { SetLog(QwtPlot::xBottom, yes); }
|
|
void SlsQt1DPlot::SetLogY(bool yes) { SetLog(QwtPlot::yLeft, yes); }
|
|
void SlsQt1DPlot::SetLog(int axisId, bool yes) {
|
|
if (axisId == QwtPlot::xBottom)
|
|
zoomer->SetLogX(yes);
|
|
if (axisId == QwtPlot::yLeft)
|
|
zoomer->SetLogY(yes);
|
|
|
|
zoomer->ResetZoomBase(); // needs to be done before setting Engine
|
|
|
|
// the old ones are deleted by in the setAxisScaleFunction() function see:
|
|
// 128 of file qwt_plot_axis.cpp
|
|
if (yes)
|
|
setAxisScaleEngine(axisId, new QwtLog10ScaleEngine());
|
|
else
|
|
setAxisScaleEngine(axisId, new QwtLinearScaleEngine());
|
|
|
|
axisScaleEngine(QwtPlot::yLeft)->setAttribute(QwtScaleEngine::Floating);
|
|
axisScaleEngine(QwtPlot::xBottom)->setAttribute(QwtScaleEngine::Floating);
|
|
|
|
Update();
|
|
}
|
|
|
|
void SlsQt1DPlot::UnZoom() {
|
|
setAxisScale(QwtPlot::xBottom, zoomer->x(), zoomer->x() + zoomer->w());
|
|
setAxisScale(QwtPlot::yLeft, zoomer->y(), zoomer->y() + zoomer->h());
|
|
|
|
zoomer->setZoomBase(); // Call replot for the attached plot before
|
|
// initializing the zoomer with its scales.
|
|
Update();
|
|
}
|
|
|
|
void SlsQt1DPlot::SetZoom(double xmin, double ymin, double x_width,
|
|
double y_width) {
|
|
setAxisScale(QwtPlot::xBottom, xmin, xmin + x_width);
|
|
setAxisScale(QwtPlot::yLeft, ymin, ymin + y_width);
|
|
Update();
|
|
}
|
|
|
|
void SlsQt1DPlot::RemoveHLine() {
|
|
if (hline)
|
|
hline->detach();
|
|
delete hline;
|
|
hline = 0;
|
|
}
|
|
|
|
void SlsQt1DPlot::InsertHLine(double y) {
|
|
if (!hline) {
|
|
hline = new QwtPlotMarker();
|
|
hline->setLabelAlignment(Qt::AlignRight | Qt::AlignTop);
|
|
hline->setLineStyle(QwtPlotMarker::HLine);
|
|
hline->attach(this);
|
|
}
|
|
hline->setYValue(y);
|
|
}
|
|
|
|
void SlsQt1DPlot::RemoveVLine() {
|
|
if (vline)
|
|
vline->detach();
|
|
delete vline;
|
|
vline = 0;
|
|
}
|
|
|
|
void SlsQt1DPlot::InsertVLine(double x) {
|
|
if (!vline) {
|
|
vline = new QwtPlotMarker();
|
|
vline->setLabelAlignment(Qt::AlignRight | Qt::AlignTop);
|
|
vline->setLineStyle(QwtPlotMarker::VLine);
|
|
vline->attach(this);
|
|
}
|
|
vline->setXValue(x);
|
|
}
|
|
|
|
void SlsQt1DPlot::SetupZoom() {
|
|
// LeftButton for the zooming
|
|
// MidButton for the panning
|
|
// RightButton: zoom out by 1
|
|
// Ctrl+RighButton: zoom out to full size
|
|
|
|
zoomer = new SlsQt1DZoomer(canvas());
|
|
|
|
#if QT_VERSION < 0x040000
|
|
zoomer->setMousePattern(QwtEventPattern::MouseSelect2, Qt::RightButton,
|
|
Qt::ControlButton);
|
|
#else
|
|
zoomer->setMousePattern(QwtEventPattern::MouseSelect2, Qt::RightButton,
|
|
Qt::ControlModifier);
|
|
#endif
|
|
zoomer->setMousePattern(QwtEventPattern::MouseSelect3, Qt::RightButton);
|
|
|
|
panner = new QwtPlotPanner((QwtPlotCanvas *)canvas());
|
|
panner->setAxisEnabled(QwtPlot::yRight, false);
|
|
panner->setMouseButton(Qt::MidButton);
|
|
|
|
// Avoid jumping when labels with more/less digits
|
|
// appear/disappear when scrolling vertically
|
|
|
|
const QFontMetrics fm(axisWidget(QwtPlot::yLeft)->font());
|
|
QwtScaleDraw *sd = axisScaleDraw(QwtPlot::yLeft);
|
|
sd->setMinimumExtent(fm.width("100.00"));
|
|
|
|
const QColor c(Qt::darkBlue);
|
|
zoomer->setRubberBandPen(c);
|
|
zoomer->setTrackerPen(c);
|
|
}
|
|
|
|
// Set a plain canvas frame and align the scales to it
|
|
void SlsQt1DPlot::alignScales() {
|
|
// The code below shows how to align the scales to
|
|
// the canvas frame, but is also a good example demonstrating
|
|
// why the spreaded API needs polishing.
|
|
|
|
((QwtPlotCanvas *)canvas())->setFrameStyle(QFrame::Box | QFrame::Plain);
|
|
((QwtPlotCanvas *)canvas())->setLineWidth(1);
|
|
|
|
for (int i = 0; i < QwtPlot::axisCnt; i++) {
|
|
QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(i);
|
|
if (scaleWidget)
|
|
scaleWidget->setMargin(0);
|
|
QwtScaleDraw *scaleDraw = (QwtScaleDraw *)axisScaleDraw(i);
|
|
if (scaleDraw)
|
|
scaleDraw->enableComponent(QwtAbstractScaleDraw::Backbone, false);
|
|
}
|
|
}
|
|
|
|
void SlsQt1DPlot::UnknownStuff() {
|
|
// We don't need the cache here
|
|
((QwtPlotCanvas *)canvas())
|
|
->setPaintAttribute(QwtPlotCanvas::BackingStore, false);
|
|
#ifdef Q_WS_X11
|
|
// Qt::WA_PaintOnScreen is only supported for X11, but leads
|
|
// to substantial bugs with Qt 4.2.x/Windows
|
|
canvas()->setAttribute(Qt::WA_PaintOnScreen, true);
|
|
#endif
|
|
}
|
|
|
|
// Added by Dhanya on 19.06.2012 to disable zooming when any of the axes range
|
|
// has been set
|
|
void SlsQt1DPlot::DisableZoom(bool disable) {
|
|
if (disableZoom != disable) {
|
|
disableZoom = disable;
|
|
if (disable) {
|
|
if (zoomer) {
|
|
zoomer->setMousePattern(QwtEventPattern::MouseSelect1,
|
|
Qt::NoButton);
|
|
zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
|
|
Qt::NoButton, Qt::ControlModifier);
|
|
zoomer->setMousePattern(QwtEventPattern::MouseSelect3,
|
|
Qt::NoButton);
|
|
}
|
|
if (panner)
|
|
panner->setMouseButton(Qt::NoButton);
|
|
} else {
|
|
if (zoomer) {
|
|
zoomer->setMousePattern(QwtEventPattern::MouseSelect1,
|
|
Qt::LeftButton);
|
|
zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
|
|
Qt::RightButton, Qt::ControlModifier);
|
|
zoomer->setMousePattern(QwtEventPattern::MouseSelect3,
|
|
Qt::RightButton);
|
|
}
|
|
if (panner)
|
|
panner->setMouseButton(Qt::MidButton);
|
|
}
|
|
}
|
|
}
|