kdelibs/kdeui/plotting/kplotobject.cpp
2014-11-13 01:04:59 +02:00

391 lines
11 KiB
C++

/* -*- C++ -*-
This file is part of the KDE libraries
Copyright (C) 2003 Jason Harris <kstars@30doradus.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kplotobject.h"
#include <QtAlgorithms>
#include <QPainter>
#include <kdebug.h>
#include "kplotpoint.h"
#include "kplotwidget.h"
class KPlotObject::Private
{
public:
Private( KPlotObject * qq )
: q( qq )
{
}
~Private()
{
qDeleteAll( pList );
}
KPlotObject *q;
QList<KPlotPoint*> pList;
PlotTypes type;
PointStyle pointStyle;
double size;
QPen pen, linePen, barPen, labelPen;
QBrush brush, barBrush;
};
KPlotObject::KPlotObject( const QColor &c, PlotType t, double size, PointStyle ps )
: d( new Private( this ) )
{
//By default, all pens and brushes are set to the given color
setBrush( c );
setBarBrush( c );
setPen( QPen( brush(), 1 ) );
setLinePen( pen() );
setBarPen( pen() );
setLabelPen( pen() );
d->type |= t;
setSize( size );
setPointStyle( ps );
}
KPlotObject::~KPlotObject()
{
delete d;
}
KPlotObject::PlotTypes KPlotObject::plotTypes() const
{
return d->type;
}
void KPlotObject::setShowPoints( bool b )
{
if ( b )
{
d->type |= KPlotObject::Points;
}
else
{
d->type &= ~KPlotObject::Points;
}
}
void KPlotObject::setShowLines( bool b )
{
if ( b )
{
d->type |= KPlotObject::Lines;
}
else
{
d->type &= ~KPlotObject::Lines;
}
}
void KPlotObject::setShowBars( bool b )
{
if ( b )
{
d->type |= KPlotObject::Bars;
}
else
{
d->type &= ~KPlotObject::Bars;
}
}
double KPlotObject::size() const
{
return d->size;
}
void KPlotObject::setSize( double s )
{
d->size = s;
}
KPlotObject::PointStyle KPlotObject::pointStyle() const
{
return d->pointStyle;
}
void KPlotObject::setPointStyle( PointStyle p )
{
d->pointStyle = p;
}
const QPen& KPlotObject::pen() const
{
return d->pen;
}
void KPlotObject::setPen( const QPen &p )
{
d->pen = p;
}
const QPen& KPlotObject::linePen() const
{
return d->linePen;
}
void KPlotObject::setLinePen( const QPen &p )
{
d->linePen = p;
}
const QPen& KPlotObject::barPen() const
{
return d->barPen;
}
void KPlotObject::setBarPen( const QPen &p )
{
d->barPen = p;
}
const QPen& KPlotObject::labelPen() const
{
return d->labelPen;
}
void KPlotObject::setLabelPen( const QPen &p )
{
d->labelPen = p;
}
const QBrush KPlotObject::brush() const
{
return d->brush;
}
void KPlotObject::setBrush( const QBrush &b )
{
d->brush = b;
}
const QBrush KPlotObject::barBrush() const
{
return d->barBrush;
}
void KPlotObject::setBarBrush( const QBrush &b )
{
d->barBrush = b;
}
QList< KPlotPoint* > KPlotObject::points() const
{
return d->pList;
}
void KPlotObject::addPoint( const QPointF &p, const QString &label, double barWidth )
{
addPoint( new KPlotPoint( p.x(), p.y(), label, barWidth ) );
}
void KPlotObject::addPoint( KPlotPoint *p )
{
if ( !p )
return;
d->pList.append( p );
}
void KPlotObject::addPoint( double x, double y, const QString &label, double barWidth )
{
addPoint( new KPlotPoint( x, y, label, barWidth ) );
}
void KPlotObject::removePoint( int index ) {
if ( ( index < 0 ) || ( index >= d->pList.count() ) ) {
kWarning() << "KPlotObject::removePoint(): index " << index << " out of range!";
return;
}
d->pList.removeAt( index );
}
void KPlotObject::clearPoints()
{
qDeleteAll( d->pList );
d->pList.clear();
}
void KPlotObject::draw( QPainter *painter, KPlotWidget *pw ) {
//Order of drawing determines z-distance: Bars in the back, then lines,
//then points, then labels.
if ( d->type & Bars ) {
painter->setPen( barPen() );
painter->setBrush( barBrush() );
double w = 0;
for ( int i=0; i<d->pList.size(); ++i ) {
if ( d->pList[i]->barWidth() == 0.0 ) {
if ( i<d->pList.size()-1 )
w = d->pList[i+1]->x() - d->pList[i]->x();
//For the last bin, we'll just keep the previous width
} else {
w = d->pList[i]->barWidth();
}
QPointF pp = d->pList[i]->position();
QPointF p1( pp.x() - 0.5*w, 0.0 );
QPointF p2( pp.x() + 0.5*w, pp.y() );
QPointF sp1 = pw->mapToWidget( p1 );
QPointF sp2 = pw->mapToWidget( p2 );
QRectF barRect = QRectF( sp1.x(), sp1.y(), sp2.x()-sp1.x(), sp2.y()-sp1.y() ).normalized();
painter->drawRect( barRect );
pw->maskRect( barRect, 0.25 );
}
}
//Draw lines:
if ( d->type & Lines ) {
painter->setPen( linePen() );
QPointF Previous = QPointF(); //Initialize to null
foreach ( KPlotPoint *pp, d->pList ) {
//q is the position of the point in screen pixel coordinates
QPointF q = pw->mapToWidget( pp->position() );
if ( ! Previous.isNull() ) {
painter->drawLine( Previous, q );
pw->maskAlongLine( Previous, q );
}
Previous = q;
}
}
//Draw points:
if ( d->type & Points ) {
foreach( KPlotPoint *pp, d->pList ) {
//q is the position of the point in screen pixel coordinates
QPointF q = pw->mapToWidget( pp->position() );
if ( pw->pixRect().contains( q.toPoint(), false ) ) {
double x1 = q.x() - size();
double y1 = q.y() - size();
QRectF qr = QRectF( x1, y1, 2*size(), 2*size() );
//Mask out this rect in the plot for label avoidance
pw->maskRect( qr, 2.0 );
painter->setPen( pen() );
painter->setBrush( brush() );
switch ( pointStyle() ) {
case Circle:
painter->drawEllipse( qr );
break;
case Letter:
painter->drawText( qr, Qt::AlignCenter, pp->label().left(1) );
break;
case Triangle:
{
QPolygonF tri;
tri << QPointF( q.x() - size(), q.y() + size() )
<< QPointF( q.x(), q.y() - size() )
<< QPointF( q.x() + size(), q.y() + size() );
painter->drawPolygon( tri );
break;
}
case Square:
painter->drawRect( qr );
break;
case Pentagon:
{
QPolygonF pent;
pent << QPointF( q.x(), q.y() - size() )
<< QPointF( q.x() + size(), q.y() - 0.309*size() )
<< QPointF( q.x() + 0.588*size(), q.y() + size() )
<< QPointF( q.x() - 0.588*size(), q.y() + size() )
<< QPointF( q.x() - size(), q.y() - 0.309*size() );
painter->drawPolygon( pent );
break;
}
case Hexagon:
{
QPolygonF hex;
hex << QPointF( q.x(), q.y() + size() )
<< QPointF( q.x() + size(), q.y() + 0.5*size() )
<< QPointF( q.x() + size(), q.y() - 0.5*size() )
<< QPointF( q.x(), q.y() - size() )
<< QPointF( q.x() - size(), q.y() + 0.5*size() )
<< QPointF( q.x() - size(), q.y() - 0.5*size() );
painter->drawPolygon( hex );
break;
}
case Asterisk:
painter->drawLine( q, QPointF( q.x(), q.y() + size() ) );
painter->drawLine( q, QPointF( q.x() + size(), q.y() + 0.5*size() ) );
painter->drawLine( q, QPointF( q.x() + size(), q.y() - 0.5*size() ) );
painter->drawLine( q, QPointF( q.x(), q.y() - size() ) );
painter->drawLine( q, QPointF( q.x() - size(), q.y() + 0.5*size() ) );
painter->drawLine( q, QPointF( q.x() - size(), q.y() - 0.5*size() ) );
break;
case Star:
{
QPolygonF star;
star << QPointF( q.x(), q.y() - size() )
<< QPointF( q.x() + 0.2245*size(), q.y() - 0.309*size() )
<< QPointF( q.x() + size(), q.y() - 0.309*size() )
<< QPointF( q.x() + 0.363*size(), q.y() + 0.118*size() )
<< QPointF( q.x() + 0.588*size(), q.y() + size() )
<< QPointF( q.x(), q.y() + 0.382*size() )
<< QPointF( q.x() - 0.588*size(), q.y() + size() )
<< QPointF( q.x() - 0.363*size(), q.y() + 0.118*size() )
<< QPointF( q.x() - size(), q.y() - 0.309*size() )
<< QPointF( q.x() - 0.2245*size(), q.y() - 0.309*size() );
painter->drawPolygon( star );
break;
}
default:
break;
}
}
}
}
//Draw labels
painter->setPen( labelPen() );
foreach ( KPlotPoint *pp, d->pList ) {
QPoint q = pw->mapToWidget( pp->position() ).toPoint();
if ( pw->pixRect().contains(q, false) && ! pp->label().isEmpty() ) {
pw->placeLabel( painter, pp );
}
}
}