Loading...
Searching...
No Matches
qwt_symbol.cpp
/******************************************************************************
* 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 "qwt_symbol.h"
#include "qwt_painter.h"
#include "qwt_graphic.h"
#include "qwt_math.h"
#include <qpainter.h>
#include <qpainterpath.h>
#include <qpixmap.h>
#include <qpaintengine.h>
#ifndef QWT_NO_SVG
#include <qsvgrenderer.h>
#endif
namespace QwtTriangle
{
enum Type
{
Left,
Right,
Up,
Down
};
}
static QwtGraphic qwtPathGraphic( const QPainterPath& path,
const QPen& pen, const QBrush& brush )
{
QwtGraphic graphic;
graphic.setRenderHint( QwtGraphic::RenderPensUnscaled );
QPainter painter( &graphic );
painter.setPen( pen );
painter.setBrush( brush );
painter.drawPath( path );
painter.end();
return graphic;
}
static inline QRectF qwtScaledBoundingRect(
const QwtGraphic& graphic, const QSizeF size )
{
QSizeF scaledSize = size;
if ( scaledSize.isEmpty() )
scaledSize = graphic.defaultSize();
const QSizeF sz = graphic.controlPointRect().size();
double sx = 1.0;
if ( sz.width() > 0.0 )
sx = scaledSize.width() / sz.width();
double sy = 1.0;
if ( sz.height() > 0.0 )
sy = scaledSize.height() / sz.height();
return graphic.scaledBoundingRect( sx, sy );
}
static inline void qwtDrawPixmapSymbols( QPainter* painter,
const QPointF* points, int numPoints, const QwtSymbol& symbol )
{
QSize size = symbol.size();
if ( size.isEmpty() )
size = symbol.pixmap().size();
const QTransform transform = painter->transform();
if ( transform.isScaling() )
{
const QRect r( 0, 0, size.width(), size.height() );
size = transform.mapRect( r ).size();
}
QPixmap pm = symbol.pixmap();
if ( pm.size() != size )
pm = pm.scaled( size );
QPointF pinPoint( 0.5 * size.width(), 0.5 * size.height() );
if ( symbol.isPinPointEnabled() )
pinPoint = symbol.pinPoint();
painter->resetTransform();
for ( int i = 0; i < numPoints; i++ )
{
const QPointF pos = transform.map( points[i] ) - pinPoint;
QwtPainter::drawPixmap( painter,
QRect( pos.toPoint(), pm.size() ), pm );
}
}
#ifndef QWT_NO_SVG
static inline void qwtDrawSvgSymbols( QPainter* painter,
const QPointF* points, int numPoints,
QSvgRenderer* renderer, const QwtSymbol& symbol )
{
if ( renderer == NULL || !renderer->isValid() )
return;
const QRectF viewBox = renderer->viewBoxF();
if ( viewBox.isEmpty() )
return;
QSizeF sz = symbol.size();
if ( !sz.isValid() )
sz = viewBox.size();
const double sx = sz.width() / viewBox.width();
const double sy = sz.height() / viewBox.height();
QPointF pinPoint = viewBox.center();
if ( symbol.isPinPointEnabled() )
pinPoint = symbol.pinPoint();
const double dx = sx * ( pinPoint.x() - viewBox.left() );
const double dy = sy * ( pinPoint.y() - viewBox.top() );
for ( int i = 0; i < numPoints; i++ )
{
const double x = points[i].x() - dx;
const double y = points[i].y() - dy;
renderer->render( painter,
QRectF( x, y, sz.width(), sz.height() ) );
}
}
#endif
static inline void qwtDrawGraphicSymbols( QPainter* painter,
const QPointF* points, int numPoints, const QwtGraphic& graphic,
const QwtSymbol& symbol )
{
const QRectF pointRect = graphic.controlPointRect();
if ( pointRect.isEmpty() )
return;
double sx = 1.0;
double sy = 1.0;
const QSize sz = symbol.size();
if ( sz.isValid() )
{
sx = sz.width() / pointRect.width();
sy = sz.height() / pointRect.height();
}
QPointF pinPoint = pointRect.center();
if ( symbol.isPinPointEnabled() )
pinPoint = symbol.pinPoint();
const QTransform transform = painter->transform();
for ( int i = 0; i < numPoints; i++ )
{
QTransform tr = transform;
tr.translate( points[i].x(), points[i].y() );
tr.scale( sx, sy );
tr.translate( -pinPoint.x(), -pinPoint.y() );
painter->setTransform( tr );
graphic.render( painter );
}
painter->setTransform( transform );
}
static inline void qwtDrawEllipseSymbols( QPainter* painter,
const QPointF* points, int numPoints, const QwtSymbol& symbol )
{
painter->setBrush( symbol.brush() );
painter->setPen( symbol.pen() );
const QSize size = symbol.size();
if ( QwtPainter::roundingAlignment( painter ) )
{
const int sw = size.width();
const int sh = size.height();
const int sw2 = size.width() / 2;
const int sh2 = size.height() / 2;
for ( int i = 0; i < numPoints; i++ )
{
const int x = qRound( points[i].x() );
const int y = qRound( points[i].y() );
const QRectF r( x - sw2, y - sh2, sw, sh );
QwtPainter::drawEllipse( painter, r );
}
}
else
{
const double sw = size.width();
const double sh = size.height();
const double sw2 = 0.5 * size.width();
const double sh2 = 0.5 * size.height();
for ( int i = 0; i < numPoints; i++ )
{
const double x = points[i].x();
const double y = points[i].y();
const QRectF r( x - sw2, y - sh2, sw, sh );
QwtPainter::drawEllipse( painter, r );
}
}
}
static inline void qwtDrawRectSymbols( QPainter* painter,
const QPointF* points, int numPoints, const QwtSymbol& symbol )
{
const QSize size = symbol.size();
QPen pen = symbol.pen();
pen.setJoinStyle( Qt::MiterJoin );
painter->setPen( pen );
painter->setBrush( symbol.brush() );
painter->setRenderHint( QPainter::Antialiasing, false );
if ( QwtPainter::roundingAlignment( painter ) )
{
const int sw = size.width();
const int sh = size.height();
const int sw2 = size.width() / 2;
const int sh2 = size.height() / 2;
for ( int i = 0; i < numPoints; i++ )
{
const int x = qRound( points[i].x() );
const int y = qRound( points[i].y() );
const QRect r( x - sw2, y - sh2, sw, sh );
QwtPainter::drawRect( painter, r );
}
}
else
{
const double sw = size.width();
const double sh = size.height();
const double sw2 = 0.5 * size.width();
const double sh2 = 0.5 * size.height();
for ( int i = 0; i < numPoints; i++ )
{
const double x = points[i].x();
const double y = points[i].y();
const QRectF r( x - sw2, y - sh2, sw, sh );
QwtPainter::drawRect( painter, r );
}
}
}
static inline void qwtDrawDiamondSymbols( QPainter* painter,
const QPointF* points, int numPoints, const QwtSymbol& symbol )
{
const QSize size = symbol.size();
QPen pen = symbol.pen();
pen.setJoinStyle( Qt::MiterJoin );
painter->setPen( pen );
painter->setBrush( symbol.brush() );
if ( QwtPainter::roundingAlignment( painter ) )
{
for ( int i = 0; i < numPoints; i++ )
{
const int x = qRound( points[i].x() );
const int y = qRound( points[i].y() );
const int x1 = x - size.width() / 2;
const int y1 = y - size.height() / 2;
const int x2 = x1 + size.width();
const int y2 = y1 + size.height();
QPolygonF polygon;
polygon += QPointF( x, y1 );
polygon += QPointF( x1, y );
polygon += QPointF( x, y2 );
polygon += QPointF( x2, y );
QwtPainter::drawPolygon( painter, polygon );
}
}
else
{
for ( int i = 0; i < numPoints; i++ )
{
const QPointF& pos = points[i];
const double x1 = pos.x() - 0.5 * size.width();
const double y1 = pos.y() - 0.5 * size.height();
const double x2 = x1 + size.width();
const double y2 = y1 + size.height();
QPolygonF polygon;
polygon += QPointF( pos.x(), y1 );
polygon += QPointF( x2, pos.y() );
polygon += QPointF( pos.x(), y2 );
polygon += QPointF( x1, pos.y() );
QwtPainter::drawPolygon( painter, polygon );
}
}
}
static inline void qwtDrawTriangleSymbols(
QPainter* painter, QwtTriangle::Type type,
const QPointF* points, int numPoints,
const QwtSymbol& symbol )
{
const QSize size = symbol.size();
QPen pen = symbol.pen();
pen.setJoinStyle( Qt::MiterJoin );
painter->setPen( pen );
painter->setBrush( symbol.brush() );
const bool doAlign = QwtPainter::roundingAlignment( painter );
double sw2 = 0.5 * size.width();
double sh2 = 0.5 * size.height();
if ( doAlign )
{
sw2 = std::floor( sw2 );
sh2 = std::floor( sh2 );
}
QPolygonF triangle( 3 );
QPointF* trianglePoints = triangle.data();
for ( int i = 0; i < numPoints; i++ )
{
const QPointF& pos = points[i];
double x = pos.x();
double y = pos.y();
if ( doAlign )
{
x = qRound( x );
y = qRound( y );
}
const double x1 = x - sw2;
const double x2 = x1 + size.width();
const double y1 = y - sh2;
const double y2 = y1 + size.height();
switch ( type )
{
case QwtTriangle::Left:
{
trianglePoints[0].rx() = x2;
trianglePoints[0].ry() = y1;
trianglePoints[1].rx() = x1;
trianglePoints[1].ry() = y;
trianglePoints[2].rx() = x2;
trianglePoints[2].ry() = y2;
break;
}
case QwtTriangle::Right:
{
trianglePoints[0].rx() = x1;
trianglePoints[0].ry() = y1;
trianglePoints[1].rx() = x2;
trianglePoints[1].ry() = y;
trianglePoints[2].rx() = x1;
trianglePoints[2].ry() = y2;
break;
}
case QwtTriangle::Up:
{
trianglePoints[0].rx() = x1;
trianglePoints[0].ry() = y2;
trianglePoints[1].rx() = x;
trianglePoints[1].ry() = y1;
trianglePoints[2].rx() = x2;
trianglePoints[2].ry() = y2;
break;
}
case QwtTriangle::Down:
{
trianglePoints[0].rx() = x1;
trianglePoints[0].ry() = y1;
trianglePoints[1].rx() = x;
trianglePoints[1].ry() = y2;
trianglePoints[2].rx() = x2;
trianglePoints[2].ry() = y1;
break;
}
}
QwtPainter::drawPolygon( painter, triangle );
}
}
static inline void qwtDrawLineSymbols(
QPainter* painter, int orientations,
const QPointF* points, int numPoints, const QwtSymbol& symbol )
{
const QSize size = symbol.size();
int off = 0;
QPen pen = symbol.pen();
if ( pen.width() > 1 )
{
pen.setCapStyle( Qt::FlatCap );
off = 1;
}
painter->setPen( pen );
painter->setRenderHint( QPainter::Antialiasing, false );
if ( QwtPainter::roundingAlignment( painter ) )
{
const int sw = qwtFloor( size.width() );
const int sh = qwtFloor( size.height() );
const int sw2 = size.width() / 2;
const int sh2 = size.height() / 2;
for ( int i = 0; i < numPoints; i++ )
{
if ( orientations & Qt::Horizontal )
{
const int x = qRound( points[i].x() ) - sw2;
const int y = qRound( points[i].y() );
QwtPainter::drawLine( painter, x, y, x + sw + off, y );
}
if ( orientations & Qt::Vertical )
{
const int x = qRound( points[i].x() );
const int y = qRound( points[i].y() ) - sh2;
QwtPainter::drawLine( painter, x, y, x, y + sh + off );
}
}
}
else
{
const double sw = size.width();
const double sh = size.height();
const double sw2 = 0.5 * size.width();
const double sh2 = 0.5 * size.height();
for ( int i = 0; i < numPoints; i++ )
{
if ( orientations & Qt::Horizontal )
{
const double x = points[i].x() - sw2;
const double y = points[i].y();
QwtPainter::drawLine( painter, x, y, x + sw, y );
}
if ( orientations & Qt::Vertical )
{
const double y = points[i].y() - sh2;
const double x = points[i].x();
QwtPainter::drawLine( painter, x, y, x, y + sh );
}
}
}
}
static inline void qwtDrawXCrossSymbols( QPainter* painter,
const QPointF* points, int numPoints, const QwtSymbol& symbol )
{
const QSize size = symbol.size();
int off = 0;
QPen pen = symbol.pen();
if ( pen.width() > 1 )
{
pen.setCapStyle( Qt::FlatCap );
off = 1;
}
painter->setPen( pen );
if ( QwtPainter::roundingAlignment( painter ) )
{
const int sw = size.width();
const int sh = size.height();
const int sw2 = size.width() / 2;
const int sh2 = size.height() / 2;
for ( int i = 0; i < numPoints; i++ )
{
const QPointF& pos = points[i];
const int x = qRound( pos.x() );
const int y = qRound( pos.y() );
const int x1 = x - sw2;
const int x2 = x1 + sw + off;
const int y1 = y - sh2;
const int y2 = y1 + sh + off;
QwtPainter::drawLine( painter, x1, y1, x2, y2 );
QwtPainter::drawLine( painter, x2, y1, x1, y2 );
}
}
else
{
const double sw = size.width();
const double sh = size.height();
const double sw2 = 0.5 * size.width();
const double sh2 = 0.5 * size.height();
for ( int i = 0; i < numPoints; i++ )
{
const QPointF& pos = points[i];
const double x1 = pos.x() - sw2;
const double x2 = x1 + sw;
const double y1 = pos.y() - sh2;
const double y2 = y1 + sh;
QwtPainter::drawLine( painter, x1, y1, x2, y2 );
QwtPainter::drawLine( painter, x1, y2, x2, y1 );
}
}
}
static inline void qwtDrawStar1Symbols( QPainter* painter,
const QPointF* points, int numPoints, const QwtSymbol& symbol )
{
const QSize size = symbol.size();
painter->setPen( symbol.pen() );
if ( QwtPainter::roundingAlignment( painter ) )
{
QRect r( 0, 0, size.width(), size.height() );
for ( int i = 0; i < numPoints; i++ )
{
r.moveCenter( points[i].toPoint() );
const double sqrt1_2 = 0.70710678118654752440; /* 1/sqrt(2) */
const double d1 = r.width() / 2.0 * ( 1.0 - sqrt1_2 );
QwtPainter::drawLine( painter,
qRound( r.left() + d1 ), qRound( r.top() + d1 ),
qRound( r.right() - d1 ), qRound( r.bottom() - d1 ) );
QwtPainter::drawLine( painter,
qRound( r.left() + d1 ), qRound( r.bottom() - d1 ),
qRound( r.right() - d1), qRound( r.top() + d1 ) );
const QPoint c = r.center();
QwtPainter::drawLine( painter,
c.x(), r.top(), c.x(), r.bottom() );
QwtPainter::drawLine( painter,
r.left(), c.y(), r.right(), c.y() );
}
}
else
{
QRectF r( 0, 0, size.width(), size.height() );
for ( int i = 0; i < numPoints; i++ )
{
r.moveCenter( points[i] );
const double sqrt1_2 = 0.70710678118654752440; /* 1/sqrt(2) */
const QPointF c = r.center();
const double d1 = r.width() / 2.0 * ( 1.0 - sqrt1_2 );
QwtPainter::drawLine( painter,
r.left() + d1, r.top() + d1,
r.right() - d1, r.bottom() - d1 );
QwtPainter::drawLine( painter,
r.left() + d1, r.bottom() - d1,
r.right() - d1, r.top() + d1 );
QwtPainter::drawLine( painter,
c.x(), r.top(),
c.x(), r.bottom() );
QwtPainter::drawLine( painter,
r.left(), c.y(),
r.right(), c.y() );
}
}
}
static inline void qwtDrawStar2Symbols( QPainter* painter,
const QPointF* points, int numPoints, const QwtSymbol& symbol )
{
QPen pen = symbol.pen();
if ( pen.width() > 1 )
pen.setCapStyle( Qt::FlatCap );
pen.setJoinStyle( Qt::MiterJoin );
painter->setPen( pen );
painter->setBrush( symbol.brush() );
const double cos30 = 0.866025; // cos(30°)
const double dy = 0.25 * symbol.size().height();
const double dx = 0.5 * symbol.size().width() * cos30 / 3.0;
QPolygonF star( 12 );
QPointF* starPoints = star.data();
const bool doAlign = QwtPainter::roundingAlignment( painter );
for ( int i = 0; i < numPoints; i++ )
{
double x = points[i].x();
double y = points[i].y();
if ( doAlign )
{
x = qRound( x );
y = qRound( y );
}
double x1 = x - 3 * dx;
double y1 = y - 2 * dy;
if ( doAlign )
{
x1 = qRound( x - 3 * dx );
y1 = qRound( y - 2 * dy );
}
const double x2 = x1 + 1 * dx;
const double x3 = x1 + 2 * dx;
const double x4 = x1 + 3 * dx;
const double x5 = x1 + 4 * dx;
const double x6 = x1 + 5 * dx;
const double x7 = x1 + 6 * dx;
const double y2 = y1 + 1 * dy;
const double y3 = y1 + 2 * dy;
const double y4 = y1 + 3 * dy;
const double y5 = y1 + 4 * dy;
starPoints[0].rx() = x4;
starPoints[0].ry() = y1;
starPoints[1].rx() = x5;
starPoints[1].ry() = y2;
starPoints[2].rx() = x7;
starPoints[2].ry() = y2;
starPoints[3].rx() = x6;
starPoints[3].ry() = y3;
starPoints[4].rx() = x7;
starPoints[4].ry() = y4;
starPoints[5].rx() = x5;
starPoints[5].ry() = y4;
starPoints[6].rx() = x4;
starPoints[6].ry() = y5;
starPoints[7].rx() = x3;
starPoints[7].ry() = y4;
starPoints[8].rx() = x1;
starPoints[8].ry() = y4;
starPoints[9].rx() = x2;
starPoints[9].ry() = y3;
starPoints[10].rx() = x1;
starPoints[10].ry() = y2;
starPoints[11].rx() = x3;
starPoints[11].ry() = y2;
QwtPainter::drawPolygon( painter, star );
}
}
static inline void qwtDrawHexagonSymbols( QPainter* painter,
const QPointF* points, int numPoints, const QwtSymbol& symbol )
{
painter->setBrush( symbol.brush() );
painter->setPen( symbol.pen() );
const double cos30 = 0.866025; // cos(30°)
const double dx = 0.5 * ( symbol.size().width() - cos30 );
const double dy = 0.25 * symbol.size().height();
QPolygonF hexaPolygon( 6 );
QPointF* hexaPoints = hexaPolygon.data();
const bool doAlign = QwtPainter::roundingAlignment( painter );
for ( int i = 0; i < numPoints; i++ )
{
double x = points[i].x();
double y = points[i].y();
if ( doAlign )
{
x = qRound( x );
y = qRound( y );
}
double x1 = x - dx;
double y1 = y - 2 * dy;
if ( doAlign )
{
x1 = std::ceil( x1 );
y1 = std::ceil( y1 );
}
const double x2 = x1 + 1 * dx;
const double x3 = x1 + 2 * dx;
const double y2 = y1 + 1 * dy;
const double y3 = y1 + 3 * dy;
const double y4 = y1 + 4 * dy;
hexaPoints[0].rx() = x2;
hexaPoints[0].ry() = y1;
hexaPoints[1].rx() = x3;
hexaPoints[1].ry() = y2;
hexaPoints[2].rx() = x3;
hexaPoints[2].ry() = y3;
hexaPoints[3].rx() = x2;
hexaPoints[3].ry() = y4;
hexaPoints[4].rx() = x1;
hexaPoints[4].ry() = y3;
hexaPoints[5].rx() = x1;
hexaPoints[5].ry() = y2;
QwtPainter::drawPolygon( painter, hexaPolygon );
}
}
class QwtSymbol::PrivateData
{
public:
PrivateData( QwtSymbol::Style st, const QBrush& br,
const QPen& pn, const QSize& sz )
: style( st )
, size( sz )
, brush( br )
, pen( pn )
, isPinPointEnabled( false )
{
cache.policy = QwtSymbol::AutoCache;
#ifndef QWT_NO_SVG
svg.renderer = NULL;
#endif
}
~PrivateData()
{
#ifndef QWT_NO_SVG
delete svg.renderer;
#endif
}
Style style;
QSize size;
QBrush brush;
QPen pen;
bool isPinPointEnabled;
QPointF pinPoint;
struct Path
{
QPainterPath path;
QwtGraphic graphic;
} path;
struct Pixmap
{
QPixmap pixmap;
} pixmap;
struct Graphic
{
QwtGraphic graphic;
} graphic;
#ifndef QWT_NO_SVG
struct SVG
{
QSvgRenderer* renderer;
} svg;
#endif
struct PaintCache
{
QwtSymbol::CachePolicy policy;
QPixmap pixmap;
} cache;
};
QwtSymbol::QwtSymbol( Style style )
{
m_data = new PrivateData( style, QBrush( Qt::gray ),
QPen( Qt::black, 0 ), QSize() );
}
QwtSymbol::QwtSymbol( QwtSymbol::Style style, const QBrush& brush,
const QPen& pen, const QSize& size )
{
m_data = new PrivateData( style, brush, pen, size );
}
QwtSymbol::QwtSymbol( const QPainterPath& path,
const QBrush& brush, const QPen& pen )
{
m_data = new PrivateData( QwtSymbol::Path, brush, pen, QSize() );
setPath( path );
}
QwtSymbol::~QwtSymbol()
{
delete m_data;
}
void QwtSymbol::setCachePolicy(
QwtSymbol::CachePolicy policy )
{
if ( m_data->cache.policy != policy )
{
m_data->cache.policy = policy;
invalidateCache();
}
}
QwtSymbol::CachePolicy QwtSymbol::cachePolicy() const
{
return m_data->cache.policy;
}
void QwtSymbol::setPath( const QPainterPath& path )
{
m_data->style = QwtSymbol::Path;
m_data->path.path = path;
m_data->path.graphic.reset();
}
const QPainterPath& QwtSymbol::path() const
{
return m_data->path.path;
}
void QwtSymbol::setPixmap( const QPixmap& pixmap )
{
m_data->style = QwtSymbol::Pixmap;
m_data->pixmap.pixmap = pixmap;
}
const QPixmap& QwtSymbol::pixmap() const
{
return m_data->pixmap.pixmap;
}
void QwtSymbol::setGraphic( const QwtGraphic& graphic )
{
m_data->style = QwtSymbol::Graphic;
m_data->graphic.graphic = graphic;
}
const QwtGraphic& QwtSymbol::graphic() const
{
return m_data->graphic.graphic;
}
#ifndef QWT_NO_SVG
void QwtSymbol::setSvgDocument( const QByteArray& svgDocument )
{
m_data->style = QwtSymbol::SvgDocument;
if ( m_data->svg.renderer == NULL )
m_data->svg.renderer = new QSvgRenderer();
m_data->svg.renderer->load( svgDocument );
}
#endif
void QwtSymbol::setSize( int width, int height )
{
if ( ( width >= 0 ) && ( height < 0 ) )
height = width;
setSize( QSize( width, height ) );
}
void QwtSymbol::setSize( const QSize& size )
{
if ( size.isValid() && size != m_data->size )
{
m_data->size = size;
invalidateCache();
}
}
const QSize& QwtSymbol::size() const
{
return m_data->size;
}
void QwtSymbol::setBrush( const QBrush& brush )
{
if ( brush != m_data->brush )
{
m_data->brush = brush;
invalidateCache();
if ( m_data->style == QwtSymbol::Path )
m_data->path.graphic.reset();
}
}
const QBrush& QwtSymbol::brush() const
{
return m_data->brush;
}
void QwtSymbol::setPen( const QColor& color,
qreal width, Qt::PenStyle style )
{
setPen( QPen( color, width, style ) );
}
void QwtSymbol::setPen( const QPen& pen )
{
if ( pen != m_data->pen )
{
m_data->pen = pen;
invalidateCache();
if ( m_data->style == QwtSymbol::Path )
m_data->path.graphic.reset();
}
}
const QPen& QwtSymbol::pen() const
{
return m_data->pen;
}
void QwtSymbol::setColor( const QColor& color )
{
switch ( m_data->style )
{
case QwtSymbol::Ellipse:
case QwtSymbol::Rect:
case QwtSymbol::Diamond:
case QwtSymbol::Triangle:
case QwtSymbol::UTriangle:
case QwtSymbol::DTriangle:
case QwtSymbol::RTriangle:
case QwtSymbol::LTriangle:
case QwtSymbol::Star2:
case QwtSymbol::Hexagon:
{
if ( m_data->brush.color() != color )
{
m_data->brush.setColor( color );
invalidateCache();
}
break;
}
case QwtSymbol::Cross:
case QwtSymbol::XCross:
case QwtSymbol::HLine:
case QwtSymbol::VLine:
case QwtSymbol::Star1:
{
if ( m_data->pen.color() != color )
{
m_data->pen.setColor( color );
invalidateCache();
}
break;
}
default:
{
if ( m_data->brush.color() != color ||
m_data->pen.color() != color )
{
invalidateCache();
}
m_data->brush.setColor( color );
m_data->pen.setColor( color );
}
}
}
void QwtSymbol::setPinPoint( const QPointF& pos, bool enable )
{
if ( m_data->pinPoint != pos )
{
m_data->pinPoint = pos;
if ( m_data->isPinPointEnabled )
{
invalidateCache();
}
}
setPinPointEnabled( enable );
}
QPointF QwtSymbol::pinPoint() const
{
return m_data->pinPoint;
}
void QwtSymbol::setPinPointEnabled( bool on )
{
if ( m_data->isPinPointEnabled != on )
{
m_data->isPinPointEnabled = on;
invalidateCache();
}
}
bool QwtSymbol::isPinPointEnabled() const
{
return m_data->isPinPointEnabled;
}
void QwtSymbol::drawSymbols( QPainter* painter,
const QPointF* points, int numPoints ) const
{
if ( numPoints <= 0 )
return;
bool useCache = false;
// Don't use the pixmap, when the paint device
// could generate scalable vectors
if ( QwtPainter::roundingAlignment( painter ) &&
!painter->transform().isScaling() )
{
if ( m_data->cache.policy == QwtSymbol::Cache )
{
useCache = true;
}
else if ( m_data->cache.policy == QwtSymbol::AutoCache )
{
switch( painter->paintEngine()->type() )
{
case QPaintEngine::OpenGL:
case QPaintEngine::OpenGL2:
{
// using a FBO as cache ?
useCache = false;
break;
}
case QPaintEngine::OpenVG:
case QPaintEngine::SVG:
case QPaintEngine::Pdf:
case QPaintEngine::Picture:
{
// vector graphics
useCache = false;
break;
}
case QPaintEngine::X11:
{
switch( m_data->style )
{
case QwtSymbol::XCross:
case QwtSymbol::HLine:
case QwtSymbol::VLine:
case QwtSymbol::Cross:
{
// for the very simple shapes using vector graphics is
// usually faster.
useCache = false;
break;
}
case QwtSymbol::Pixmap:
{
if ( m_data->size.isEmpty() ||
m_data->size == m_data->pixmap.pixmap.size() )
{
// no need to have a pixmap cache for a pixmap
// of the same size
useCache = false;
}
break;
}
default:
break;
}
break;
}
default:
{
useCache = true;
}
}
}
}
if ( useCache )
{
const QRect br = boundingRect();
if ( m_data->cache.pixmap.isNull() )
{
m_data->cache.pixmap = QwtPainter::backingStore( NULL, br.size() );
m_data->cache.pixmap.fill( Qt::transparent );
QPainter p( &m_data->cache.pixmap );
p.setRenderHints( painter->renderHints() );
p.translate( -br.topLeft() );
const QPointF pos( 0.0, 0.0 );
renderSymbols( &p, &pos, 1 );
}
const int dx = br.left();
const int dy = br.top();
for ( int i = 0; i < numPoints; i++ )
{
const int left = qRound( points[i].x() ) + dx;
const int top = qRound( points[i].y() ) + dy;
painter->drawPixmap( left, top, m_data->cache.pixmap );
}
}
else
{
painter->save();
renderSymbols( painter, points, numPoints );
painter->restore();
}
}
void QwtSymbol::drawSymbol( QPainter* painter, const QRectF& rect ) const
{
if ( m_data->style == QwtSymbol::NoSymbol )
return;
if ( m_data->style == QwtSymbol::Graphic )
{
m_data->graphic.graphic.render(
painter, rect, Qt::KeepAspectRatio );
}
else if ( m_data->style == QwtSymbol::Path )
{
if ( m_data->path.graphic.isNull() )
{
m_data->path.graphic = qwtPathGraphic(
m_data->path.path, m_data->pen, m_data->brush );
}
m_data->path.graphic.render(
painter, rect, Qt::KeepAspectRatio );
return;
}
else if ( m_data->style == QwtSymbol::SvgDocument )
{
#ifndef QWT_NO_SVG
if ( m_data->svg.renderer )
{
QRectF scaledRect;
QSizeF sz = m_data->svg.renderer->viewBoxF().size();
if ( !sz.isEmpty() )
{
sz.scale( rect.size(), Qt::KeepAspectRatio );
scaledRect.setSize( sz );
scaledRect.moveCenter( rect.center() );
}
else
{
scaledRect = rect;
}
m_data->svg.renderer->render(
painter, scaledRect );
}
#endif
}
else
{
const QRect br = boundingRect();
// scale the symbol size to fit into rect.
const double ratio = qMin( rect.width() / br.width(),
rect.height() / br.height() );
painter->save();
painter->translate( rect.center() );
painter->scale( ratio, ratio );
const bool isPinPointEnabled = m_data->isPinPointEnabled;
m_data->isPinPointEnabled = false;
const QPointF pos;
renderSymbols( painter, &pos, 1 );
m_data->isPinPointEnabled = isPinPointEnabled;
painter->restore();
}
}
void QwtSymbol::renderSymbols( QPainter* painter,
const QPointF* points, int numPoints ) const
{
switch ( m_data->style )
{
case QwtSymbol::Ellipse:
{
qwtDrawEllipseSymbols( painter, points, numPoints, *this );
break;
}
case QwtSymbol::Rect:
{
qwtDrawRectSymbols( painter, points, numPoints, *this );
break;
}
case QwtSymbol::Diamond:
{
qwtDrawDiamondSymbols( painter, points, numPoints, *this );
break;
}
case QwtSymbol::Cross:
{
qwtDrawLineSymbols( painter, Qt::Horizontal | Qt::Vertical,
points, numPoints, *this );
break;
}
case QwtSymbol::XCross:
{
qwtDrawXCrossSymbols( painter, points, numPoints, *this );
break;
}
case QwtSymbol::Triangle:
case QwtSymbol::UTriangle:
{
qwtDrawTriangleSymbols( painter, QwtTriangle::Up,
points, numPoints, *this );
break;
}
case QwtSymbol::DTriangle:
{
qwtDrawTriangleSymbols( painter, QwtTriangle::Down,
points, numPoints, *this );
break;
}
case QwtSymbol::RTriangle:
{
qwtDrawTriangleSymbols( painter, QwtTriangle::Right,
points, numPoints, *this );
break;
}
case QwtSymbol::LTriangle:
{
qwtDrawTriangleSymbols( painter, QwtTriangle::Left,
points, numPoints, *this );
break;
}
case QwtSymbol::HLine:
{
qwtDrawLineSymbols( painter, Qt::Horizontal,
points, numPoints, *this );
break;
}
case QwtSymbol::VLine:
{
qwtDrawLineSymbols( painter, Qt::Vertical,
points, numPoints, *this );
break;
}
case QwtSymbol::Star1:
{
qwtDrawStar1Symbols( painter, points, numPoints, *this );
break;
}
case QwtSymbol::Star2:
{
qwtDrawStar2Symbols( painter, points, numPoints, *this );
break;
}
case QwtSymbol::Hexagon:
{
qwtDrawHexagonSymbols( painter, points, numPoints, *this );
break;
}
case QwtSymbol::Path:
{
if ( m_data->path.graphic.isNull() )
{
m_data->path.graphic = qwtPathGraphic( m_data->path.path,
m_data->pen, m_data->brush );
}
qwtDrawGraphicSymbols( painter, points, numPoints,
m_data->path.graphic, *this );
break;
}
case QwtSymbol::Pixmap:
{
qwtDrawPixmapSymbols( painter, points, numPoints, *this );
break;
}
case QwtSymbol::Graphic:
{
qwtDrawGraphicSymbols( painter, points, numPoints,
m_data->graphic.graphic, *this );
break;
}
case QwtSymbol::SvgDocument:
{
#ifndef QWT_NO_SVG
qwtDrawSvgSymbols( painter, points, numPoints,
m_data->svg.renderer, *this );
#endif
break;
}
default:;
}
}
QRect QwtSymbol::boundingRect() const
{
QRectF rect;
bool pinPointTranslation = false;
switch ( m_data->style )
{
case QwtSymbol::Ellipse:
case QwtSymbol::Rect:
case QwtSymbol::Hexagon:
{
qreal pw = 0.0;
if ( m_data->pen.style() != Qt::NoPen )
pw = QwtPainter::effectivePenWidth( m_data->pen );
rect.setSize( m_data->size + QSizeF( pw, pw ) );
rect.moveCenter( QPointF( 0.0, 0.0 ) );
break;
}
case QwtSymbol::XCross:
case QwtSymbol::Diamond:
case QwtSymbol::Triangle:
case QwtSymbol::UTriangle:
case QwtSymbol::DTriangle:
case QwtSymbol::RTriangle:
case QwtSymbol::LTriangle:
case QwtSymbol::Star1:
case QwtSymbol::Star2:
{
qreal pw = 0.0;
if ( m_data->pen.style() != Qt::NoPen )
pw = QwtPainter::effectivePenWidth( m_data->pen );
rect.setSize( m_data->size + QSizeF( 2 * pw, 2 * pw ) );
rect.moveCenter( QPointF( 0.0, 0.0 ) );
break;
}
case QwtSymbol::Path:
{
if ( m_data->path.graphic.isNull() )
{
m_data->path.graphic = qwtPathGraphic(
m_data->path.path, m_data->pen, m_data->brush );
}
rect = qwtScaledBoundingRect(
m_data->path.graphic, m_data->size );
pinPointTranslation = true;
break;
}
case QwtSymbol::Pixmap:
{
if ( m_data->size.isEmpty() )
rect.setSize( m_data->pixmap.pixmap.size() );
else
rect.setSize( m_data->size );
pinPointTranslation = true;
break;
}
case QwtSymbol::Graphic:
{
rect = qwtScaledBoundingRect(
m_data->graphic.graphic, m_data->size );
pinPointTranslation = true;
break;
}
#ifndef QWT_NO_SVG
case QwtSymbol::SvgDocument:
{
if ( m_data->svg.renderer )
rect = m_data->svg.renderer->viewBoxF();
if ( m_data->size.isValid() && !rect.isEmpty() )
{
QSizeF sz = rect.size();
const double sx = m_data->size.width() / sz.width();
const double sy = m_data->size.height() / sz.height();
QTransform transform;
transform.scale( sx, sy );
rect = transform.mapRect( rect );
}
pinPointTranslation = true;
break;
}
#endif
default:
{
rect.setSize( m_data->size );
rect.moveCenter( QPointF( 0.0, 0.0 ) );
}
}
if ( pinPointTranslation )
{
QPointF pinPoint( 0.0, 0.0 );
if ( m_data->isPinPointEnabled )
pinPoint = rect.center() - m_data->pinPoint;
rect.moveCenter( pinPoint );
}
QRect r;
r.setLeft( qwtFloor( rect.left() ) );
r.setTop( qwtFloor( rect.top() ) );
r.setRight( qwtCeil( rect.right() ) );
r.setBottom( qwtCeil( rect.bottom() ) );
if ( m_data->style != QwtSymbol::Pixmap )
r.adjust( -1, -1, 1, 1 ); // for antialiasing
return r;
}
void QwtSymbol::invalidateCache()
{
if ( !m_data->cache.pixmap.isNull() )
m_data->cache.pixmap = QPixmap();
}
void QwtSymbol::setStyle( QwtSymbol::Style style )
{
if ( m_data->style != style )
{
m_data->style = style;
invalidateCache();
}
}
QwtSymbol::Style QwtSymbol::style() const
{
return m_data->style;
}
QwtGraphic
A paint device for scalable graphics.
Definition qwt_graphic.h:76
QwtGraphic::RenderPensUnscaled
@ RenderPensUnscaled
Definition qwt_graphic.h:96
QwtGraphic::reset
void reset()
Clear all stored commands.
Definition qwt_graphic.cpp:397
QwtGraphic::setRenderHint
void setRenderHint(RenderHint, bool on=true)
Definition qwt_graphic.cpp:443
QwtGraphic::isNull
bool isNull() const
Definition qwt_graphic.cpp:413
QwtGraphic::controlPointRect
QRectF controlPointRect() const
Definition qwt_graphic.cpp:493
QwtGraphic::defaultSize
QSizeF defaultSize() const
Default size.
Definition qwt_graphic.cpp:574
QwtGraphic::scaledBoundingRect
QRectF scaledBoundingRect(qreal sx, qreal sy) const
Calculate the target rectangle for scaling the graphic.
Definition qwt_graphic.cpp:514
QwtGraphic::render
void render(QPainter *) const
Replay all recorded painter commands.
Definition qwt_graphic.cpp:624
QwtPainter::drawEllipse
static void drawEllipse(QPainter *, const QRectF &)
Wrapper for QPainter::drawEllipse()
Definition qwt_painter.cpp:416
QwtPainter::drawPolygon
static void drawPolygon(QPainter *, const QPolygonF &)
Wrapper for QPainter::drawPolygon()
Definition qwt_painter.cpp:551
QwtPainter::effectivePenWidth
static qreal effectivePenWidth(const QPen &)
Definition qwt_painter.h:201
QwtPainter::drawRect
static void drawRect(QPainter *, qreal x, qreal y, qreal w, qreal h)
Wrapper for QPainter::drawRect()
Definition qwt_painter.cpp:337
QwtPainter::backingStore
static QPixmap backingStore(QWidget *, const QSize &)
Definition qwt_painter.cpp:1515
QwtPainter::roundingAlignment
static bool roundingAlignment()
Definition qwt_painter.h:183
QwtPainter::drawPixmap
static void drawPixmap(QPainter *, const QRectF &, const QPixmap &)
Wrapper for QPainter::drawPixmap()
Definition qwt_painter.cpp:784
QwtPainter::drawLine
static void drawLine(QPainter *, qreal x1, qreal y1, qreal x2, qreal y2)
Wrapper for QPainter::drawLine()
Definition qwt_painter.h:154
QwtSymbol
A class for drawing symbols.
Definition qwt_symbol.h:32
QwtSymbol::path
const QPainterPath & path() const
Definition qwt_symbol.cpp:977
QwtSymbol::setColor
virtual void setColor(const QColor &)
Set the color of the symbol.
Definition qwt_symbol.cpp:1186
QwtSymbol::style
Style style() const
Definition qwt_symbol.cpp:1795
QwtSymbol::brush
const QBrush & brush() const
Definition qwt_symbol.cpp:1123
QwtSymbol::pixmap
const QPixmap & pixmap() const
Definition qwt_symbol.cpp:1002
QwtSymbol::setPen
void setPen(const QColor &, qreal width=0.0, Qt::PenStyle=Qt::SolidLine)
Definition qwt_symbol.cpp:1141
QwtSymbol::drawSymbol
void drawSymbol(QPainter *, const QRectF &) const
Draw the symbol into a rectangle.
Definition qwt_symbol.cpp:1434
QwtSymbol::setCachePolicy
void setCachePolicy(CachePolicy)
Definition qwt_symbol.cpp:899
QwtSymbol::setStyle
void setStyle(Style)
Definition qwt_symbol.cpp:1782
QwtSymbol::setPinPointEnabled
void setPinPointEnabled(bool)
Definition qwt_symbol.cpp:1278
QwtSymbol::~QwtSymbol
virtual ~QwtSymbol()
Destructor.
Definition qwt_symbol.cpp:886
QwtSymbol::boundingRect
virtual QRect boundingRect() const
Definition qwt_symbol.cpp:1637
QwtSymbol::setSvgDocument
void setSvgDocument(const QByteArray &)
Definition qwt_symbol.cpp:1044
QwtSymbol::drawSymbols
void drawSymbols(QPainter *, const QPolygonF &) const
Draw symbols at the specified points.
Definition qwt_symbol.h:251
QwtSymbol::Style
Style
Definition qwt_symbol.h:39
QwtSymbol::VLine
@ VLine
Vertical line.
Definition qwt_symbol.h:77
QwtSymbol::Ellipse
@ Ellipse
Ellipse or circle.
Definition qwt_symbol.h:44
QwtSymbol::LTriangle
@ LTriangle
Triangle pointing left.
Definition qwt_symbol.h:62
QwtSymbol::Star1
@ Star1
X combined with +.
Definition qwt_symbol.h:80
QwtSymbol::HLine
@ HLine
Horizontal line.
Definition qwt_symbol.h:74
QwtSymbol::Rect
@ Rect
Rectangle.
Definition qwt_symbol.h:47
QwtSymbol::Pixmap
@ Pixmap
Definition qwt_symbol.h:103
QwtSymbol::Triangle
@ Triangle
Triangle pointing upwards.
Definition qwt_symbol.h:53
QwtSymbol::SvgDocument
@ SvgDocument
Definition qwt_symbol.h:119
QwtSymbol::Hexagon
@ Hexagon
Hexagon.
Definition qwt_symbol.h:86
QwtSymbol::Diamond
@ Diamond
Diamond.
Definition qwt_symbol.h:50
QwtSymbol::Graphic
@ Graphic
Definition qwt_symbol.h:111
QwtSymbol::Path
@ Path
Definition qwt_symbol.h:95
QwtSymbol::XCross
@ XCross
Diagonal cross (X)
Definition qwt_symbol.h:71
QwtSymbol::Cross
@ Cross
Cross (+)
Definition qwt_symbol.h:68
QwtSymbol::UTriangle
@ UTriangle
Triangle pointing upwards.
Definition qwt_symbol.h:59
QwtSymbol::NoSymbol
@ NoSymbol
No Style. The symbol cannot be drawn.
Definition qwt_symbol.h:41
QwtSymbol::DTriangle
@ DTriangle
Triangle pointing downwards.
Definition qwt_symbol.h:56
QwtSymbol::RTriangle
@ RTriangle
Triangle pointing right.
Definition qwt_symbol.h:65
QwtSymbol::Star2
@ Star2
Six-pointed star.
Definition qwt_symbol.h:83
QwtSymbol::setPath
void setPath(const QPainterPath &)
Set a painter path as symbol.
Definition qwt_symbol.cpp:966
QwtSymbol::setPixmap
void setPixmap(const QPixmap &)
Definition qwt_symbol.cpp:992
QwtSymbol::QwtSymbol
QwtSymbol(Style=NoSymbol)
Definition qwt_symbol.cpp:843
QwtSymbol::invalidateCache
void invalidateCache()
Definition qwt_symbol.cpp:1770
QwtSymbol::setPinPoint
void setPinPoint(const QPointF &pos, bool enable=true)
Set and enable a pin point.
Definition qwt_symbol.cpp:1249
QwtSymbol::setSize
void setSize(const QSize &)
Definition qwt_symbol.cpp:1081
QwtSymbol::isPinPointEnabled
bool isPinPointEnabled() const
Definition qwt_symbol.cpp:1291
QwtSymbol::setGraphic
void setGraphic(const QwtGraphic &)
Definition qwt_symbol.cpp:1017
QwtSymbol::size
const QSize & size() const
Definition qwt_symbol.cpp:1094
QwtSymbol::renderSymbols
virtual void renderSymbols(QPainter *, const QPointF *, int numPoints) const
Definition qwt_symbol.cpp:1513
QwtSymbol::CachePolicy
CachePolicy
Definition qwt_symbol.h:151
QwtSymbol::AutoCache
@ AutoCache
Definition qwt_symbol.h:164
QwtSymbol::Cache
@ Cache
Always use a pixmap cache.
Definition qwt_symbol.h:156
QwtSymbol::cachePolicy
CachePolicy cachePolicy() const
Definition qwt_symbol.cpp:913
QwtSymbol::graphic
const QwtGraphic & graphic() const
Definition qwt_symbol.cpp:1027
QwtSymbol::pen
const QPen & pen() const
Definition qwt_symbol.cpp:1171
QwtSymbol::pinPoint
QPointF pinPoint() const
Definition qwt_symbol.cpp:1267
QwtSymbol::setBrush
void setBrush(const QBrush &)
Assign a brush.
Definition qwt_symbol.cpp:1107