/** * @author Ian Johnson * @version 1.0 */ #include "SlsQt1DPlot.h" #include #include #include #include #include #include #include #include #include #include "qwt_symbol.h" #include #if QWT_VERSION >= 0x060100 #define QwtLog10ScaleEngine QwtLogScaleEngine #endif SlsQtH1D::SlsQtH1D(QString title, int n, double min, double max, double *data) : QwtPlotCurve(title) { 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 = 0; 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); } #if QWT_VERSION < 0x060000 setSymbol(*marker); #else setSymbol(marker); #endif } 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]; } #if QWT_VERSION < 0x060000 setRawData(x, y, ndata); #else setRawSamples(x, y, ndata); #endif } 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]; } // #if QWT_VERSION<0x060000 // setRawData(x,y,ndata); // #else setRawSamples(x, y, ndata); // #endif } int SlsQtH1D::SetUpArrays(int n) { n = n < 1 ? 1 : n; //overflow bin if (n + 1 > n_array) { n_array = n + 1; if (x) delete x; if (y) 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() { if (the_next) 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; if (hline) delete hline; if (vline) delete vline; } 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() { #if QWT_VERSION < 0x060000 // Disable polygon clipping //not supported for version 6 QwtPainter::setDeviceClipping(false); canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false); canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false); #else // We don't need the cache here ((QwtPlotCanvas *)canvas())->setPaintAttribute(QwtPlotCanvas::BackingStore, false); #endif #if QT_VERSION >= 0x040000 #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 #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; #ifdef VERBOSE if (disable) std::cout << "Disabling zoom\n"; else std::cout << "Enabling zoom\n"; #endif if (disable) { if (zoomer) { zoomer->setMousePattern(QwtEventPattern::MouseSelect1, Qt::NoButton); #if QT_VERSION < 0x040000 zoomer->setMousePattern(QwtEventPattern::MouseSelect2, Qt::NoButton, Qt::ControlButton); #else zoomer->setMousePattern(QwtEventPattern::MouseSelect2, Qt::NoButton, Qt::ControlModifier); #endif zoomer->setMousePattern(QwtEventPattern::MouseSelect3, Qt::NoButton); } if (panner) panner->setMouseButton(Qt::NoButton); } else { if (zoomer) { zoomer->setMousePattern(QwtEventPattern::MouseSelect1, Qt::LeftButton); #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); } if (panner) panner->setMouseButton(Qt::MidButton); } } }