You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1356 lines
0 B
1356 lines
0 B
15 years ago
|
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||
|
* Qwt Widget Library
|
||
|
* Copyright (C) 1997 Josef Wilgen
|
||
|
* Copyright (C) 2002 Uwe Rathmann
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the Qwt License, Version 1.0
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#include <qpainter.h>
|
||
|
#include <qpixmap.h>
|
||
|
#include <qbitarray.h>
|
||
|
#include "qwt_global.h"
|
||
|
#include "qwt_legend.h"
|
||
|
#include "qwt_legend_item.h"
|
||
|
#include "qwt_data.h"
|
||
|
#include "qwt_scale_map.h"
|
||
|
#include "qwt_double_rect.h"
|
||
|
#include "qwt_math.h"
|
||
|
#include "qwt_clipper.h"
|
||
|
#include "qwt_painter.h"
|
||
|
#include "qwt_plot.h"
|
||
|
#include "qwt_plot_canvas.h"
|
||
|
#include "qwt_curve_fitter.h"
|
||
|
#include "qwt_symbol.h"
|
||
|
#include "qwt_plot_curve.h"
|
||
|
|
||
|
#define SCALE_PEN 0
|
||
|
|
||
|
#if QT_VERSION < 0x040000
|
||
|
#include <qguardedptr.h>
|
||
|
#else
|
||
|
#include <qpointer.h>
|
||
|
#endif
|
||
|
|
||
|
#if QT_VERSION >= 0x040000
|
||
|
|
||
|
#include <qevent.h>
|
||
|
#include <qpaintengine.h>
|
||
|
|
||
|
class QwtPlotCurvePaintHelper: public QObject
|
||
|
{
|
||
|
public:
|
||
|
QwtPlotCurvePaintHelper(const QwtPlotCurve *curve, int from, int to):
|
||
|
_curve(curve),
|
||
|
_from(from),
|
||
14 years ago
|
_to(to) {
|
||
15 years ago
|
}
|
||
|
|
||
14 years ago
|
virtual bool eventFilter(QObject *, QEvent *event) {
|
||
|
if ( event->type() == QEvent::Paint ) {
|
||
15 years ago
|
_curve->draw(_from, _to);
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
private:
|
||
|
const QwtPlotCurve *_curve;
|
||
|
int _from;
|
||
|
int _to;
|
||
|
};
|
||
|
|
||
|
#endif // QT_VERSION >= 0x040000
|
||
|
|
||
|
// Creating and initializing a QPainter is an
|
||
|
// expensive operation. So we keep an painter
|
||
|
// open for situations, where we paint outside
|
||
|
// of paint events. This improves the performance
|
||
|
// of incremental painting like in the realtime
|
||
|
// example a lot.
|
||
|
// But it is not possible to have more than
|
||
|
// one QPainter open at the same time. So we
|
||
|
// need to close it before regular paint events
|
||
|
// are processed.
|
||
|
|
||
|
class QwtGuardedPainter: public QObject
|
||
|
{
|
||
|
public:
|
||
14 years ago
|
~QwtGuardedPainter() {
|
||
15 years ago
|
end();
|
||
|
}
|
||
|
|
||
14 years ago
|
QPainter *begin(QwtPlotCanvas *canvas) {
|
||
15 years ago
|
_canvas = canvas;
|
||
|
|
||
|
QMap<QwtPlotCanvas *, QPainter *>::iterator it = _map.find(_canvas);
|
||
14 years ago
|
if ( it == _map.end() ) {
|
||
15 years ago
|
QPainter *painter = new QPainter(_canvas);
|
||
|
painter->setClipping(true);
|
||
|
painter->setClipRect(_canvas->contentsRect());
|
||
|
|
||
|
it = _map.insert(_canvas, painter);
|
||
|
_canvas->installEventFilter(this);
|
||
|
}
|
||
|
#if QT_VERSION < 0x040000
|
||
|
return it.data();
|
||
|
#else
|
||
|
return it.value();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
14 years ago
|
void end() {
|
||
|
if ( _canvas ) {
|
||
15 years ago
|
QMap<QwtPlotCanvas *, QPainter *>::iterator it = _map.find(_canvas);
|
||
14 years ago
|
if ( it != _map.end() ) {
|
||
15 years ago
|
_canvas->removeEventFilter(this);
|
||
|
|
||
|
#if QT_VERSION < 0x040000
|
||
|
delete it.data();
|
||
|
#else
|
||
|
delete it.value();
|
||
|
#endif
|
||
|
_map.erase(it);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
14 years ago
|
virtual bool eventFilter(QObject *, QEvent *event) {
|
||
15 years ago
|
if ( event->type() == QEvent::Paint )
|
||
|
end();
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private:
|
||
14 years ago
|
#if QT_VERSION < 0x040000
|
||
15 years ago
|
QGuardedPtr<QwtPlotCanvas> _canvas;
|
||
|
#else
|
||
|
QPointer<QwtPlotCanvas> _canvas;
|
||
|
#endif
|
||
|
static QMap<QwtPlotCanvas *, QPainter *> _map;
|
||
|
};
|
||
|
|
||
|
QMap<QwtPlotCanvas *, QPainter *> QwtGuardedPainter::_map;
|
||
|
|
||
14 years ago
|
static QwtPolygon clipPolygon(QPainter *painter, int attributes,
|
||
|
const QwtPolygon &polygon)
|
||
15 years ago
|
{
|
||
|
bool doClipping = attributes & QwtPlotCurve::ClipPolygons;
|
||
|
QRect clipRect = painter->window();
|
||
|
|
||
14 years ago
|
if ( !doClipping ) {
|
||
15 years ago
|
#if QT_VERSION >= 0x040000
|
||
|
const QPaintEngine *pe = painter->paintEngine();
|
||
|
if ( pe && pe->type() == QPaintEngine::SVG )
|
||
|
#else
|
||
|
if ( painter->device()->devType() == QInternal::Picture )
|
||
|
#endif
|
||
|
{
|
||
|
// The SVG paint engine ignores any clipping,
|
||
|
// so we enable polygon clipping.
|
||
|
|
||
|
doClipping = true;
|
||
|
if ( painter->hasClipping() )
|
||
|
clipRect &= painter->clipRegion().boundingRect();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( doClipping )
|
||
|
return QwtClipper::clipPolygon(clipRect, polygon);
|
||
14 years ago
|
|
||
15 years ago
|
return polygon;
|
||
|
}
|
||
|
|
||
|
static int verifyRange(int size, int &i1, int &i2)
|
||
|
{
|
||
14 years ago
|
if (size < 1)
|
||
15 years ago
|
return 0;
|
||
|
|
||
|
i1 = qwtLim(i1, 0, size-1);
|
||
|
i2 = qwtLim(i2, 0, size-1);
|
||
|
|
||
|
if ( i1 > i2 )
|
||
|
qSwap(i1, i2);
|
||
|
|
||
|
return (i2 - i1 + 1);
|
||
|
}
|
||
|
|
||
|
class QwtPlotCurve::PrivateData
|
||
|
{
|
||
|
public:
|
||
|
class PixelMatrix: private QBitArray
|
||
|
{
|
||
|
public:
|
||
|
PixelMatrix(const QRect& rect):
|
||
|
QBitArray(rect.width() * rect.height()),
|
||
14 years ago
|
_rect(rect) {
|
||
15 years ago
|
fill(false);
|
||
|
}
|
||
|
|
||
14 years ago
|
inline bool testPixel(const QPoint& pos) {
|
||
15 years ago
|
if ( !_rect.contains(pos) )
|
||
|
return false;
|
||
|
|
||
14 years ago
|
const int idx = _rect.width() * (pos.y() - _rect.y()) +
|
||
|
(pos.x() - _rect.x());
|
||
15 years ago
|
|
||
|
const bool marked = testBit(idx);
|
||
|
if ( !marked )
|
||
|
setBit(idx, true);
|
||
|
|
||
|
return !marked;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
QRect _rect;
|
||
|
};
|
||
|
|
||
|
PrivateData():
|
||
|
curveType(Yfx),
|
||
|
style(QwtPlotCurve::Lines),
|
||
|
reference(0.0),
|
||
|
attributes(0),
|
||
14 years ago
|
paintAttributes(0) {
|
||
15 years ago
|
symbol = new QwtSymbol();
|
||
|
pen = QPen(Qt::black);
|
||
|
curveFitter = new QwtSplineCurveFitter;
|
||
|
}
|
||
|
|
||
14 years ago
|
~PrivateData() {
|
||
15 years ago
|
delete symbol;
|
||
|
delete curveFitter;
|
||
|
}
|
||
|
|
||
|
QwtPlotCurve::CurveType curveType;
|
||
|
QwtPlotCurve::CurveStyle style;
|
||
|
double reference;
|
||
|
|
||
|
QwtSymbol *symbol;
|
||
|
QwtCurveFitter *curveFitter;
|
||
|
|
||
|
QPen pen;
|
||
|
QBrush brush;
|
||
|
|
||
|
int attributes;
|
||
|
int paintAttributes;
|
||
|
|
||
|
QwtGuardedPainter guardedPainter;
|
||
|
};
|
||
|
|
||
|
//! Constructor
|
||
|
QwtPlotCurve::QwtPlotCurve():
|
||
|
QwtPlotItem(QwtText())
|
||
|
{
|
||
|
init();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Constructor
|
||
14 years ago
|
\param title title of the curve
|
||
15 years ago
|
*/
|
||
|
QwtPlotCurve::QwtPlotCurve(const QwtText &title):
|
||
|
QwtPlotItem(title)
|
||
|
{
|
||
|
init();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Constructor
|
||
14 years ago
|
\param title title of the curve
|
||
15 years ago
|
*/
|
||
|
QwtPlotCurve::QwtPlotCurve(const QString &title):
|
||
|
QwtPlotItem(QwtText(title))
|
||
|
{
|
||
|
init();
|
||
|
}
|
||
|
|
||
|
//! Destructor
|
||
|
QwtPlotCurve::~QwtPlotCurve()
|
||
|
{
|
||
|
delete d_xy;
|
||
|
delete d_data;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Initialize data members
|
||
|
*/
|
||
|
void QwtPlotCurve::init()
|
||
|
{
|
||
|
setItemAttribute(QwtPlotItem::Legend);
|
||
|
setItemAttribute(QwtPlotItem::AutoScale);
|
||
|
|
||
|
d_data = new PrivateData;
|
||
|
d_xy = new QwtPolygonFData(QwtArray<QwtDoublePoint>());
|
||
|
|
||
|
setZ(20.0);
|
||
|
}
|
||
|
|
||
|
//! \return QwtPlotItem::Rtti_PlotCurve
|
||
|
int QwtPlotCurve::rtti() const
|
||
|
{
|
||
|
return QwtPlotItem::Rtti_PlotCurve;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Specify an attribute how to draw the curve
|
||
|
|
||
|
The attributes can be used to modify the drawing algorithm.
|
||
|
|
||
|
The following attributes are defined:<dl>
|
||
|
<dt>PaintFiltered</dt>
|
||
|
<dd>Tries to reduce the data that has to be painted, by sorting out
|
||
|
duplicates, or paintings outside the visible area. Might have a
|
||
14 years ago
|
notable impact on curves with many close points.
|
||
15 years ago
|
Only a couple of very basic filtering algos are implemented.</dd>
|
||
|
<dt>ClipPolygons</dt>
|
||
|
<dd>Clip polygons before painting them. In situations, where points
|
||
|
are far outside the visible area this might be a great improvement
|
||
|
for the painting performance ( especially on Windows ).
|
||
|
</dl>
|
||
|
|
||
|
The default is, that no paint attributes are enabled.
|
||
|
|
||
|
\param attribute Paint attribute
|
||
|
\param on On/Off
|
||
|
/sa testPaintAttribute()
|
||
|
*/
|
||
|
void QwtPlotCurve::setPaintAttribute(PaintAttribute attribute, bool on)
|
||
|
{
|
||
|
if ( on )
|
||
|
d_data->paintAttributes |= attribute;
|
||
|
else
|
||
|
d_data->paintAttributes &= ~attribute;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Return the current paint attributes
|
||
|
\sa setPaintAttribute
|
||
|
*/
|
||
|
bool QwtPlotCurve::testPaintAttribute(PaintAttribute attribute) const
|
||
|
{
|
||
|
return (d_data->paintAttributes & attribute);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Set the curve's drawing style
|
||
|
|
||
|
Valid styles are:
|
||
|
<dl>
|
||
|
<dt>NoCurve</dt>
|
||
|
<dd>Don't draw a curve. Note: This doesn't affect the symbol. </dd>
|
||
|
<dt>Lines</dt>
|
||
|
<dd>Connect the points with straight lines. The lines might
|
||
|
be interpolated depending on the 'Fitted' option. Curve
|
||
|
fitting can be configured using setCurveFitter.</dd>
|
||
|
<dt>Sticks</dt>
|
||
|
<dd>Draw vertical sticks from a baseline which is defined by setBaseline().</dd>
|
||
|
<dt>Steps</dt>
|
||
|
<dd>Connect the points with a step function. The step function
|
||
|
is drawn from the left to the right or vice versa,
|
||
|
depending on the 'Inverted' option.</dd>
|
||
|
<dt>Dots</dt>
|
||
|
<dd>Draw dots at the locations of the data points. Note:
|
||
|
This is different from a dotted line (see setPen()).</dd>
|
||
|
<dt>UserCurve ...</dt>
|
||
|
<dd>Styles >= UserCurve are reserved for derived
|
||
|
classes of QwtPlotCurve that overload drawCurve() with
|
||
|
additional application specific curve types.</dd>
|
||
|
</dl>
|
||
|
\sa style()
|
||
|
*/
|
||
|
void QwtPlotCurve::setStyle(CurveStyle style)
|
||
|
{
|
||
14 years ago
|
if ( style != d_data->style ) {
|
||
15 years ago
|
d_data->style = style;
|
||
|
itemChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Return the current style
|
||
|
\sa setStyle()
|
||
|
*/
|
||
14 years ago
|
QwtPlotCurve::CurveStyle QwtPlotCurve::style() const
|
||
|
{
|
||
|
return d_data->style;
|
||
15 years ago
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Assign a symbol
|
||
|
\param symbol Symbol
|
||
|
\sa symbol()
|
||
|
*/
|
||
|
void QwtPlotCurve::setSymbol(const QwtSymbol &symbol )
|
||
|
{
|
||
|
delete d_data->symbol;
|
||
|
d_data->symbol = symbol.clone();
|
||
|
itemChanged();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Return the current symbol
|
||
|
\sa setSymbol()
|
||
|
*/
|
||
14 years ago
|
const QwtSymbol &QwtPlotCurve::symbol() const
|
||
|
{
|
||
|
return *d_data->symbol;
|
||
15 years ago
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Assign a pen
|
||
|
\param pen New pen
|
||
|
\sa pen(), brush()
|
||
|
*/
|
||
|
void QwtPlotCurve::setPen(const QPen &pen)
|
||
|
{
|
||
14 years ago
|
if ( pen != d_data->pen ) {
|
||
15 years ago
|
d_data->pen = pen;
|
||
|
itemChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Return the pen used to draw the lines
|
||
|
\sa setPen(), brush()
|
||
|
*/
|
||
14 years ago
|
const QPen& QwtPlotCurve::pen() const
|
||
|
{
|
||
|
return d_data->pen;
|
||
15 years ago
|
}
|
||
|
|
||
|
/*!
|
||
14 years ago
|
\brief Assign a brush.
|
||
|
In case of brush.style() != QBrush::NoBrush
|
||
15 years ago
|
and style() != QwtPlotCurve::Sticks
|
||
|
the area between the curve and the baseline will be filled.
|
||
|
In case !brush.color().isValid() the area will be filled by
|
||
|
pen.color(). The fill algorithm simply connects the first and the
|
||
14 years ago
|
last curve point to the baseline. So the curve data has to be sorted
|
||
|
(ascending or descending).
|
||
15 years ago
|
\param brush New brush
|
||
|
\sa brush(), setBaseline(), baseline()
|
||
|
*/
|
||
|
void QwtPlotCurve::setBrush(const QBrush &brush)
|
||
|
{
|
||
14 years ago
|
if ( brush != d_data->brush ) {
|
||
15 years ago
|
d_data->brush = brush;
|
||
|
itemChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Return the brush used to fill the area between lines and the baseline
|
||
|
\sa setBrush(), setBaseline(), baseline()
|
||
|
*/
|
||
14 years ago
|
const QBrush& QwtPlotCurve::brush() const
|
||
15 years ago
|
{
|
||
|
return d_data->brush;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
Set data by copying x- and y-values from specified memory blocks.
|
||
|
Contrary to setCurveRawData(), this function makes a 'deep copy' of
|
||
|
the data.
|
||
|
|
||
|
\param xData pointer to x values
|
||
|
\param yData pointer to y values
|
||
|
\param size size of xData and yData
|
||
|
|
||
|
\sa QwtCPointerData
|
||
|
*/
|
||
|
void QwtPlotCurve::setData(const double *xData, const double *yData, int size)
|
||
|
{
|
||
|
delete d_xy;
|
||
|
d_xy = new QwtArrayData(xData, yData, size);
|
||
|
itemChanged();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Initialize data with x- and y-arrays (explicitly shared)
|
||
|
|
||
|
\param xData x data
|
||
|
\param yData y data
|
||
|
|
||
|
\sa QwtArrayData
|
||
|
*/
|
||
14 years ago
|
void QwtPlotCurve::setData(const QwtArray<double> &xData,
|
||
|
const QwtArray<double> &yData)
|
||
15 years ago
|
{
|
||
|
delete d_xy;
|
||
|
d_xy = new QwtArrayData(xData, yData);
|
||
|
itemChanged();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Initialize data with an array of points (explicitly shared).
|
||
|
|
||
|
\param data Data
|
||
|
\sa QwtPolygonFData
|
||
|
*/
|
||
|
#if QT_VERSION < 0x040000
|
||
|
void QwtPlotCurve::setData(const QwtArray<QwtDoublePoint> &data)
|
||
|
#else
|
||
|
void QwtPlotCurve::setData(const QPolygonF &data)
|
||
|
#endif
|
||
|
{
|
||
|
delete d_xy;
|
||
|
d_xy = new QwtPolygonFData(data);
|
||
|
itemChanged();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Initialize data with a pointer to QwtData.
|
||
|
|
||
|
\param data Data
|
||
|
\sa QwtData::copy()
|
||
|
*/
|
||
|
void QwtPlotCurve::setData(const QwtData &data)
|
||
|
{
|
||
|
delete d_xy;
|
||
|
d_xy = data.copy();
|
||
|
itemChanged();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Initialize the data by pointing to memory blocks which are not managed
|
||
|
by QwtPlotCurve.
|
||
|
|
||
|
setRawData is provided for efficiency. It is important to keep the pointers
|
||
|
during the lifetime of the underlying QwtCPointerData class.
|
||
|
|
||
|
\param xData pointer to x data
|
||
|
\param yData pointer to y data
|
||
|
\param size size of x and y
|
||
|
|
||
|
\sa QwtCPointerData::setData.
|
||
|
*/
|
||
|
void QwtPlotCurve::setRawData(const double *xData, const double *yData, int size)
|
||
|
{
|
||
|
delete d_xy;
|
||
|
d_xy = new QwtCPointerData(xData, yData, size);
|
||
|
itemChanged();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Returns the bounding rectangle of the curve data. If there is
|
||
|
no bounding rect, like for empty data the rectangle is invalid.
|
||
|
\sa QwtData::boundingRect(), QwtDoubleRect::isValid()
|
||
|
*/
|
||
|
|
||
|
QwtDoubleRect QwtPlotCurve::boundingRect() const
|
||
|
{
|
||
|
if ( d_xy == NULL )
|
||
|
return QwtDoubleRect(1.0, 1.0, -2.0, -2.0); // invalid
|
||
|
|
||
|
return d_xy->boundingRect();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Draw the complete curve
|
||
|
|
||
|
\param painter Painter
|
||
|
\param xMap Maps x-values into pixel coordinates.
|
||
|
\param yMap Maps y-values into pixel coordinates.
|
||
|
|
||
|
\sa drawCurve(), drawSymbols()
|
||
|
*/
|
||
|
void QwtPlotCurve::draw(QPainter *painter,
|
||
14 years ago
|
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||
|
const QRect &) const
|
||
15 years ago
|
{
|
||
|
draw(painter, xMap, yMap, 0, -1);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Draw a set of points of a curve.
|
||
|
|
||
|
When observing an measurement while it is running, new points have to be
|
||
|
added to an existing curve. drawCurve can be used to display them avoiding
|
||
|
a complete redraw of the canvas.
|
||
|
|
||
|
Setting plot()->canvas()->setAttribute(Qt::WA_PaintOutsidePaintEvent, true);
|
||
|
will result in faster painting, if the paint engine of the canvas widget
|
||
14 years ago
|
supports this feature.
|
||
15 years ago
|
|
||
|
\param from Index of the first point to be painted
|
||
|
\param to Index of the last point to be painted. If to < 0 the
|
||
|
curve will be painted to its last point.
|
||
|
|
||
|
\sa drawCurve(), drawSymbols()
|
||
|
*/
|
||
|
void QwtPlotCurve::draw(int from, int to) const
|
||
|
{
|
||
|
if ( !plot() )
|
||
|
return;
|
||
|
|
||
|
QwtPlotCanvas *canvas = plot()->canvas();
|
||
|
|
||
|
#if QT_VERSION >= 0x040000
|
||
|
#if 0
|
||
14 years ago
|
if ( canvas->paintEngine()->type() == QPaintEngine::OpenGL ) {
|
||
15 years ago
|
/*
|
||
|
OpenGL alway repaint the complete widget.
|
||
|
So for this operation OpenGL is one of the slowest
|
||
|
environments.
|
||
|
*/
|
||
|
canvas->repaint();
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if ( !canvas->testAttribute(Qt::WA_WState_InPaintEvent) &&
|
||
14 years ago
|
!canvas->testAttribute(Qt::WA_PaintOutsidePaintEvent) ) {
|
||
15 years ago
|
/*
|
||
|
We save curve and range in helper and call repaint.
|
||
|
The helper filters the Paint event, to repeat
|
||
|
the QwtPlotCurve::draw, but now from inside the paint
|
||
|
event.
|
||
|
*/
|
||
|
|
||
|
QwtPlotCurvePaintHelper helper(this, from, to);
|
||
|
canvas->installEventFilter(&helper);
|
||
|
|
||
|
const bool noSystemBackground =
|
||
|
canvas->testAttribute(Qt::WA_NoSystemBackground);
|
||
|
canvas->setAttribute(Qt::WA_NoSystemBackground, true);
|
||
|
canvas->repaint();
|
||
|
canvas->setAttribute(Qt::WA_NoSystemBackground, noSystemBackground);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
const QwtScaleMap xMap = plot()->canvasMap(xAxis());
|
||
|
const QwtScaleMap yMap = plot()->canvasMap(yAxis());
|
||
|
|
||
|
if ( canvas->testPaintAttribute(QwtPlotCanvas::PaintCached) &&
|
||
14 years ago
|
canvas->paintCache() && !canvas->paintCache()->isNull() ) {
|
||
15 years ago
|
QPainter cachePainter((QPixmap *)canvas->paintCache());
|
||
|
cachePainter.translate(-canvas->contentsRect().x(),
|
||
14 years ago
|
-canvas->contentsRect().y());
|
||
15 years ago
|
|
||
|
draw(&cachePainter, xMap, yMap, from, to);
|
||
|
}
|
||
|
|
||
|
#if QT_VERSION >= 0x040000
|
||
14 years ago
|
if ( canvas->testAttribute(Qt::WA_WState_InPaintEvent) ) {
|
||
15 years ago
|
QPainter painter(canvas);
|
||
|
|
||
|
painter.setClipping(true);
|
||
|
painter.setClipRect(canvas->contentsRect());
|
||
|
|
||
|
draw(&painter, xMap, yMap, from, to);
|
||
14 years ago
|
} else
|
||
15 years ago
|
#endif
|
||
|
{
|
||
|
QPainter *painter = d_data->guardedPainter.begin(canvas);
|
||
|
draw(painter, xMap, yMap, from, to);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Draw an interval of the curve
|
||
|
\param painter Painter
|
||
|
\param xMap maps x-values into pixel coordinates.
|
||
|
\param yMap maps y-values into pixel coordinates.
|
||
|
\param from index of the first point to be painted
|
||
14 years ago
|
\param to index of the last point to be painted. If to < 0 the
|
||
15 years ago
|
curve will be painted to its last point.
|
||
|
|
||
|
\sa drawCurve(), drawSymbols(),
|
||
|
*/
|
||
|
void QwtPlotCurve::draw(QPainter *painter,
|
||
14 years ago
|
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||
|
int from, int to) const
|
||
15 years ago
|
{
|
||
|
if ( !painter || dataSize() <= 0 )
|
||
|
return;
|
||
|
|
||
|
if (to < 0)
|
||
|
to = dataSize() - 1;
|
||
|
|
||
14 years ago
|
if ( verifyRange(dataSize(), from, to) > 0 ) {
|
||
15 years ago
|
painter->save();
|
||
14 years ago
|
|
||
15 years ago
|
QPen pen = d_data->pen;
|
||
|
|
||
|
#if SCALE_PEN
|
||
14 years ago
|
if ( pen.width() > 0 ) {
|
||
15 years ago
|
const QwtMetricsMap &metricsMap = QwtPainter::metricsMap();
|
||
|
pen.setWidth(metricsMap.screenToLayoutX(pen.width()));
|
||
|
}
|
||
|
#endif
|
||
14 years ago
|
|
||
15 years ago
|
painter->setPen(pen);
|
||
|
|
||
|
/*
|
||
14 years ago
|
Qt 4.0.0 is slow when drawing lines, but it's even
|
||
15 years ago
|
slower when the painter has a brush. So we don't
|
||
|
set the brush before we really need it.
|
||
|
*/
|
||
|
|
||
|
drawCurve(painter, d_data->style, xMap, yMap, from, to);
|
||
|
painter->restore();
|
||
|
|
||
14 years ago
|
if (d_data->symbol->style() != QwtSymbol::NoSymbol) {
|
||
15 years ago
|
painter->save();
|
||
|
drawSymbols(painter, *d_data->symbol, xMap, yMap, from, to);
|
||
|
painter->restore();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
14 years ago
|
\brief Draw the line part (without symbols) of a curve interval.
|
||
15 years ago
|
\param painter Painter
|
||
|
\param style curve style, see QwtPlotCurve::CurveStyle
|
||
|
\param xMap x map
|
||
|
\param yMap y map
|
||
|
\param from index of the first point to be painted
|
||
|
\param to index of the last point to be painted
|
||
|
\sa draw(), drawDots(), drawLines(), drawSteps(), drawSticks()
|
||
|
*/
|
||
|
|
||
|
void QwtPlotCurve::drawCurve(QPainter *painter, int style,
|
||
14 years ago
|
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||
|
int from, int to) const
|
||
15 years ago
|
{
|
||
14 years ago
|
switch (style) {
|
||
|
case Lines:
|
||
|
if ( testCurveAttribute(Fitted) ) {
|
||
|
// we always need the complete
|
||
|
// curve for fitting
|
||
|
from = 0;
|
||
|
to = dataSize() - 1;
|
||
|
}
|
||
|
drawLines(painter, xMap, yMap, from, to);
|
||
|
break;
|
||
|
case Sticks:
|
||
|
drawSticks(painter, xMap, yMap, from, to);
|
||
|
break;
|
||
|
case Steps:
|
||
|
drawSteps(painter, xMap, yMap, from, to);
|
||
|
break;
|
||
|
case Dots:
|
||
|
drawDots(painter, xMap, yMap, from, to);
|
||
|
break;
|
||
|
case NoCurve:
|
||
|
default:
|
||
|
break;
|
||
15 years ago
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Draw lines
|
||
|
|
||
|
If the CurveAttribute Fitted is enabled a QwtCurveFitter tries
|
||
|
to interpolate/smooth the curve, before it is painted.
|
||
|
|
||
|
\param painter Painter
|
||
|
\param xMap x map
|
||
|
\param yMap y map
|
||
|
\param from index of the first point to be painted
|
||
|
\param to index of the last point to be painted
|
||
|
|
||
14 years ago
|
\sa setCurveAttribute(), setCurveFitter(), draw(),
|
||
15 years ago
|
drawLines(), drawDots(), drawSteps(), drawSticks()
|
||
|
*/
|
||
|
void QwtPlotCurve::drawLines(QPainter *painter,
|
||
14 years ago
|
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||
|
int from, int to) const
|
||
15 years ago
|
{
|
||
|
int size = to - from + 1;
|
||
|
if ( size <= 0 )
|
||
|
return;
|
||
|
|
||
|
QwtPolygon polyline;
|
||
14 years ago
|
if ( ( d_data->attributes & Fitted ) && d_data->curveFitter ) {
|
||
15 years ago
|
// Transform x and y values to window coordinates
|
||
|
// to avoid a distinction between linear and
|
||
|
// logarithmic scales.
|
||
|
|
||
|
#if QT_VERSION < 0x040000
|
||
|
QwtArray<QwtDoublePoint> points(size);
|
||
|
#else
|
||
|
QPolygonF points(size);
|
||
|
#endif
|
||
14 years ago
|
for (int i = from; i <= to; i++) {
|
||
15 years ago
|
QwtDoublePoint &p = points[i];
|
||
|
p.setX( xMap.xTransform(x(i)) );
|
||
|
p.setY( yMap.xTransform(y(i)) );
|
||
|
}
|
||
|
|
||
|
points = d_data->curveFitter->fitCurve(points);
|
||
|
size = points.size();
|
||
|
|
||
|
if ( size == 0 )
|
||
|
return;
|
||
|
|
||
|
// Round QwtDoublePoints to QPoints
|
||
|
// When Qwt support for Qt3 has been dropped (Qwt 6.x)
|
||
|
// we will use a doubles for painting and the following
|
||
|
// step will be obsolete.
|
||
|
|
||
|
polyline.resize(size);
|
||
|
|
||
|
const QwtDoublePoint *p = points.data();
|
||
|
QPoint *pl = polyline.data();
|
||
14 years ago
|
if ( d_data->paintAttributes & PaintFiltered ) {
|
||
15 years ago
|
|
||
|
QPoint pp(qRound(p[0].x()), qRound(p[0].y()));
|
||
|
pl[0] = pp;
|
||
|
|
||
|
int count = 1;
|
||
14 years ago
|
for (int i = 1; i < size; i++) {
|
||
15 years ago
|
const QPoint pi(qRound(p[i].x()), qRound(p[i].y()));
|
||
14 years ago
|
if ( pi != pp ) {
|
||
15 years ago
|
pl[count++] = pi;
|
||
|
pp = pi;
|
||
|
}
|
||
|
}
|
||
|
if ( count != size )
|
||
|
polyline.resize(count);
|
||
14 years ago
|
} else {
|
||
|
for ( int i = 0; i < size; i++ ) {
|
||
15 years ago
|
pl[i].setX( qRound(p[i].x()) );
|
||
|
pl[i].setY( qRound(p[i].y()) );
|
||
|
}
|
||
|
}
|
||
14 years ago
|
} else {
|
||
15 years ago
|
polyline.resize(size);
|
||
|
|
||
14 years ago
|
if ( d_data->paintAttributes & PaintFiltered ) {
|
||
15 years ago
|
QPoint pp( xMap.transform(x(from)), yMap.transform(y(from)) );
|
||
|
polyline.setPoint(0, pp);
|
||
|
|
||
|
int count = 1;
|
||
14 years ago
|
for (int i = from + 1; i <= to; i++) {
|
||
15 years ago
|
const QPoint pi(xMap.transform(x(i)), yMap.transform(y(i)));
|
||
14 years ago
|
if ( pi != pp ) {
|
||
15 years ago
|
polyline.setPoint(count, pi);
|
||
|
count++;
|
||
|
|
||
|
pp = pi;
|
||
|
}
|
||
|
}
|
||
|
if ( count != size )
|
||
|
polyline.resize(count);
|
||
14 years ago
|
} else {
|
||
|
for (int i = from; i <= to; i++) {
|
||
15 years ago
|
int xi = xMap.transform(x(i));
|
||
|
int yi = yMap.transform(y(i));
|
||
|
|
||
|
polyline.setPoint(i - from, xi, yi);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
polyline = ::clipPolygon(painter, d_data->paintAttributes, polyline);
|
||
|
|
||
|
QwtPainter::drawPolyline(painter, polyline);
|
||
|
|
||
|
if ( d_data->brush.style() != Qt::NoBrush )
|
||
|
fillCurve(painter, xMap, yMap, polyline);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Draw sticks
|
||
|
|
||
|
\param painter Painter
|
||
|
\param xMap x map
|
||
|
\param yMap y map
|
||
|
\param from index of the first point to be painted
|
||
|
\param to index of the last point to be painted
|
||
|
|
||
|
\sa draw(), drawCurve(), drawDots(), drawLines(), drawSteps()
|
||
|
*/
|
||
|
void QwtPlotCurve::drawSticks(QPainter *painter,
|
||
14 years ago
|
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||
|
int from, int to) const
|
||
15 years ago
|
{
|
||
|
int x0 = xMap.transform(d_data->reference);
|
||
|
int y0 = yMap.transform(d_data->reference);
|
||
|
|
||
14 years ago
|
for (int i = from; i <= to; i++) {
|
||
15 years ago
|
const int xi = xMap.transform(x(i));
|
||
|
const int yi = yMap.transform(y(i));
|
||
|
|
||
|
if (d_data->curveType == Xfy)
|
||
|
QwtPainter::drawLine(painter, x0, yi, xi, yi);
|
||
|
else
|
||
|
QwtPainter::drawLine(painter, xi, y0, xi, yi);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Draw dots
|
||
|
|
||
|
\param painter Painter
|
||
|
\param xMap x map
|
||
|
\param yMap y map
|
||
|
\param from index of the first point to be painted
|
||
|
\param to index of the last point to be painted
|
||
|
|
||
|
\sa draw(), drawCurve(), drawSticks(), drawLines(), drawSteps()
|
||
|
*/
|
||
|
void QwtPlotCurve::drawDots(QPainter *painter,
|
||
14 years ago
|
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||
|
int from, int to) const
|
||
15 years ago
|
{
|
||
|
const QRect window = painter->window();
|
||
|
if ( window.isEmpty() )
|
||
|
return;
|
||
|
|
||
|
const bool doFill = d_data->brush.style() != Qt::NoBrush;
|
||
|
|
||
|
QwtPolygon polyline;
|
||
|
if ( doFill )
|
||
|
polyline.resize(to - from + 1);
|
||
|
|
||
14 years ago
|
if ( to > from && d_data->paintAttributes & PaintFiltered ) {
|
||
|
if ( doFill ) {
|
||
15 years ago
|
QPoint pp( xMap.transform(x(from)), yMap.transform(y(from)) );
|
||
|
|
||
|
QwtPainter::drawPoint(painter, pp.x(), pp.y());
|
||
|
polyline.setPoint(0, pp);
|
||
|
|
||
|
int count = 1;
|
||
14 years ago
|
for (int i = from + 1; i <= to; i++) {
|
||
15 years ago
|
const QPoint pi(xMap.transform(x(i)), yMap.transform(y(i)));
|
||
14 years ago
|
if ( pi != pp ) {
|
||
15 years ago
|
QwtPainter::drawPoint(painter, pi.x(), pi.y());
|
||
|
|
||
|
polyline.setPoint(count, pi);
|
||
|
count++;
|
||
|
|
||
|
pp = pi;
|
||
|
}
|
||
|
}
|
||
|
if ( int(polyline.size()) != count )
|
||
|
polyline.resize(count);
|
||
14 years ago
|
} else {
|
||
15 years ago
|
// if we don't need to fill, we can sort out
|
||
|
// duplicates independent from the order
|
||
|
|
||
|
PrivateData::PixelMatrix pixelMatrix(window);
|
||
|
|
||
14 years ago
|
for (int i = from; i <= to; i++) {
|
||
15 years ago
|
const QPoint p( xMap.transform(x(i)),
|
||
14 years ago
|
yMap.transform(y(i)) );
|
||
15 years ago
|
|
||
|
if ( pixelMatrix.testPixel(p) )
|
||
|
QwtPainter::drawPoint(painter, p.x(), p.y());
|
||
|
}
|
||
|
}
|
||
14 years ago
|
} else {
|
||
|
for (int i = from; i <= to; i++) {
|
||
15 years ago
|
const int xi = xMap.transform(x(i));
|
||
|
const int yi = yMap.transform(y(i));
|
||
|
QwtPainter::drawPoint(painter, xi, yi);
|
||
|
|
||
|
if ( doFill )
|
||
|
polyline.setPoint(i - from, xi, yi);
|
||
|
}
|
||
|
}
|
||
|
|
||
14 years ago
|
if ( doFill ) {
|
||
15 years ago
|
polyline = ::clipPolygon(painter, d_data->paintAttributes, polyline);
|
||
|
fillCurve(painter, xMap, yMap, polyline);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Draw step function
|
||
|
|
||
14 years ago
|
The direction of the steps depends on Inverted attribute.
|
||
15 years ago
|
|
||
|
\param painter Painter
|
||
|
\param xMap x map
|
||
|
\param yMap y map
|
||
|
\param from index of the first point to be painted
|
||
|
\param to index of the last point to be painted
|
||
|
|
||
|
\sa CurveAttribute, setCurveAttribute(),
|
||
|
draw(), drawCurve(), drawDots(), drawLines(), drawSticks()
|
||
|
*/
|
||
|
void QwtPlotCurve::drawSteps(QPainter *painter,
|
||
14 years ago
|
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||
|
int from, int to) const
|
||
15 years ago
|
{
|
||
|
QwtPolygon polyline(2 * (to - from) + 1);
|
||
|
|
||
|
bool inverted = d_data->curveType == Yfx;
|
||
|
if ( d_data->attributes & Inverted )
|
||
|
inverted = !inverted;
|
||
|
|
||
|
int i,ip;
|
||
14 years ago
|
for (i = from, ip = 0; i <= to; i++, ip += 2) {
|
||
15 years ago
|
const int xi = xMap.transform(x(i));
|
||
|
const int yi = yMap.transform(y(i));
|
||
|
|
||
14 years ago
|
if ( ip > 0 ) {
|
||
15 years ago
|
if (inverted)
|
||
|
polyline.setPoint(ip - 1, polyline[ip-2].x(), yi);
|
||
|
else
|
||
|
polyline.setPoint(ip - 1, xi, polyline[ip-2].y());
|
||
|
}
|
||
|
|
||
|
polyline.setPoint(ip, xi, yi);
|
||
|
}
|
||
|
|
||
|
polyline = ::clipPolygon(painter, d_data->paintAttributes, polyline);
|
||
|
|
||
|
QwtPainter::drawPolyline(painter, polyline);
|
||
|
|
||
|
if ( d_data->brush.style() != Qt::NoBrush )
|
||
|
fillCurve(painter, xMap, yMap, polyline);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
\brief Specify an attribute for drawing the curve
|
||
|
|
||
|
The attributes can be used to modify the drawing style.
|
||
|
The following attributes are defined:<dl>
|
||
|
<dt>Fitted</dt>
|
||
|
<dd>For Lines only. A QwtCurveFitter tries to
|
||
|
interpolate/smooth the curve, before it is painted.
|
||
|
Note that curve fitting requires temorary memory
|
||
14 years ago
|
for calculating coefficients and additional points.
|
||
15 years ago
|
If painting in Fitted mode is slow it might be better
|
||
|
to fit the points, before they are passed to QwtPlotCurve.
|
||
|
</dd>
|
||
|
<dt>Inverted</dt>
|
||
|
<dd>For Steps only. Draws a step function
|
||
|
from the right to the left.</dd></dl>
|
||
|
|
||
|
\param attribute Curve attribute
|
||
|
\param on On/Off
|
||
|
|
||
|
/sa testCurveAttribute(), setCurveFitter()
|
||
|
*/
|
||
|
void QwtPlotCurve::setCurveAttribute(CurveAttribute attribute, bool on)
|
||
|
{
|
||
|
if ( bool(d_data->attributes & attribute) == on )
|
||
|
return;
|
||
|
|
||
|
if ( on )
|
||
|
d_data->attributes |= attribute;
|
||
|
else
|
||
|
d_data->attributes &= ~attribute;
|
||
|
|
||
|
itemChanged();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return true, if attribute is enabled
|
||
|
\sa setCurveAttribute()
|
||
|
*/
|
||
14 years ago
|
bool QwtPlotCurve::testCurveAttribute(CurveAttribute attribute) const
|
||
|
{
|
||
15 years ago
|
return d_data->attributes & attribute;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Assign the curve type
|
||
|
|
||
|
<dt>QwtPlotCurve::Yfx
|
||
|
<dd>Draws y as a function of x (the default). The
|
||
|
baseline is interpreted as a horizontal line
|
||
|
with y = baseline().</dd>
|
||
|
<dt>QwtPlotCurve::Xfy
|
||
|
<dd>Draws x as a function of y. The baseline is
|
||
|
interpreted as a vertical line with x = baseline().</dd>
|
||
|
|
||
|
The baseline is used for aligning the sticks, or
|
||
|
filling the curve with a brush.
|
||
|
|
||
|
\sa curveType()
|
||
|
*/
|
||
|
void QwtPlotCurve::setCurveType(CurveType curveType)
|
||
|
{
|
||
14 years ago
|
if ( d_data->curveType != curveType ) {
|
||
15 years ago
|
d_data->curveType = curveType;
|
||
|
itemChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Return the curve type
|
||
|
\sa setCurveType()
|
||
|
*/
|
||
|
QwtPlotCurve::CurveType QwtPlotCurve::curveType() const
|
||
|
{
|
||
|
return d_data->curveType;
|
||
|
}
|
||
|
|
||
|
void QwtPlotCurve::setCurveFitter(QwtCurveFitter *curveFitter)
|
||
|
{
|
||
|
delete d_data->curveFitter;
|
||
|
d_data->curveFitter = curveFitter;
|
||
|
|
||
|
itemChanged();
|
||
|
}
|
||
|
|
||
|
QwtCurveFitter *QwtPlotCurve::curveFitter() const
|
||
|
{
|
||
|
return d_data->curveFitter;
|
||
|
}
|
||
|
|
||
14 years ago
|
/*!
|
||
|
Fill the area between the curve and the baseline with
|
||
15 years ago
|
the curve brush
|
||
|
|
||
|
\param painter Painter
|
||
|
\param xMap x map
|
||
|
\param yMap y map
|
||
|
\param pa Polygon
|
||
|
|
||
|
\sa setBrush(), setBaseline(), setCurveType()
|
||
|
*/
|
||
|
|
||
|
void QwtPlotCurve::fillCurve(QPainter *painter,
|
||
14 years ago
|
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||
|
QwtPolygon &pa) const
|
||
15 years ago
|
{
|
||
|
if ( d_data->brush.style() == Qt::NoBrush )
|
||
|
return;
|
||
|
|
||
|
closePolyline(xMap, yMap, pa);
|
||
|
if ( pa.count() <= 2 ) // a line can't be filled
|
||
|
return;
|
||
|
|
||
|
QBrush b = d_data->brush;
|
||
|
if ( !b.color().isValid() )
|
||
|
b.setColor(d_data->pen.color());
|
||
|
|
||
|
painter->save();
|
||
|
|
||
|
painter->setPen(QPen(Qt::NoPen));
|
||
|
painter->setBrush(b);
|
||
|
|
||
|
QwtPainter::drawPolygon(painter, pa);
|
||
|
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
14 years ago
|
\brief Complete a polygon to be a closed polygon
|
||
15 years ago
|
including the area between the original polygon
|
||
|
and the baseline.
|
||
|
\param xMap X map
|
||
|
\param yMap Y map
|
||
|
\param pa Polygon to be completed
|
||
|
*/
|
||
|
|
||
|
void QwtPlotCurve::closePolyline(
|
||
|
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||
|
QwtPolygon &pa) const
|
||
|
{
|
||
|
const int sz = pa.size();
|
||
|
if ( sz < 2 )
|
||
|
return;
|
||
|
|
||
|
pa.resize(sz + 2);
|
||
|
|
||
14 years ago
|
if ( d_data->curveType == QwtPlotCurve::Xfy ) {
|
||
15 years ago
|
pa.setPoint(sz,
|
||
14 years ago
|
xMap.transform(d_data->reference), pa.point(sz - 1).y());
|
||
15 years ago
|
pa.setPoint(sz + 1,
|
||
14 years ago
|
xMap.transform(d_data->reference), pa.point(0).y());
|
||
|
} else {
|
||
15 years ago
|
pa.setPoint(sz,
|
||
14 years ago
|
pa.point(sz - 1).x(), yMap.transform(d_data->reference));
|
||
15 years ago
|
pa.setPoint(pa.size() - 1,
|
||
14 years ago
|
pa.point(0).x(), yMap.transform(d_data->reference));
|
||
15 years ago
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Draw symbols
|
||
|
\param painter Painter
|
||
|
\param symbol Curve symbol
|
||
|
\param xMap x map
|
||
|
\param yMap y map
|
||
|
\param from index of the first point to be painted
|
||
|
\param to index of the last point to be painted
|
||
|
|
||
|
\sa setSymbol(), draw(), drawCurve()
|
||
|
*/
|
||
|
void QwtPlotCurve::drawSymbols(QPainter *painter, const QwtSymbol &symbol,
|
||
14 years ago
|
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||
|
int from, int to) const
|
||
15 years ago
|
{
|
||
|
painter->setBrush(symbol.brush());
|
||
|
|
||
|
const QwtMetricsMap &metricsMap = QwtPainter::metricsMap();
|
||
|
|
||
|
QPen pen = symbol.pen();
|
||
|
|
||
|
#if SCALE_PEN
|
||
|
if ( pen.width() > 0 )
|
||
|
pen.setWidth(metricsMap.screenToLayoutX(pen.width()));
|
||
|
#endif
|
||
|
|
||
|
painter->setPen(pen);
|
||
|
|
||
|
QRect rect;
|
||
|
rect.setSize(metricsMap.screenToLayout(symbol.size()));
|
||
|
|
||
14 years ago
|
if ( to > from && d_data->paintAttributes & PaintFiltered ) {
|
||
15 years ago
|
const QRect window = painter->window();
|
||
|
if ( window.isEmpty() )
|
||
|
return;
|
||
|
|
||
|
PrivateData::PixelMatrix pixelMatrix(window);
|
||
|
|
||
14 years ago
|
for (int i = from; i <= to; i++) {
|
||
15 years ago
|
const QPoint pi( xMap.transform(x(i)),
|
||
14 years ago
|
yMap.transform(y(i)) );
|
||
15 years ago
|
|
||
14 years ago
|
if ( pixelMatrix.testPixel(pi) ) {
|
||
15 years ago
|
rect.moveCenter(pi);
|
||
|
symbol.draw(painter, rect);
|
||
|
}
|
||
|
}
|
||
14 years ago
|
} else {
|
||
|
for (int i = from; i <= to; i++) {
|
||
15 years ago
|
const int xi = xMap.transform(x(i));
|
||
|
const int yi = yMap.transform(y(i));
|
||
|
|
||
|
rect.moveCenter(QPoint(xi, yi));
|
||
|
symbol.draw(painter, rect);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Set the value of the baseline
|
||
|
|
||
|
The baseline is needed for filling the curve with a brush or
|
||
14 years ago
|
the Sticks drawing style.
|
||
15 years ago
|
The default value is 0.0. The interpretation
|
||
|
of the baseline depends on the CurveType. With QwtPlotCurve::Yfx,
|
||
|
the baseline is interpreted as a horizontal line at y = baseline(),
|
||
|
with QwtPlotCurve::Yfy, it is interpreted as a vertical line at
|
||
|
x = baseline().
|
||
|
\param reference baseline
|
||
|
\sa baseline(), setBrush(), setStyle(), setCurveType()
|
||
|
*/
|
||
|
void QwtPlotCurve::setBaseline(double reference)
|
||
|
{
|
||
14 years ago
|
if ( d_data->reference != reference ) {
|
||
15 years ago
|
d_data->reference = reference;
|
||
|
itemChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Return the value of the baseline
|
||
|
\sa setBaseline
|
||
|
*/
|
||
14 years ago
|
double QwtPlotCurve::baseline() const
|
||
|
{
|
||
|
return d_data->reference;
|
||
15 years ago
|
}
|
||
|
|
||
|
/*!
|
||
|
Return the size of the data arrays
|
||
|
\sa setData()
|
||
|
*/
|
||
|
int QwtPlotCurve::dataSize() const
|
||
|
{
|
||
|
return d_xy->size();
|
||
|
}
|
||
|
|
||
|
int QwtPlotCurve::closestPoint(const QPoint &pos, double *dist) const
|
||
|
{
|
||
|
if ( plot() == NULL || dataSize() <= 0 )
|
||
|
return -1;
|
||
|
|
||
|
const QwtScaleMap xMap = plot()->canvasMap(xAxis());
|
||
|
const QwtScaleMap yMap = plot()->canvasMap(yAxis());
|
||
|
|
||
|
int index = -1;
|
||
|
double dmin = 1.0e10;
|
||
|
|
||
14 years ago
|
for (int i=0; i < dataSize(); i++) {
|
||
15 years ago
|
const double cx = xMap.xTransform(x(i)) - pos.x();
|
||
|
const double cy = yMap.xTransform(y(i)) - pos.y();
|
||
|
|
||
|
const double f = qwtSqr(cx) + qwtSqr(cy);
|
||
14 years ago
|
if (f < dmin) {
|
||
15 years ago
|
index = i;
|
||
|
dmin = f;
|
||
|
}
|
||
|
}
|
||
|
if ( dist )
|
||
|
*dist = sqrt(dmin);
|
||
|
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
//! Update the widget that represents the curve on the legend
|
||
|
void QwtPlotCurve::updateLegend(QwtLegend *legend) const
|
||
|
{
|
||
|
if ( !legend )
|
||
|
return;
|
||
|
|
||
|
QwtPlotItem::updateLegend(legend);
|
||
|
|
||
|
QWidget *widget = legend->find(this);
|
||
|
if ( !widget || !widget->inherits("QwtLegendItem") )
|
||
|
return;
|
||
|
|
||
|
QwtLegendItem *legendItem = (QwtLegendItem *)widget;
|
||
|
|
||
|
#if QT_VERSION < 0x040000
|
||
|
const bool doUpdate = legendItem->isUpdatesEnabled();
|
||
|
#else
|
||
|
const bool doUpdate = legendItem->updatesEnabled();
|
||
|
#endif
|
||
|
legendItem->setUpdatesEnabled(false);
|
||
|
|
||
|
const int policy = legend->displayPolicy();
|
||
|
|
||
14 years ago
|
if (policy == QwtLegend::FixedIdentifier) {
|
||
15 years ago
|
int mode = legend->identifierMode();
|
||
|
|
||
|
if (mode & QwtLegendItem::ShowLine)
|
||
|
legendItem->setCurvePen(pen());
|
||
|
|
||
|
if (mode & QwtLegendItem::ShowSymbol)
|
||
|
legendItem->setSymbol(symbol());
|
||
|
|
||
|
if (mode & QwtLegendItem::ShowText)
|
||
|
legendItem->setText(title());
|
||
|
else
|
||
|
legendItem->setText(QwtText());
|
||
|
|
||
|
legendItem->setIdentifierMode(mode);
|
||
14 years ago
|
} else if (policy == QwtLegend::AutoIdentifier) {
|
||
15 years ago
|
int mode = 0;
|
||
|
|
||
14 years ago
|
if (QwtPlotCurve::NoCurve != style()) {
|
||
15 years ago
|
legendItem->setCurvePen(pen());
|
||
|
mode |= QwtLegendItem::ShowLine;
|
||
|
}
|
||
14 years ago
|
if (QwtSymbol::NoSymbol != symbol().style()) {
|
||
15 years ago
|
legendItem->setSymbol(symbol());
|
||
|
mode |= QwtLegendItem::ShowSymbol;
|
||
|
}
|
||
14 years ago
|
if ( !title().isEmpty() ) {
|
||
15 years ago
|
legendItem->setText(title());
|
||
|
mode |= QwtLegendItem::ShowText;
|
||
14 years ago
|
} else {
|
||
15 years ago
|
legendItem->setText(QwtText());
|
||
|
}
|
||
|
legendItem->setIdentifierMode(mode);
|
||
|
}
|
||
|
|
||
|
legendItem->setUpdatesEnabled(doUpdate);
|
||
|
legendItem->update();
|
||
|
}
|