/* -*- C++ -*- This file is part of the KDE libraries Copyright (C) 2003 Jason Harris 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 #include #include #include #include "kplotpoint.h" #include "kplotwidget.h" class KPlotObject::Private { public: Private( KPlotObject * qq ) : q( qq ) { } ~Private() { qDeleteAll( pList ); } KPlotObject *q; QList 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; ipList.size(); ++i ) { if ( d->pList[i]->barWidth() == 0.0 ) { if ( ipList.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 ); } } }