#include "ref.h" /* * Special class to change axis tick marks to the correct * values. Used to show different types of scales, such as * air meters, ice meters, time, or frequency. */ class rDepthScaleDraw: public QwtScaleDraw { public: MatrixData* data; PlotOptions* plot; rDepthScaleDraw( MatrixData* d, PlotOptions* p ) { data = d; plot = p; } virtual QwtText label(double v) const { // Send getDepthScaleVal the pixel tick mark value, and get the scaled value. double depth = data->getDepthScaleVal( 0, 2, v ); // Invert the axis value. depth -= plot->timeOffset; // Convert the double to a QString, as the label is a string. QString s; s.sprintf( "%.2f", depth ); return s; } private: }; /* * Special class that was included in the Qwt example. * Sets up the capability to zoom in and out on the plot. */ class MyZoomer: public QwtPlotZoomer { public: MyZoomer(QwtPlotCanvas *canvas): QwtPlotZoomer(canvas) { setTrackerMode(AlwaysOn); } virtual QwtText trackerText(const QwtDoublePoint &pos) const { QColor bg(Qt::white); #if QT_VERSION >= 0x040300 bg.setAlpha(200); #endif QwtText text = QwtPlotZoomer::trackerText(pos); text.setBackgroundBrush( QBrush( bg )); return text; } }; /* * Special data object for the plotting to work properly. * QwtPlot expects an object that is of type QwtData, with * certain functions to work properly. This class sets up * those functions. */ class rData: public QwtData { public: rData() { } rData( int chan, MatrixData* data, int size, PlotOptions* p ) { // Initialize the member variables. dataVals = data; s = size; params = p; singleChan = chan; } // Create a new copy of the data object. virtual QwtData *copy() const { return new rData( singleChan, dataVals, s, params ); } // Return the size. virtual size_t size() const { return s; } // Return the x value. Just returns itself, as we are // plotting at every column point in the data container. virtual double x(size_t i) const { return i; } // Return the y value. This is retrieved from the data container. virtual double y(size_t i) const { if( i < s ) { // Check to make sure the channel to plot is a valid channel. if( ( singleChan >= 0 ) && ( singleChan < dataVals->getChanNum() ) ) { // Pass in the channel to plot, along with the column and row values. return dataVals->getRefPulse( singleChan, i ); } } // Should never reach here, but just in case, return 0.0. return 0.0; } private: MatrixData* dataVals; // Pointer to the data container. unsigned int s; // Length of the plot window. unsigned int plot; // Type of A-Scope plot. PlotOptions* params; int singleChan; // Value for which channel to plot, if plotting individual channels. double pointInterval; // The number of points represented between each pixel on the screen. }; /* Function: Ref * Params In * bool* chans: Pointer to the list of which channels are checked. * int pType: Type of A-Scope to display. (Sum or Individual) * QWidget* parent: Pointer to the parent object of the Ref. * MatrixData* data: Pointer to the data container. * Return * N/A * Purpose * Default constructor. Sets up the plot widget with different curves based on which * type of A-Scope the user wants displayed. Also enables zooming on the plot. */ Ref::Ref( PlotOptions* p, QWidget *parent, MatrixData* data ):QwtPlot( parent ) { // Initialize variables. uavData = data; plotOpt = p; // Initialize array. refChans = new QwtPlotCurve*[ uavData->getChanNum() + 1 ]; // Setup the colors for each curve. initCurveColors(); //Disable polygon clipping QwtPainter::setDeviceClipping(false); // We don't need the cache here canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false); // Setup window title and legend. setTitle("Reference Waveform(s) Plot"); insertLegend(new QwtLegend(), QwtPlot::RightLegend); setCanvasBackground( Qt::black ); // Setup grid lines QwtPlotGrid *grid = new QwtPlotGrid; grid->enableXMin( true ); grid->enableYMin( true ); grid->setMajPen( QPen( Qt::gray, 0, Qt::DotLine ) ); grid->setMinPen( QPen( Qt::gray, 0 , Qt::DotLine ) ); grid->attach( this ); // Set axis titles setAxis(); // As a precaution, make the curves = NULL. removeCurves(); // Create the curves that will be used in the plot. setupCurves(); // Set the data for each curve to plot. setCurveData(); // LeftButton for the zooming // MidButton for the panning // RightButton: zoom out by 1 // Ctrl+RighButton: zoom out to full size zoomer = new MyZoomer(canvas()); zoomer->setMousePattern( QwtEventPattern::MouseSelect2, Qt::RightButton, Qt::ControlModifier ); zoomer->setMousePattern( QwtEventPattern::MouseSelect3, Qt::RightButton ); panner = new QwtPlotPanner( 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); //Redraw the image. scale(); } /* Function: initCurveColors * Params In * N/A * Return * N/A * Purpose * Function sets up colors for 9 different curves, or 8 channels. * ( curveColors[0] is for the sum of channels. ) */ void Ref::initCurveColors() { // Initialize the colors for each possible curve. // Maximum number of curves supported is 8 channels. // These are use for showing individual channels. // When displaying the sum of selected channels, black is default. curveColors[0] = "#0000ff"; // Blue curveColors[1] = "#ff0000"; // Red curveColors[2] = "#00ff00"; // Green curveColors[3] = "#00ffff"; // Cyan curveColors[4] = "#ff00ff"; // Magenta curveColors[5] = "#800000"; // Dark Red curveColors[6] = "#ffff00"; // Yellow curveColors[7] = "#a0a0a4"; // Gray } /* Function: redraw * Params In * N/A * Return * N/A * Purpose * Only calls replot(), which forces the window to replot the data. * Redraw is called after new data has arrived, so the plot should * change, as long as the new data was different from the old data. */ void Ref::redraw() { replot(); } /* Function: reset * Params In * N/A * Return * N/A * Purpose * Function clears the plot, sets up the axis, and adds the selected curves * to the plot. */ void Ref::reset() { // Clear the plot and cache. clear(); canvas()->invalidatePaintCache(); // Set up the axis values and labels. setAxis(); // Remove the curves, add the new curves and set the data to be plotted. removeCurves(); setupCurves(); setCurveData(); // Scale the axis to the data. scale(); // LeftButton for the zooming // MidButton for the panning // RightButton: zoom out by 1 level on the stack // Ctrl+RighButton: zoom out to full size delete zoomer; delete panner; zoomer = new MyZoomer(canvas()); zoomer->setMousePattern( QwtEventPattern::MouseSelect2, Qt::RightButton, Qt::ControlModifier ); zoomer->setMousePattern( QwtEventPattern::MouseSelect3, Qt::RightButton ); panner = new QwtPlotPanner( canvas() ); panner->setAxisEnabled( QwtPlot::yRight, false ); panner->setMouseButton( Qt::MidButton ); } /* Function: setCurveData * Params In * N/A * Return * N/A * Purpose * Function sets the data for each curve, including the sum of channels curve. * After the data is set, only the curves that should be displayed are attached * to the plot window and set to visible. This makes sure that unneeded curves * are not plotted, which would waste valuable clock cycles for every refresh. */ void Ref::setCurveData() { // Set the data for each channel's curve, and the sum of channels curve. for( int i = 0; i < uavData->getChanNum(); ++i ) { refChans[i]->setData( rData( i, uavData, uavData->getColumnLen( 3 ), plotOpt ) ); } // Detach every channel and make them invisible. // This removes the curve from the canvas so that it // will not be drawn during the next replot. for( int j = 0; j < uavData->getChanNum(); ++j ) { refChans[j]->detach(); refChans[j]->setVisible( false ); } // Attach and make visible the curves for each channel selected. for( int k = 0; k < uavData->getChanNum(); ++k ) { if( plotOpt->channels[k] ) { refChans[k]->attach( this ); refChans[k]->setVisible( true ); } } } /* Function: setupCurves * Params In * N/A * Return * N/A * Purpose * Only calls replot(), which forces the window to replot the data. * Redraw is called after new data has arrived, so the plot should * change, as long as the new data was different from the old data. */ void Ref::setupCurves() { // Setup the curves for each individual channel. for( int i = 0; i < uavData->getChanNum(); ++i ) { QString chan = "Channel "; QString chNum; chNum.setNum( i + 1 ); chan += chNum; refChans[i] = new QwtPlotCurve( chan ); QPen color( curveColors[i] ); color.setWidth( 2 ); refChans[i]->setPen( QPen( color ) ); refChans[i]->setPaintAttribute( QwtPlotCurve::ClipPolygons, true ); } } void Ref::removeCurves() { for( int i = 0; i < uavData->getChanNum(); ++i ) { refChans[i] = NULL; } } void Ref::scale() { this->setAxisAutoScale( QwtPlot::yLeft ); replot(); QwtScaleDiv* temp = this->axisScaleDiv( QwtPlot::yLeft ); this->setAxisScaleDiv( QwtPlot::yLeft, *temp ); // LeftButton for the zooming // MidButton for the panning // RightButton: zoom out by 1 level on the stack // Ctrl+RighButton: zoom out to full size delete zoomer; delete panner; zoomer = new MyZoomer(canvas()); zoomer->setMousePattern( QwtEventPattern::MouseSelect2, Qt::RightButton, Qt::ControlModifier ); zoomer->setMousePattern( QwtEventPattern::MouseSelect3, Qt::RightButton ); panner = new QwtPlotPanner( canvas() ); panner->setAxisEnabled( QwtPlot::yRight, false ); panner->setMouseButton( Qt::MidButton ); } /* Function: setAxis * Params In * N/A * Return * N/A * Purpose * Only calls replot(), which forces the window to replot the data. * Redraw is called after new data has arrived, so the plot should * change, as long as the new data was different from the old data. */ void Ref::setAxis() { // setAxisScale( QwtPlot::xBottom, 0, uavData->getColumnLen( 3 )-1 ); // Set the depth scale for the xBottom axis. setAxisScaleDraw( QwtPlot::xBottom, new rDepthScaleDraw( uavData, plotOpt ) ); setAxisTitle( QwtPlot::yLeft, "Amplitude" ); setAxisTitle( QwtPlot::xBottom, "Two Way Time (us)" ); }