/* Copyright (c) 2008-2015 Jan W. Krieger (, ) (DKFZ) & IWR, University of Heidelberg This software is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program 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 Lesser General Public License (LGPL) for more details. You should have received a copy of the GNU Lesser General Public License (LGPL) along with this program. If not, see . */ /* Name: jkqtpfastplotter.h Copyright: (c) 2010 Author: Jan krieger , http://www.jkrieger.de/ */ /** * \defgroup jkqtfastplotter Speed-Optimized Plotter class * \ingroup tools_qt */ /** \file jkqtpfastplotter.h * \ingroup jkqtfastplotter */ #ifndef JKQTFASTPLOTTER_H #define JKQTFASTPLOTTER_H #include "jkqtplottertools/jkqtp_imexport.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "jkqtplottertools/jkqtptools.h" #ifdef DEBUG_TIMING # include "jkqtplottertools/jkqtphighrestimer.h" #endif #define JKQTFASTPLOTTER_ABS_MIN_LINEWIDTH 0.05 // forward declaration class JKQTFPPlot; #ifndef JKQTFASTPLOTTER_NOOPENGL # define JKQTFASTPLOTTER_BASEWIDGET QGLWidget # define JKQTFASTPLOTTER_BASEWIDGET_CONSTRUCTOR(parent) QGLWidget(QGLFormat(QGL::StencilBuffer | QGL::AlphaChannel | QGL::Rgba), parent) #else # define JKQTFASTPLOTTER_BASEWIDGET QWidget # define JKQTFASTPLOTTER_BASEWIDGET_CONSTRUCTOR(parent) QWidget(parent) #endif /** * \brief create a property variable and a default variable for it. Also creates a doxygen comment for the default variable * \ingroup jkqtfastplotter */ #define JKQTFPPROPERTY(type,varname) \ type varname; \ /** \brief default value for property property varname. \see varname for more information */ \ type def_##varname; /** * \brief saves the given property (for which also a def_property exists) into the given settings object * \ingroup jkqtfastplotter */ #define JKQTFPPROPERTYsave(settings, group, var, varname) \ if (var!=def_##var) settings.setValue(group+varname, var); /** * \brief loads the given property from the given settings object * \ingroup jkqtfastplotter */ #define JKQTFPPROPERTYload(settings, group, var, varname, varconvert) \ var=settings.value(group+varname, var).varconvert; /*! \brief a speed optimized plotter class \ingroup jkqtfastplotter This plotter class is (in contrast to JKQTPlotter) optimized for speed. It allows to plot function graphs/data in a simple manner. The focus of design was not on a nice output (athough this is not unimportant), but on the speed of the output. So the class may be used to di quick plotting of data, i.e. in fast image sequence applications. These measures were taken to increase speed: - The coordinate system is drawn onto an internal image which is only updated, when the size of the widget or a property of the coordinate system changes. When only the data changes, just the data plot has to be updated. - The class uses an internal buffer with the complete image, so a repaint does not always trigger a complete repaint of all elements, but just measns painting the internal image to the screen. This also allows to plot selections ... over the plot, without having to replot the plots. - The definition of the coordinate system as well as the definition the system ticks ... is reduced to the absolute minimum. - The method set_doDrawing() allows to prevent replotting of the class contents, e.g. when you want to set a multitude of parameters without triggering a replot every time. . The class supports these features: - coordinate axes may be linear or logarithmic. - ticks and tick labels are drawn by a simple algorithm: The user has to supply two values: \c zeroTick is a tick value that exists in any case (i.e. 0) and \c tickDistance which contains the distance between two ticks (only applicable to linear axes). Then the class starts to draw at zeroTick and move on to \c zeroTick+tickDistance and \c zeroTick-tickDistance until \c min / \c max of the axis is reached. For logarithmic axes the class uses \c zeroTick*10 and \c zeroTick/10 - plot may contain a grid (x and y grid may be switched on/off separately). - plots are represented by descendents of JKQTFPPlot and the plotting code is completely contained therein (and should be speed optimized). - it is possible to keep a specified aspect ration - it is possible to couple different plots in a way, that they are plottetd with the same width/height both in pixel and world coordinates by using plotterSizesChanged() and synchronizeX() / synchronizeY(). . */ class LIB_EXPORT JKQTFastPlotter : public JKQTFASTPLOTTER_BASEWIDGET { Q_OBJECT protected: /** \brief indicates whether to do full repaint (system and data) at the next repaint (any of the repaint meothods) */ bool doFullRepaint; /** \brief this stores the currently displayed coordinate system */ QImage systemImage; /** \brief this stores the currently displayed plot */ QImage image; /** \brief this can be used when drawing a zoom rectangle to store an unchanged * copy of the currently displayed image. */ QImage oldImage; /** \brief if \c false the plotting won't be performed (may be used to set more than one parameter without replot */ bool doDrawing; /** \brief list of plots in this graph */ QVector plots; /** \brief free space between widget left border and plot left border */ JKQTFPPROPERTY(int, plotBorderLeft); /** \brief free space between widget bottom border and plot bottom border */ JKQTFPPROPERTY(int, plotBorderBottom); /** \brief free space between widget right border and plot left border */ JKQTFPPROPERTY(int, plotBorderRight); /** \brief free space between widget top border and plot bottom border */ JKQTFPPROPERTY(int, plotBorderTop); /** \brief internally calculated: free space between widget left border and plot left border * * \note This is the actual border used for plotting, as it may be different from what the user supplied. * Note also that this is at least as huge as the suer supplied border value! */ int internalPlotBorderLeft; /** \brief internally calculated: free space between widget bottom border and plot bottom border * * \note This is the actual border used for plotting, as it may be different from what the user supplied. * Note also that this is at least as huge as the suer supplied border value! */ int internalPlotBorderBottom; /** \brief internally calculated: free space between widget right border and plot left border * * \note This is the actual border used for plotting, as it may be different from what the user supplied. * Note also that this is at least as huge as the suer supplied border value! */ int internalPlotBorderRight; /** \brief internally calculated: free space between widget top border and plot bottom border * * \note This is the actual border used for plotting, as it may be different from what the user supplied. * Note also that this is at least as huge as the suer supplied border value! */ int internalPlotBorderTop; /** \brief plot width in pixels inside the widget (calculated by calcPlotScaling() from plotBorderLeft, plotBorderRight and widgetWidth) */ int plotWidth; /** \brief plot height in pixels inside the widget (calculated by calcPlotScaling() from plotBorderTop, plotBorderBottom and widgetHeight) */ int plotHeight; /** \brief color of the coordinate system */ JKQTFPPROPERTY(QColor, systemColor); /** \brief width of the coordinate (in pixel) */ JKQTFPPROPERTY(double, systemWidth); /** \brief color of the background*/ JKQTFPPROPERTY(QColor, backgroundColor); /** \brief color of the plot's background * * \note the background is not drawn if this color is set to \c QColor(Qt::transparent) ! */ JKQTFPPROPERTY(QColor, plotBackgroundColor); /** \brief indicates whether to draw a system box */ JKQTFPPROPERTY(bool, drawSystemBox); /** \brief indicates whether to draw axes at x=0/y=0 */ JKQTFPPROPERTY(bool, drawZeroAxes); /** \brief indicates whether to draw a grid */ JKQTFPPROPERTY(bool, drawGrid); /** \brief color of the coordinate grid */ JKQTFPPROPERTY(QColor, gridColor); /** \brief style of the coordinate grid */ JKQTFPPROPERTY(Qt::PenStyle, gridStyle); /** \brief width of the coordinate grid (in pixel) */ JKQTFPPROPERTY(double, gridWidth); /** \brief font size (in points) of the axis labels */ JKQTFPPROPERTY(double, labelFontSize); /** \brief font name of the axis labels */ JKQTFPPROPERTY(QString, labelFontName); /** \brief font size (in points) of the tick labels */ JKQTFPPROPERTY(double, tickFontSize); /** \brief font name of the tick labels */ JKQTFPPROPERTY(QString, tickFontName); /** \brief length of an axis tick (pixels) */ JKQTFPPROPERTY(double, tickLength); /** \brief minimum value of x axis */ double xMin; /** \brief maximum value of x axis */ double xMax; /** \brief minimum value of y axis */ double yMin; /** \brief maximum value of y axis */ double yMax; /** \brief is x axis logarithmic? */ bool xAxisLog; /** \brief is x axis logarithmic? */ bool yAxisLog; /** \brief width of plot on x axis (calculated internally) */ double xWidth; /** \brief x axis scaling factor (calculated internally) */ double xScale; /** \brief x axis offset (calculated internally) */ double xOffset; /** \brief width of plot on y axis (calculated internally) */ double yWidth; /** \brief y axis scaling factor (calculated internally) */ double yScale; /** \brief y axis offset (calculated internally) */ double yOffset; /** \brief a label position from which axis label plotting is started for the x axis */ double xZeroTick; /** \brief a label position from which axis label plotting is started for the y axis */ double yZeroTick; /** \brief distance between two labels on x axis */ double xTickDistance; /** \brief distance between two labels on y axis */ double yTickDistance; /** \brief label of x axis */ QString xAxisLabel; /** \brief label of y axis */ QString yAxisLabel; /** \brief plot y axis label */ bool yAxisLabelVisible; /** \brief plot x axis label */ bool xAxisLabelVisible; /** \brief synchronize x-axis settings to this plotter */ JKQTFastPlotter* synchronizeX; /** \brief synchronize y-axis settings to this plotter */ JKQTFastPlotter* synchronizeY; /** \brief aspect ration of the plot, only used when maintainAspectRation is \c true * * The aspect ratio is defined as \c width/height of the plot in pixels. * So if you want to have a plot spanning \c x=0..20 and \c y=0..10 where each 1x1 square should be * as wide as high you will have to set aspectRatio to \c 2 . * * \note Note that aspect ratios only make sense for linear-linear plots. This will be ignored * if any one axis is logarithmic. */ double aspectRatio; /** \brief indicates whether to maintain a specific aspect ratio */ bool maintainAspectRatio; QPoint mouseDragStart; QPoint mouseDragEnd; bool dragging; QPen dragShapePen; bool dragLine; QAction* actCopyImage; /** \brief this simply paints the stored image to the widget's surface */ virtual void paintEvent(QPaintEvent *event); /** \brief resizes the internal representation (image) of the graphs */ virtual void resizeEvent(QResizeEvent *event); /** \brief event handler for a double click */ virtual void mouseDoubleClickEvent ( QMouseEvent * event ); /** \brief event handler for a mouse move */ virtual void mouseMoveEvent ( QMouseEvent * event ); /** \brief event handler for a mouse button press */ virtual void mousePressEvent ( QMouseEvent * event ); /** \brief event handler for a mouse button is released */ virtual void mouseReleaseEvent(QMouseEvent* event); /** \brief paint the coordinate system */ void plotSystem(QPainter& painter); /** \brief paint the graphs */ void plotGraphs(QPainter& painter); /** \brief recalculate the scaling of the plot */ void calcPlotScaling(); QSize minimumSizeHint() const; /** \brief mutex to lock global widget repaint */ QMutex mutexRepaint; /** \brief mutex to lock data repaint */ QMutex mutexRepaintData; /** \brief mutex to lock system repaint */ QMutex mutexRepaintSystem; public: /** \brief class constructor */ JKQTFastPlotter(QWidget *parent = 0); /** \brief set the properties of the x axis */ void setXRange(double min, double max, bool logarithmic=false); /** \brief set the properties of the y axis */ void setYRange(double min, double max, bool logarithmic=false); /** \brief set the properties of both axes */ void setXYRange(double xmin, double xmax, double ymin, double ymax, bool xlogarithmic=false, bool ylogarithmic=false); /** \brief clear all plots in the graph * * \param remove if \c true the object will also be deleted from memory, not just from the list */ void clearPlots(bool remove=false); /** \brief add a new graph */ void addPlot(JKQTFPPlot* g); /** \brief return the internal number (0..N-1) of the given plot, or -1*/ int getPlotNum(JKQTFPPlot* g); /** \brief remove given graph * * \param id specifies the graph to delete * \param remove if \c true the object will also be deleted from memory, not just from the list */ void deletePlot(int id, bool remove=false); /** \brief remove given graph * * \param g specifies the graph to delete * \param remove if \c true the object will also be deleted from memory, not just from the list */ void deletePlot(JKQTFPPlot* g, bool remove=false); /** \brief return x-pixel coordinate from x coordinate */ inline double x2p(double x) { if (xAxisLog) { if (x<0) return xOffset+log(xMin/10.0)/log(10.0)*xScale; return xOffset+log(x)/log(10.0)*xScale; } else { return xOffset+x*xScale; } }; /** \brief return x coordinate coordinate from x-pixel */ inline double p2x(long x) { if (xAxisLog) { return exp(log(10.0)*((double)x-xOffset)/(xScale)); } else { return ((double)x-xOffset)/(xScale); } }; /** \brief return y-pixel coordinate from y coordinate */ inline double y2p(double y) { if (yAxisLog) { if (y<0) return yOffset-log(yMin/10.0)/log(10.0)*yScale; return yOffset-log(y)/log(10.0)*yScale; } else { return yOffset-y*yScale; } }; /** \brief return y coordinate coordinate from y-pixel */ inline double p2y(long y) { if (yAxisLog) { return exp(log(10.0)*((double)y-yOffset)/(-1.0*yScale)); } else { return ((double)y-yOffset)/(-1.0*yScale); } }; JKQTPGET_SET_MACRO_I(QPen, dragShapePen, update()) JKQTPGET_SET_MACRO_I(bool, dragLine, update()) JKQTPGET_SET_MACRO_I(int, plotBorderLeft, update_plot()) JKQTPGET_SET_MACRO_I(int, plotBorderBottom, update_plot()) JKQTPGET_SET_MACRO_I(int, plotBorderRight, update_plot()) JKQTPGET_SET_MACRO_I(int, plotBorderTop, update_plot()) JKQTPGET_MACRO(int, plotWidth) JKQTPGET_MACRO(int, plotHeight) JKQTPGET_SET_MACRO(bool, doDrawing) JKQTPGET_MACRO(int, internalPlotBorderLeft) JKQTPGET_MACRO(int, internalPlotBorderBottom) JKQTPGET_MACRO(int, internalPlotBorderRight) JKQTPGET_MACRO(int, internalPlotBorderTop) JKQTPGET_MACRO(double, xMin) JKQTPGET_MACRO(double, xMax) JKQTPGET_MACRO(double, yMin) JKQTPGET_MACRO(double, yMax) JKQTPGET_MACRO(bool, xAxisLog) JKQTPGET_MACRO(bool, yAxisLog) JKQTPGET_SET_MACRO_I(QColor, backgroundColor, update_plot()) JKQTPGET_SET_MACRO_I(QColor, plotBackgroundColor, update_plot()) JKQTPGET_SET_MACRO_I(bool, drawGrid, update_plot()) JKQTPGET_SET_MACRO_I(QColor, gridColor, update_plot()) JKQTPGET_SET_MACRO_I(Qt::PenStyle, gridStyle, update_plot()) JKQTPGET_SET_MACRO_I(double, gridWidth, update_plot()) JKQTPGET_SET_MACRO_I(double, labelFontSize, update_plot()) JKQTPGET_SET_MACRO_I(QString, labelFontName, update_plot()) JKQTPGET_SET_MACRO_I(double, tickFontSize, update_plot()) JKQTPGET_SET_MACRO_I(QString, tickFontName, update_plot()) JKQTPGET_SET_MACRO_I(double, tickLength, update_plot()) JKQTPGET_SET_MACRO_I(bool, drawSystemBox, update_plot()) JKQTPGET_SET_MACRO_I(bool, drawZeroAxes, update_plot()) JKQTPGET_SET_MACRO_I(QColor, systemColor, update_plot()) JKQTPGET_SET_MACRO_I(double, systemWidth, update_plot()) JKQTPGET_SET_MACRO_I(double, xZeroTick, update_plot()) JKQTPGET_SET_MACRO_I(double, yZeroTick, update_plot()) JKQTPGET_SET_MACRO_I(double, xTickDistance, update_plot()) JKQTPGET_SET_MACRO_I(double, yTickDistance, update_plot()) JKQTPGET_SET_MACRO_I(QString, xAxisLabel, update_plot()) JKQTPGET_SET_MACRO_I(QString, yAxisLabel, update_plot()) JKQTPGET_SET_MACRO_I(double, aspectRatio, update_plot()) JKQTPGET_SET_MACRO_I(bool, maintainAspectRatio, update_plot()) JKQTPGET_SET_MACRO_I(bool, xAxisLabelVisible, update_plot()) JKQTPGET_SET_MACRO_I(bool, yAxisLabelVisible, update_plot()) JKQTPGET_SET_MACRO_I(JKQTFastPlotter*, synchronizeX, update_plot()) JKQTPGET_SET_MACRO_I(JKQTFastPlotter*, synchronizeY, update_plot()) /** \brief draw the contents onto any QPainter, starting at (0,0), returns the size of the whole plot in \a size, if supplied with the default background color */ void draw(QPainter* painter, QSize* size=NULL); /** \brief draw the contents onto any QPainter, starting at (0,0), returns the size of the whole plot in \a size, if supplied with the supplied\a background color */ void draw(QPainter* painter, QColor background, QSize* size); signals: /** \brief emitted whenever the graph sizes (borders, plotWidth, plotHeight) change*/ void plotterSizesChanged(); /** \brief emitted whenever the graph is replotted */ void replotting(); /** \brief emitted whenever the mouse is clicked inside the plot */ void clicked(double x, double y); /** \brief emitted whenever the mouse is clicked inside the plot */ void clicked(double x, double y, Qt::KeyboardModifiers modifiers); /** \brief emitted whenever the mouse is double-clicked inside the plot */ void doubleClicked(double x, double y); /** \brief emitted whenever the mouse is double-clicked inside the plot */ void doubleClicked(double x, double y, Qt::KeyboardModifiers modifiers); /** \brief emitted whenever the mouse is clicked inside the plot */ void mouseMoved(double x, double y); /** \brief emitted when the mouse has been dragged with the left button clicked */ void mouseDragged(double x_start, double y_start, double x_end, double y_end, Qt::KeyboardModifiers modifiers); /** \brief emitted after the mouse has been dragged with the left button clicked */ void mouseDragFinished(double x_start, double y_start, double x_end, double y_end, Qt::KeyboardModifiers modifiers); public slots: /** \brief copy the current plot image to the clipboard */ void copyImage(); /** \brief replot everything (slowest possible plotting) */ void update_plot(); /** \brief replot everything (slowest possible plotting) and forces a repaint calling QWidget::repaint() */ void update_plot_immediate(); /** \brief replot only the data * * This internally calls QWidget::update(), so no immediate repaint() is forced! If you want an immediate update, * call update_data_immediate() instead! */ void update_data(); /** \brief replot only the data, forces a redraw by calling QWidget::repaint() */ void update_data_immediate(); /** \brief set xMin*/ void set_xMin(double value){ set_doDrawing(false); setXRange(value,xMax,xAxisLog); set_doDrawing(true); } /** \brief set xMax*/ void set_xMax(double value){ set_doDrawing(false); setXRange(xMin,value,xAxisLog); set_doDrawing(true); } /** \brief set yMin*/ void set_yMin(double value){ set_doDrawing(false); setYRange(value,yMax,yAxisLog); set_doDrawing(true); } /** \brief set yMax*/ void set_yMax(double value){ set_doDrawing(false); setYRange(yMin,value,yAxisLog); set_doDrawing(true); } }; /*! \brief base class for all plots that may be plotted by JKQTFastPlotter \ingroup jkqtfastplotter */ class LIB_EXPORT JKQTFPPlot: public QObject { Q_OBJECT protected: /** \brief parent class, i.e. the plotter to plot on */ JKQTFastPlotter* parent; /** \brief indicates whether the plot is visible or not */ bool visible; public: /** \brief class constructor */ JKQTFPPlot(JKQTFastPlotter* parent); /** \brief virtual class destructor */ virtual ~JKQTFPPlot() {}; /** \brief set the parent of the plot */ void setParent(JKQTFastPlotter* parent) { this->parent=parent; QObject::setParent(parent); }; bool isVisible() const { return this->visible; } /** \brief draw the graph */ virtual void drawGraph(QPainter& painter)=0; /** \brief draw the graph */ void paint(QPainter& painter); /** \brief start a replot of the parent widget */ void replot(); public slots: void setVisible(bool visible) { this->visible=visible; replot(); } }; /*! \brief a simple line plot for JKQTFastPlotter \ingroup jkqtfastplotter This class plots data as (x,y) points connected by straight lines. If errors for the y values are provided, also y+/-yerr errorlines are drawn. */ class LIB_EXPORT JKQTFPLinePlot: public JKQTFPPlot { public: /** \brief used to store which datatype is used for the plot data */ enum DataType { JKQTFPLPPointer, JKQTFPLPVector }; protected: /** \brief number of datapoints in the plot */ unsigned int N; /** \brief pointer to x-coordinate data to display */ double* x; /** \brief pointer to y-coordinate data to display */ double* y; /** \brief pointer to yerr-coordinate data to display */ double* yerr; /** \brief pointer to x-coordinate data to display */ QVector* xv; /** \brief pointer to y-coordinate data to display */ QVector* yv; /** \brief pointer to yerr-coordinate data to display */ QVector* yerrv; /** \brief which type of data is used for plotting ? */ DataType datatype; /** \brief color of the graph */ QColor color; /** \brief style of the graph */ Qt::PenStyle style; /** \brief width of the graph (in pixels) */ double width; /** \brief color of the graph */ QColor errorColor; /** \brief style of the graph */ Qt::PenStyle errorStyle; /** \brief width of the graph (in pixels) */ double errorWidth; public: /*! \brief class constructor \param parent parent widget \param N number of datapoints in the plot \param x points to the x values in the plot \param y points to the y values in the plot \param color color of the plot \param style style of the graph \param width width of the plot (in pixels) */ JKQTFPLinePlot(JKQTFastPlotter* parent, unsigned int N, double* x, double* y, QColor color=QColor("red"), Qt::PenStyle style=Qt::SolidLine, double width=1) ; /*! \brief class constructor \param parent parent widget \param x points to the x values in the plot \param y points to the y values in the plot \param color color of the plot \param style style of the graph \param width width of the plot (in pixels) */ JKQTFPLinePlot(JKQTFastPlotter* parent, QVector* x, QVector* y, QColor color=QColor("red"), Qt::PenStyle style=Qt::SolidLine, double width=1) ; /** \brief draw the graph */ virtual void drawGraph(QPainter& painter); inline void set_data(double* x, double* y, unsigned int N) { this->x=x; this->y=y; this->yerr=NULL; this->N=N; datatype=JKQTFPLPPointer; replot(); }; inline void set_data(double* x, double* y, double* yerr, unsigned int N) { this->x=x; this->y=y; this->yerr=yerr; this->N=N; datatype=JKQTFPLPPointer; replot(); }; inline void set_data(QVector* x, QVector* y) { this->x=NULL; this->y=NULL; this->yerr=NULL; this->xv=x; this->yv=y; this->yerrv=NULL; this->N=x->size(); datatype=JKQTFPLPVector; replot(); }; inline void set_data(QVector* x, QVector* y, QVector* yerr) { this->x=NULL; this->y=NULL; this->yerr=NULL; this->xv=x; this->yv=y; this->yerrv=yerr; this->N=x->size(); datatype=JKQTFPLPVector; replot(); }; inline unsigned int get_N() { if (datatype==JKQTFPLPPointer) return N; if (datatype==JKQTFPLPVector) return xv->size(); return N; } JKQTPGET_MACRO(double*, x) JKQTPGET_MACRO(double*, y) JKQTPGET_MACRO(double*, yerr) JKQTPGET_MACRO(QVector*, xv) JKQTPGET_MACRO(QVector*, yv) JKQTPGET_MACRO(QVector*, yerrv) JKQTPGET_MACRO(DataType, datatype) JKQTPGET_SET_MACRO_I(QColor, color, replot()) JKQTPGET_SET_MACRO_I(Qt::PenStyle, style, replot()) JKQTPGET_SET_MACRO_I(double, width, replot()) JKQTPGET_SET_MACRO_I(QColor, errorColor, replot()) JKQTPGET_SET_MACRO_I(Qt::PenStyle, errorStyle, replot()) JKQTPGET_SET_MACRO_I(double, errorWidth, replot()) }; /*! \brief a simple plot that draws a cross for every datapoint \ingroup jkqtfastplotter This class does not support y errors! */ class LIB_EXPORT JKQTFPVCrossPlot: public JKQTFPLinePlot { Q_OBJECT public: /*! \brief class constructor \param parent parent widget \param N number of datapoints in the plot \param x points to the x values in the plot \param y points to the y values in the plot \param color color of the plot \param style style of the graph \param width width of the plot (in pixels) */ JKQTFPVCrossPlot(JKQTFastPlotter* parent, unsigned int N, double* x, double* y, QColor color=QColor("red"), Qt::PenStyle style=Qt::SolidLine, double width=1) ; /*! \brief class constructor \param parent parent widget \param x points to the x values in the plot \param y points to the y values in the plot \param color color of the plot \param style style of the graph \param width width of the plot (in pixels) */ JKQTFPVCrossPlot(JKQTFastPlotter* parent, QVector* x, QVector* y, QColor color=QColor("red"), Qt::PenStyle style=Qt::SolidLine, double width=1) ; /** \brief draw the graph */ virtual void drawGraph(QPainter& painter); JKQTPGET_SET_MACRO_I(double, crossWidth, replot()) protected: /** \brief width of the crosses */ double crossWidth; }; /*! \brief a simple vertical bar plot for JKQTFastPlotter \ingroup jkqtfastplotter This class does not support y errors! */ class LIB_EXPORT JKQTFPVBarPlot: public JKQTFPLinePlot { Q_OBJECT public: /*! \brief class constructor \param parent parent widget \param N number of datapoints in the plot \param x points to the x values in the plot \param y points to the y values in the plot \param color color of the plot \param style style of the graph \param width width of the plot (in pixels) */ JKQTFPVBarPlot(JKQTFastPlotter* parent, unsigned int N, double* x, double* y, QColor color=QColor("red"), Qt::PenStyle style=Qt::SolidLine, double width=1) ; /*! \brief class constructor \param parent parent widget \param x points to the x values in the plot \param y points to the y values in the plot \param color color of the plot \param style style of the graph \param width width of the plot (in pixels) */ JKQTFPVBarPlot(JKQTFastPlotter* parent, QVector* x, QVector* y, QColor color=QColor("red"), Qt::PenStyle style=Qt::SolidLine, double width=1) ; /** \brief draw the graph */ virtual void drawGraph(QPainter& painter); }; /*! \brief plot a range of x values \ingroup jkqtfastplotter */ class LIB_EXPORT JKQTFPXRangePlot: public JKQTFPPlot { Q_OBJECT protected: /** \brief start of x range */ double xmin; /** \brief end of x range */ double xmax; double centerline; bool showCenterline; /** \brief color of the graph */ QColor color; /** \brief style of the graph */ Qt::PenStyle style; /** \brief width of the graph (in pixels) */ double width; /** \brief fill color of the graph */ QColor fillColor; /** \brief fill style of the graph */ Qt::BrushStyle fillStyle; public: /*! \brief class constructor \param parent parent widget \param N number of datapoints in the plot \param x points to the x values in the plot \param y points to the y values in the plot \param color color of the plot \param style style of the graph \param width width of the plot (in pixels) */ JKQTFPXRangePlot(JKQTFastPlotter* parent, double xmin, double xmax, QColor color=QColor("red"), Qt::PenStyle style=Qt::SolidLine, double width=1, Qt::BrushStyle fillStyle=Qt::NoBrush) ; /** \brief draw the graph */ virtual void drawGraph(QPainter& painter); JKQTPGET_SET_MACRO_I(QColor, color, replot()) JKQTPGET_SET_MACRO_I(QColor, fillColor, replot()) JKQTPGET_SET_MACRO_I(Qt::BrushStyle, fillStyle, replot()) JKQTPGET_SET_MACRO_I(Qt::PenStyle, style, replot()) JKQTPGET_SET_MACRO_I(double, width, replot()) JKQTPGET_MACRO(double, xmin) JKQTPGET_MACRO(double, xmax) JKQTPGET_MACRO(double, centerline) JKQTPGET_SET_MACRO_I(bool, showCenterline, replot()) public slots: void set_centerline(int centerline) { if (this->centerline!=centerline) { this->centerline=centerline; replot(); } } void set_xmin(double xmin) { if (this->xmin!=xmin) { this->xmin=xmin; replot(); } } void set_xmax(double xmax) { if (this->xmax!=xmax) { this->xmax=xmax; replot(); } } void set_xmin(int xmin) { if (this->xmin!=xmin) { this->xmin=xmin; replot(); } } void set_xmax(int xmax) { if (this->xmax!=xmax) { this->xmax=xmax; replot(); } } }; /*! \brief plot a range of x values \ingroup jkqtfastplotter */ class LIB_EXPORT JKQTFPYRangePlot: public JKQTFPPlot { Q_OBJECT protected: /** \brief start of x range */ double ymin; /** \brief end of x range */ double ymax; double centerline; bool showCenterline; /** \brief color of the graph */ QColor color; /** \brief style of the graph */ Qt::PenStyle style; /** \brief width of the graph (in pixels) */ double width; /** \brief fill color of the graph */ QColor fillColor; /** \brief fill style of the graph */ Qt::BrushStyle fillStyle; public: /*! \brief class constructor \param parent parent widget \param N number of datapoints in the plot \param x points to the x values in the plot \param y points to the y values in the plot \param color color of the plot \param style style of the graph \param width width of the plot (in pixels) */ JKQTFPYRangePlot(JKQTFastPlotter* parent, double ymin, double ymax, QColor color=QColor("red"), Qt::PenStyle style=Qt::SolidLine, double width=1, Qt::BrushStyle fillStyle=Qt::NoBrush) ; /** \brief draw the graph */ virtual void drawGraph(QPainter& painter); JKQTPGET_SET_MACRO_I(QColor, color, replot()) JKQTPGET_SET_MACRO_I(QColor, fillColor, replot()) JKQTPGET_SET_MACRO_I(Qt::BrushStyle, fillStyle, replot()) JKQTPGET_SET_MACRO_I(Qt::PenStyle, style, replot()) JKQTPGET_SET_MACRO_I(double, width, replot()) JKQTPGET_MACRO(double, ymin) JKQTPGET_MACRO(double, ymax) JKQTPGET_MACRO(double, centerline) JKQTPGET_SET_MACRO_I(bool, showCenterline, replot()) public slots: void set_centerline(int centerline) { if (this->centerline!=centerline) { this->centerline=centerline; replot(); } } void set_ymin(double xmin) { if (this->ymin!=xmin) { this->ymin=xmin; replot(); } } void set_ymax(double xmax) { if (this->ymax!=xmax) { this->ymax=xmax; replot(); } } void set_ymin(int xmin) { if (this->ymin!=xmin) { this->ymin=xmin; replot(); } } void set_ymax(int xmax) { if (this->ymax!=xmax) { this->ymax=xmax; replot(); } } }; /*! \brief a plot of a QImage \ingroup jkqtfastplotter */ class LIB_EXPORT JKQTFPQImagePlot: public JKQTFPPlot { Q_OBJECT protected: /** \brief image to plot */ QImage* image; /** \brief minimum x value of the image */ double xmin; /** \brief maximum x value of the image */ double xmax; /** \brief minimum x value of the image */ double ymin; /** \brief maximum x value of the image */ double ymax; public: /*! \brief class constructor */ JKQTFPQImagePlot(JKQTFastPlotter* parent, QImage* image, double xmin, double xmax, double ymin, double ymax) ; JKQTFPQImagePlot(JKQTFastPlotter* parent, QImage* image); /** \brief draw the graph */ virtual void drawGraph(QPainter& painter); JKQTPGET_SET_MACRO_I(QImage*, image, replot()) JKQTPGET_SET_MACRO_I(double, xmin, replot()) JKQTPGET_SET_MACRO_I(double, xmax, replot()) JKQTPGET_SET_MACRO_I(double, ymin, replot()) JKQTPGET_SET_MACRO_I(double, ymax, replot()) }; /*! \brief An enum for selecting the palette for coloring \ingroup jkqtfastplotter \details Here, the color palettes are illustrated (left is the color for the minimum and right for the maximum). */ enum JKQTFPColorPalette { JKQTFP_RED=0, /*!< \image html RED.png */ JKQTFP_INVERTEDRED=1, /*!< \image html RED.png */ JKQTFP_GREEN=2, /*!< \image html GREEN.png */ JKQTFP_INVERTEDGREEN=3, /*!< \image html GREEN.png */ JKQTFP_BLUE=4, /*!< \image html BLUE.png */ JKQTFP_INVERTEDBLUE=5, /*!< \image html BLUE.png */ JKQTFP_GRAY=6, /*!< \image html GRAY.png */ JKQTFP_INVERTEDGRAY=7, /*!< \image html GRAY.png */ JKQTFP_MATLAB=8, /*!< \image html MATLAB.png */ JKQTFP_RYGB=9, /*!< \image html RYGB.png */ JKQTFP_HSV=10, /*!< \image html HSV.png */ JKQTFP_INVERTED_HSV=11, /*!< \image html INVERTED_HSV.png */ JKQTFP_RAINBOW=12, /*!< \image html RAINBOW.png */ JKQTFP_HOT=13, /*!< \image html HOT.png */ JKQTFP_OCEAN=14, /*!< \image html OCEAN.png */ JKQTFP_TRAFFICLIGHT=15, /*!< \image html TRAFFICLIGHT.png */ JKQTFP_BLUEMAGENTAYELLOW=16, /*!< \image html BLUEMAGENTAYELLOW.png */ JKQTFP_BLUEYELLOW=17, /*!< \image html BLUEYELLOW.png */ JKQTFP_CYAN=18 /*!< \image html CYAN.png */ }; /*!datatype for an image plotpalette for coloring \ingroup jkqtfastplotter \details Here, the color palettes are illustrated (left is the color for the minimum and right for the maximum). */ enum JKQTFPImageFormat { JKQTFP_uint8=0, /*!< \image 8 bit unsigned int */ JKQTFP_uint16=1, /*!< \image 16 bit unsigned int */ JKQTFP_uint32=2, /*!< \image 32 bit unsigned int */ JKQTFP_float=3, /*!< \image float */ JKQTFP_double=4, /*!< \image double */ JKQTFP_int64=5 /*!< \image 64 bit signed int */ }; /*! \brief size of the lookup tables used by JKQTFPimagePlot_array2image() \ingroup jkqtfastplotter */ #define JKQTFPimagePlot_LUTSIZE 256 /*! \brief convert a 2D image (as 1D array) into a QImage with given palette (see JKQTFPColorPalette) \ingroup jkqtfastplotter This method uses lookup tables which are saved as static variables to convert the 2D array into an image. The luts are only created once, and stored then, so mor CPU time is saved. The precompiler define JKQTFPimagePlot_LUTSIZE sets the size of the LUTs. Note that if you don't use a specific color palette, the according LUT won't be calculated and stored! */ template inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &img, JKQTFPColorPalette palette, T minColor, T maxColor) { if (!dbl) return; #ifdef DEBUG_TIMING JKQTPHighResTimer timer; double time_sum=0; double time_gt=0; std::cout<<" timing JKQTFPimagePlot_array2image:\n"; timer.start(); #endif //std::cout<<"color range: "< max) max = v; } } else { min = minColor; max = maxColor; } #ifdef DEBUG_TIMING time_gt=timer.get_time(); time_sum+=time_gt; std::cout<<" finding min&max: "<(255.0*v), 0, 0); } } } lut_used=(*plut); } else if (palette == JKQTFP_GREEN) { unsigned int** plut=&lut_green; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); (*plut)[l]=qRgb(0, static_cast(255.0*v), 0); } } } lut_used=(*plut); } else if (palette == JKQTFP_BLUE) { unsigned int** plut=&lut_blue; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); (*plut)[l]=qRgb(0, 0, static_cast(255.0*v)); } } } lut_used=(*plut); } else if (palette == JKQTFP_GRAY) { unsigned int** plut=&lut_gray; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); (*plut)[l]=qRgb(static_cast(255.0*v), static_cast(255.0*v), static_cast(255.0*v)); } } } lut_used=(*plut); } else if (palette == JKQTFP_INVERTEDRED) { unsigned int** plut=&lut_invred; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); (*plut)[l]=qRgb(static_cast(255.0*(1.0-v)), 0, 0); } } } lut_used=(*plut); } else if (palette == JKQTFP_INVERTEDGREEN) { unsigned int** plut=&lut_invgreen; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); (*plut)[l]=qRgb(0, static_cast(255.0*(1.0-v)), 0); } } } lut_used=(*plut); } else if (palette == JKQTFP_INVERTEDBLUE) { unsigned int** plut=&lut_invblue; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); (*plut)[l]=qRgb(0, 0, static_cast(255.0*(1.0-v))); } } } lut_used=(*plut); } else if (palette == JKQTFP_INVERTEDGRAY) { unsigned int** plut=&lut_invgray; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=1.0-(l/(double)(JKQTFPimagePlot_LUTSIZE)); (*plut)[l]=qRgb(static_cast(255.0*v), static_cast(255.0*v), static_cast(255.0*v)); } } } lut_used=(*plut); } else if (palette == JKQTFP_MATLAB) { unsigned int** plut=&lut_matlab; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); double r = 382.5 - 1020.0 * std::abs(v - 0.75); if (r > 255.0) r = 255.0; else if (r < 0.0) r = 0.0; double g = 382.5 - 1020.0 * std::abs(v - 0.5); if (g > 255.0) g = 255.0; else if (g < 0.0) g = 0.0; double b = 382.5 - 1020.0 * std::abs(v - 0.25); if (b > 255.0) b = 255.0; else if (b < 0.0) b = 0.0; (*plut)[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); } } } lut_used=(*plut); } else if (palette == JKQTFP_RYGB) //gnuplot: 30,-13,-23 { unsigned int** plut=&lut_rygb; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); double r = 796.875*v - 199.21875; if (r > 255.0) r = 255.0; else if (r < 0.0) r = 0.0; double g = 255.0 * std::sin(M_PI*v); double b = 255.0 - 765.0 * v; if (b < 0.0) b = 0.0; (*plut)[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); } } } lut_used=(*plut); } else if (palette == JKQTFP_HSV) { unsigned int** plut=&lut_hsv; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); int h = static_cast(floor(6*v)); double f = 6*v-double(h); switch (h) { case 0: (*plut)[l]=qRgb(255, static_cast(255.0*f), 0); break; case 1: (*plut)[l]=qRgb(static_cast(255.0*(1-f)), 255, 0); break; case 2: (*plut)[l]=qRgb(0, 255, static_cast(255.0*f)); break; case 3: (*plut)[l]=qRgb(0, static_cast(255.0*(1-f)), 255); break; case 4: (*plut)[l]=qRgb(static_cast(255.0*f), 0, 255); break; case 5: (*plut)[l]=qRgb(255, 0, static_cast(255.0*(1-f))); break; case 6: (*plut)[l]=qRgb(255, static_cast(255.0*f), 0); break; } } } } lut_used=(*plut); } else if (palette == JKQTFP_INVERTED_HSV) { unsigned int** plut=&lut_invhsv; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); int h = static_cast(floor(6.0-6.0*v)); double f = 6.0-6.0*v-double(h); switch (h) { case 0: (*plut)[l]=qRgb(255, static_cast(255.0*f), 0); break; case 1: (*plut)[l]=qRgb(static_cast(255.0*(1-f)), 255, 0); break; case 2: (*plut)[l]=qRgb(0, 255, static_cast(255.0*f)); break; case 3: (*plut)[l]=qRgb(0, static_cast(255.0*(1-f)), 255); break; case 4: (*plut)[l]=qRgb(static_cast(255.0*f), 0, 255); break; case 5: (*plut)[l]=qRgb(255, 0, static_cast(255.0*(1-f))); break; case 6: (*plut)[l]=qRgb(255, static_cast(255.0*f), 0); break; } } } } lut_used=(*plut); } else if (palette == JKQTFP_RAINBOW) //gnuplot: 33,13,10 { if (lut_rainbow==NULL) { lut_rainbow=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(int)); //std::cout<<"!!! creating rainbow lut\n"; if (lut_rainbow!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); double r = 255.0*std::abs(2.0*v-0.5); if (r > 255.0) r = 255.0; double g = 255.0*sin(M_PI*v); double b = 255.0*cos(0.5*M_PI*v); lut_rainbow[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); } } } lut_used=lut_rainbow; } else if (palette == JKQTFP_HOT) //gnuplot: 21,22,23 { unsigned int** plut=&lut_hot; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); double r = 765.0*v; if (r > 255.0) r = 255.0; double g = 765.0*v-255.0; if (g > 255.0) g = 255.0; else if (g < 0.0) g = 0.0; double b = 765.0*v-510.0; if (b < 0.0) b = 0.0; (*plut)[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); } } } lut_used=(*plut); } else if (palette == JKQTFP_OCEAN) //gnuplot: 23,28,3 { unsigned int** plut=&lut_ocean; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); double r = 765.0*v-510.0; if (r < 0.0) r = 0.0; double g = std::abs(382.5*v-127.5); double b = 255.0*v; (*plut)[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); } } } lut_used=(*plut); } else if (palette == JKQTFP_BLUEMAGENTAYELLOW) //gnuplot: 30,31,32 { unsigned int** plut=&lut_bluemagentayellow; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); double r = (v/0.32-0.78125); if (r < 0.0) r = 0.0; if (r > 1.0) r = 1.0; double g = 2.0*v-0.84; if (g < 0.0) g = 0.0; if (g > 1.0) g = 1.0; double b = 4.0*v; if (b>1 || b<0) b = -2.0*v+1.84; if (b>1 || b<0) b = v/0.08-11.5; if (b>1 || b<0) b=1; if (b < 0.0) b = 0.0; if (b > 1.0) b = 1.0; (*plut)[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); } } } lut_used=(*plut); } else if (palette == JKQTFP_BLUEYELLOW) //gnuplot: 8,9,10 { unsigned int** plut=&lut_blueyellow; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); double r = sqrt(sqrt(v)); if (r < 0.0) r = 0.0; if (r > 1.0) r = 1.0; double g = sin(M_PI/2.0*v); if (g < 0.0) g = 0.0; if (g > 1.0) g = 1.0; double b = cos(M_PI/2.0*v); if (b < 0.0) b = 0.0; if (b > 1.0) b = 1.0; (*plut)[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); } } } lut_used=(*plut); } else if (palette == JKQTFP_CYAN) { unsigned int** plut=&lut_cyan; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); double r = v*0.5; if (r < 0.0) r = 0.0; if (r > 1.0) r = 1.0; double g = v; if (g < 0.0) g = 0.0; if (g > 1.0) g = 1.0; double b = v; if (b < 0.0) b = 0.0; if (b > 1.0) b = 1.0; (*plut)[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); } } } lut_used=(*plut); } else if (palette == JKQTFP_TRAFFICLIGHT) { unsigned int** plut=&lut_trafficlight; if ((*plut)==NULL) { (*plut)=(unsigned int*)malloc((JKQTFPimagePlot_LUTSIZE+2)*sizeof(unsigned int)); if ((*plut)!=NULL) { for (int l=0; l<=JKQTFPimagePlot_LUTSIZE; l++) { double v=l/(double)(JKQTFPimagePlot_LUTSIZE); double r = (v < 0.5) ? 128.0*sin(M_PI*(2.0*v-0.5))+128.0 : 255.0; if (r > 255.0) r = 255.0; double g = (v < 0.5) ? 512.0*v+128.0 : 512.0-512.0*v; if (g > 255.0) g = 255.0; (*plut)[l]=qRgb(static_cast(r), static_cast(g), 0); } } } lut_used=(*plut); } #ifdef DEBUG_TIMING time_gt=timer.get_time(); time_sum+=time_gt; std::cout<<" calculated/found LUT: "< JKQTFPimagePlot_LUTSIZE) ? JKQTFPimagePlot_LUTSIZE : v); line[i]=lut_used[v]; } } } else { // no LUT found: paint a black image! img.fill(0); } } #ifdef DEBUG_TIMING time_gt=timer.get_time(); time_sum+=time_gt; std::cout<<" creating colored image: "<image=image; this->imageFormat=imageFormat; this->width=width; this->height=height; replot(); } public slots: void set_rotation(int rotation) { if (this->rotation!=rotation) { this->rotation=(JKQTFPColorPalette)rotation; replot(); } } void set_palette(int palette) { if (this->palette!=palette) { this->palette=(JKQTFPColorPalette)palette; replot(); } }; void set_palette(JKQTFPColorPalette palette) { if (this->palette!=palette) { this->palette=palette; replot(); } }; void set_colorMin(uint32_t colorMin) { if (this->colorMin!=colorMin) { this-> colorMin= colorMin; replot(); } } void set_colorMax(uint32_t colorMax) { if (this->colorMax!=colorMax) { this->colorMax=colorMax; replot(); } } void set_colorMin(int colorMin) { if (this->colorMin!=colorMin) { this-> colorMin= colorMin; replot(); } } void set_colorMax(int colorMax) { if (this->colorMax!=colorMax) { this->colorMax=colorMax; replot(); } } void set_colorMin(double colorMin) { if (this->colorMin!=colorMin) { this-> colorMin= colorMin; replot(); } } void set_colorMax(double colorMax) { if (this->colorMax!=colorMax) { this->colorMax=colorMax; replot(); } } }; /*! \brief convert a 2D image (as 1D array) into a QImage and puts the image values into one color channel (set by \a channel). \ingroup jkqtfastplotter */ template inline void JKQTFPRGBImageOverlayPlot_array2image(T* dbl, int width, int height, QImage &img, int channel, T minColor, T maxColor) { if (!dbl) return; #ifdef DEBUG_TIMING JKQTPHighResTimer timer; double time_sum=0; double time_gt=0; std::cout<<" timing JKQTFPimagePlot_array2image:\n"; timer.start(); #endif //qDebug()<<"channel = "< max) max = v; } } else { min = minColor; max = maxColor; } #ifdef DEBUG_TIMING time_gt=timer.get_time(); time_sum+=time_gt; std::cout<<" finding min&max: "< 255) ? 255 : v); const register QRgb l=line[i]; line[i]=qRgb(v,qGreen(l),qBlue(l)); //if (i==j) qDebug()< 255) ? 255 : v); const register QRgb l=line[i]; line[i]=qRgb(qRed(l),v,qBlue(l)); //if (i==j) qDebug()< 255) ? 255 : v); const register QRgb l=line[i]; line[i]=qRgb(qRed(l),qGreen(l),v); //if (i==j) qDebug()<rotation!=rotation) { this->rotation=(JKQTFPColorPalette)rotation; replot(); } } inline void set_colorMinRed(uint32_t colorMin) { if (this->colorMinRed!=colorMin) { this-> colorMinRed= colorMin; replot(); } } inline void set_colorMaxRed(uint32_t colorMax) { if (this->colorMaxRed!=colorMax) { this->colorMaxRed=colorMax; replot(); } } inline void set_colorMinRed(int colorMin) { if (this->colorMinRed!=colorMin) { this-> colorMinRed= colorMin; replot(); } } inline void set_colorMaxRed(int colorMax) { if (this->colorMaxRed!=colorMax) { this->colorMaxRed=colorMax; replot(); } } inline void set_colorMinRed(double colorMin) { if (this->colorMinRed!=colorMin) { this-> colorMinRed= colorMin; replot(); } } inline void set_colorMaxRed(double colorMax) { if (this->colorMaxRed!=colorMax) { this->colorMaxRed=colorMax; replot(); } } inline void set_colorMinGreen(uint32_t colorMin) { if (this->colorMinGreen!=colorMin) { this-> colorMinGreen= colorMin; replot(); } } inline void set_colorMaxGreen(uint32_t colorMax) { if (this->colorMaxGreen!=colorMax) { this->colorMaxGreen=colorMax; replot(); } } inline void set_colorMinGreen(int colorMin) { if (this->colorMinGreen!=colorMin) { this-> colorMinGreen= colorMin; replot(); } } inline void set_colorMaxGreen(int colorMax) { if (this->colorMaxGreen!=colorMax) { this->colorMaxGreen=colorMax; replot(); } } inline void set_colorMinGreen(double colorMin) { if (this->colorMinGreen!=colorMin) { this-> colorMinGreen= colorMin; replot(); } } inline void set_colorMaxGreen(double colorMax) { if (this->colorMaxGreen!=colorMax) { this->colorMaxGreen=colorMax; replot(); } } inline void set_colorMinBlue(uint32_t colorMin) { if (this->colorMinBlue!=colorMin) { this-> colorMinBlue= colorMin; replot(); } } inline void set_colorMaxBlue(uint32_t colorMax) { if (this->colorMaxBlue!=colorMax) { this->colorMaxBlue=colorMax; replot(); } } inline void set_colorMinBlue(int colorMin) { if (this->colorMinBlue!=colorMin) { this-> colorMinBlue= colorMin; replot(); } } inline void set_colorMaxBlue(int colorMax) { if (this->colorMaxBlue!=colorMax) { this->colorMaxBlue=colorMax; replot(); } } inline void set_colorMinBlue(double colorMin) { if (this->colorMinBlue!=colorMin) { this-> colorMinBlue= colorMin; replot(); } } inline void set_colorMaxBlue(double colorMax) { if (this->colorMaxBlue!=colorMax) { this->colorMaxBlue=colorMax; replot(); } } }; /*! \brief plots an image overlay, i.e. a boolean image where each \c true pixel is drawn with a given color and the \c false pixels are transparent \ingroup jkqtfastplotter */ class LIB_EXPORT JKQTFPimageOverlayPlot: public JKQTFPPlot { Q_OBJECT public: enum SymbolType { stCircle, stRectangle }; protected: /** \brief image to plot */ bool* image; /** \brief width of image in pixels */ unsigned int width; /** \brief height of image in pixels */ unsigned int height; /** \brief minimum x value of the image */ double xmin; /** \brief maximum x value of the image */ double xmax; /** \brief minimum x value of the image */ double ymin; /** \brief maximum x value of the image */ double ymax; /** \brief color of the overlay pixels */ QColor color; /** \brief linewidth of symbols */ double linewidth; /** \brief rotation of the image when plotting in units of 90 degrees */ int rotation; SymbolType symboltype; bool showAsSymbols; public: /*! \brief class constructor */ JKQTFPimageOverlayPlot(JKQTFastPlotter* parent, bool* image, unsigned int width, unsigned int height, double xmin, double xmax, double ymin, double ymax, QColor color=QColor("red")); JKQTFPimageOverlayPlot(JKQTFastPlotter* parent, bool* image, unsigned int width, unsigned int height, QColor color=QColor("red")); /** \brief draw the graph */ virtual void drawGraph(QPainter& painter); void set_data(bool* image, unsigned int width, unsigned int height) { this->image=image; this->width=width; this->height=height; replot(); } JKQTPGET_MACRO(bool*, image) JKQTPGET_MACRO(int, rotation) JKQTPGET_MACRO(unsigned int, width) JKQTPGET_MACRO(unsigned int, height) JKQTPGET_SET_MACRO_I(double, xmin, replot()) JKQTPGET_SET_MACRO_I(double, xmax, replot()) JKQTPGET_SET_MACRO_I(double, ymin, replot()) JKQTPGET_SET_MACRO_I(double, ymax, replot()) JKQTPGET_SET_MACRO_I(bool, showAsSymbols, replot()) JKQTPGET_MACRO(QColor, color) public slots: inline void set_rotation(int rotation) { if (this->rotation!=rotation) { this->rotation=(JKQTFPColorPalette)rotation; replot(); } } inline void set_color(QColor color) { if (this->color!=color) { this->color=color; replot(); } }; }; /*! \brief plot a horizontal scale bar \ingroup jkqtfastplotter */ class LIB_EXPORT JKQTFPQScaleBarXPlot: public JKQTFPPlot { Q_OBJECT public: enum Position { TopLeft=0, TopRight=1, BottomLeft=2, BottomRight=3 }; protected: /** \brief width of scale bar */ double width; /** \brief line width of scale bar */ double lineWidth; /** \brief color of scale bar */ QColor color; /** \brief scale bar label (use %1 to include value of width) */ QString label; /** \brief font of scale bar */ QFont font; /** \brief scale bar position */ Position position; public: /*! \brief class constructor */ JKQTFPQScaleBarXPlot(JKQTFastPlotter* parent, double width=1, const QString& label=QString("%1"), QColor color=QColor("grey"), double lineWidth=2) ; /** \brief draw the graph */ virtual void drawGraph(QPainter& painter); JKQTPGET_SET_MACRO_I(double, width, replot()) JKQTPGET_SET_MACRO_I(double, lineWidth, replot()) JKQTPGET_SET_MACRO_I(QColor, color, replot()) JKQTPGET_SET_MACRO_I(QString, label, replot()) JKQTPGET_SET_MACRO_I(QFont, font, replot()) JKQTPGET_SET_MACRO_I(Position, position, replot()) public slots: void set_position(int pos) { set_position((Position)pos); } }; /*! \brief plot a horizontal scale bar \ingroup jkqtfastplotter */ class LIB_EXPORT JKQTFPQOverlayLinearGridPlot: public JKQTFPPlot { Q_OBJECT protected: /** \brief distance between grid lines */ double width; /** \brief line width of grid lines */ double lineWidth; /** \brief color of the grid */ QColor color; /** \brief grid line style */ Qt::PenStyle style; public: /*! \brief class constructor */ JKQTFPQOverlayLinearGridPlot(JKQTFastPlotter* parent, double width=1, QColor color=QColor("grey"), double lineWidth=1, Qt::PenStyle style=Qt::DashLine) ; /** \brief draw the graph */ virtual void drawGraph(QPainter& painter); JKQTPGET_SET_MACRO_I(double, width, replot()) JKQTPGET_SET_MACRO_I(double, lineWidth, replot()) JKQTPGET_SET_MACRO_I(QColor, color, replot()) JKQTPGET_SET_MACRO_I(Qt::PenStyle, style, replot()) }; #endif // JKQTFASTPLOTTER_H