# KDChartLineDiagram_p.cpp

Go to the documentation of this file.

    00001 /* -*- Mode: C++ -*-
    00002    KDChart - a multi-platform charting engine
    00003    */
    00004
    00005 /****************************************************************************
    00006  ** Copyright (C) 2005-2007 Klarälvdalens Datakonsult AB.  All rights reserved.
    00007  **
    00008  ** This file is part of the KD Chart library.
    00009  **
    00010  ** This file may be distributed and/or modified under the terms of the
    00011  ** GNU General Public License version 2 as published by the Free Software
    00012  ** Foundation and appearing in the file LICENSE.GPL included in the
    00013  ** packaging of this file.
    00014  **
    00015  ** Licensees holding valid commercial KD Chart licenses may use this file in
    00016  ** accordance with the KD Chart Commercial License Agreement provided with
    00017  ** the Software.
    00018  **
    00019  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    00020  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    00021  **
    00022  ** See http://www.kdab.net/kdchart for
    00023  **   information about KD Chart Commercial License Agreements.
    00024  **
    00025  ** Contact info@kdab.net if any conditions of this
    00026  ** licensing are not clear to you.
    00027  **
    00028  **********************************************************************/
    00029
    00030 #include "KDChartLineDiagram.h"
    00031 #include "KDChartDataValueAttributes.h"
    00032
    00033 #include "KDChartLineDiagram_p.h"
    00034
    00035 using namespace KDChart;
    00036
    00037 LineDiagram::Private::Private( const Private& rhs )
    00038     : AbstractCartesianDiagram::Private( rhs )
    00039 {
    00040 }
    00041
    00042 void LineDiagram::Private::paintPolyline(
    00043     PaintContext* ctx,
    00044     const QBrush& brush, const QPen& pen,
    00045     const QPolygonF& points ) const
    00046 {
    00047     ctx->painter()->setBrush( brush );
    00048     ctx->painter()->setPen(
    00049         QPen( pen.color(),
    00050               pen.width(),
    00051               pen.style(),
    00052               Qt::FlatCap,
    00053               Qt::MiterJoin ) );
    00054 #if QT_VERSION > 0x040299
    00055     ctx->painter()->drawPolyline( points );
    00056 #else
    00057     // FIXME (Mirko) verify, this sounds reverse-logical
    00058     // For Qt versions older than 4.3 drawPolyline is VERY slow
    00059     // so we use traditional line segments drawing instead then.
    00060     for (int i = 0; i < points.size()-1; ++i)
    00061         ctx->painter()->drawLine( points.at(i), points.at(i+1) );
    00062 #endif
    00063 }
    00064
    00070 const QPointF LineDiagram::LineDiagramType::project(
    00071     QPointF point, QPointF maxLimits,
    00072     double z, const QModelIndex& index ) const
    00073 {
    00074     Q_UNUSED( maxLimits );
    00075     ThreeDLineAttributes td = diagram()->threeDLineAttributes( index );
    00076
    00077     //Pending Michel FIXME - the rotation does not work as expected atm
    00078     double xrad = DEGTORAD( td.lineXRotation() );
    00079     double yrad = DEGTORAD( td.lineYRotation() );
    00080     QPointF ret = QPointF(point.x()*cos( yrad ) + z * sin( yrad ) ,  point.y()*cos( xrad ) - z * sin( xrad ) );
    00081     return ret;
    00082 }
    00083
    00084 void LineDiagram::LineDiagramType::paintThreeDLines(
    00085     PaintContext* ctx, const QModelIndex& index,
    00086     const QPointF& from, const QPointF& to, const double depth  )
    00087 {
    00088     // retrieve the boundaries
    00089     const QPair< QPointF, QPointF > boundaries = diagram()->dataBoundaries();
    00090     const QPointF& maxLimits = boundaries.second;
    00091     const QPointF topLeft = project( from, maxLimits, depth, index  );
    00092     const QPointF topRight = project ( to, maxLimits, depth, index  );
    00093
    00094     const QPolygonF segment = QPolygonF() << from << topLeft << topRight << to;
    00095     const QBrush indexBrush ( diagram()->brush( index ) );
    00096     const PainterSaver painterSaver( ctx->painter() );
    00097
    00098     if( diagram()->antiAliasing() )
    00099         ctx->painter()->setRenderHint( QPainter::Antialiasing );
    00100
    00101     ctx->painter()->setBrush( indexBrush );
    00102     ctx->painter()->setPen( diagram()->pen( index ) ) ;
    00103
    00104     reverseMapper().addPolygon( index.row(), index.column(), segment );
    00105     ctx->painter()->drawPolygon( segment );
    00106 }
    00107
    00108 // this method is factored out from LineDiagram::paint, and contains
    00109 // the common parts of the method that  previously implemented all
    00110 // chart types in one
    00111 void LineDiagram::LineDiagramType::paintElements(
    00112     PaintContext* ctx,
    00113     DataValueTextInfoList& list,
    00114     LineAttributesInfoList& lineList,
    00115     LineAttributes::MissingValuesPolicy policy )
    00116 {
    00117     Q_UNUSED( policy );
    00118     // paint all lines and their attributes
    00119     PainterSaver painterSaver( ctx->painter() );
    00120     if ( diagram()->antiAliasing() )
    00121         ctx->painter()->setRenderHint ( QPainter::Antialiasing );
    00122     LineAttributesInfoListIterator itline ( lineList );
    00123
    00124     QBrush curBrush;
    00125     QPen curPen;
    00126     QPolygonF points;
    00127     while ( itline.hasNext() ) {
    00128         const LineAttributesInfo& lineInfo = itline.next();
    00129         const QModelIndex& index = lineInfo.index;
    00130         const ThreeDLineAttributes td = diagram()->threeDLineAttributes( index );
    00131         const ValueTrackerAttributes vt = diagram()->valueTrackerAttributes( index );
    00132
    00133         if( td.isEnabled() ){
    00134             paintThreeDLines( ctx, index, lineInfo.value, lineInfo.nextValue, td.depth() );
    00135         } else {
    00136             const QBrush br( diagram()->brush( index ) );
    00137             const QPen pn( diagram()->pen( index ) );
    00138             if( points.count() && points.last() == lineInfo.value && curBrush == br && curPen == pn ) {
    00139                 // line goes from last value in points to lineInfo.nextValue
    00140                 reverseMapper().addLine( lineInfo.index.row(), lineInfo.index.column(), points.last(), lineInfo.nextValue );
    00141                 points << lineInfo.nextValue;
    00142             } else {
    00143                 if( points.count() )
    00144                     paintPolyline( ctx, curBrush, curPen, points );
    00145                 curBrush = br;
    00146                 curPen   = pn;
    00147                 points.clear();
    00148                 // line goes from lineInfo.value to lineInfo,nextValue
    00149                 reverseMapper().addLine( lineInfo.index.row(), lineInfo.index.column(), lineInfo.value, lineInfo.nextValue );
    00150                 points << lineInfo.value << lineInfo.nextValue;
    00151             }
    00152         }
    00153
    00154         if( vt.isEnabled() )
    00155             paintValueTracker( ctx, vt, lineInfo.value );
    00156     }
    00157     if( points.count() )
    00158         paintPolyline( ctx, curBrush, curPen, points );
    00159     // paint all data value texts and the point markers
    00160     paintDataValueTextsAndMarkers( diagram(), ctx, list, true );
    00161 }
    00162
    00163 AttributesModel* LineDiagram::LineDiagramType::attributesModel() const
    00164 {
    00165     return m_private->attributesModel;
    00166 }
    00167
    00168 QModelIndex LineDiagram::LineDiagramType::attributesModelRootIndex() const
    00169 {
    00170     return m_private->diagram->attributesModelRootIndex();
    00171 }
    00172
    00173 int LineDiagram::LineDiagramType::datasetDimension() const
    00174 {
    00175     return m_private->datasetDimension;
    00176 }
    00177
    00178 ReverseMapper& LineDiagram::LineDiagramType::reverseMapper()
    00179 {
    00180     return m_private->reverseMapper;
    00181 }
    00182
    00183 LineAttributes::MissingValuesPolicy LineDiagram::LineDiagramType::getCellValues(
    00184     int row, int column,
    00185     bool shiftCountedXValuesByHalfSection,
    00186     double& valueX, double& valueY ) const
    00187 {
    00188     return m_private->diagram->getCellValues( row, column, shiftCountedXValuesByHalfSection,
    00189                                               valueX, valueY );
    00190 }
    00191
    00192 double LineDiagram::LineDiagramType::valueForCellTesting(
    00193     int row, int column,
    00194     bool& bOK,
    00195     bool showHiddenCellsAsInvalid) const
    00196 {
    00197     return m_private->diagram->valueForCellTesting( row, column, bOK, showHiddenCellsAsInvalid );
    00198 }
    00199
    00200 LineDiagram* LineDiagram::LineDiagramType::diagram() const
    00201 {
    00202     return m_private->diagram;
    00203 }
    00204
    00205 void LineDiagram::LineDiagramType::paintAreas(
    00206     PaintContext* ctx,
    00207     const QModelIndex& index, const QList< QPolygonF >& areas,
    00208     const uint transparency )
    00209 {
    00210     QColor trans = diagram()->brush( index ).color();
    00211     trans.setAlpha( transparency );
    00212     QPen indexPen = diagram()->pen(index);
    00213     indexPen.setColor( trans );
    00214     const PainterSaver painterSaver( ctx->painter() );
    00215
    00216     if( diagram()->antiAliasing() )
    00217         ctx->painter()->setRenderHint( QPainter::Antialiasing );
    00218
    00219     ctx->painter()->setPen( indexPen );
    00220     ctx->painter()->setBrush( trans );
    00221
    00222     QPainterPath path;
    00223     for( int i = 0; i < areas.count(); ++i )
    00224     {
    00225         const QPolygonF& p = areas[ i ];
    00226         path.addPolygon( p );
    00227         reverseMapper().addPolygon( index.row(), index.column(), p );
    00228         path.closeSubpath();
    00229     }
    00230     ctx->painter()->drawPath( path );
    00231 }
    00232
    00233 double LineDiagram::LineDiagramType::valueForCell( int row, int column )
    00234 {
    00235     return diagram()->valueForCell( row, column );
    00236 }
    00237
    00238 void LineDiagram::LineDiagramType::appendDataValueTextInfoToList(
    00239             AbstractDiagram * diagram,
    00240             DataValueTextInfoList & list,
    00241             const QModelIndex & index,
    00242             const PositionPoints& points,
    00243             const Position& autoPositionPositive,
    00244             const Position& autoPositionNegative,
    00245             const qreal value )
    00246 {
    00247     Q_UNUSED( autoPositionNegative );
    00248     m_private->appendDataValueTextInfoToList( diagram, list, index, points,
    00249                                               autoPositionPositive, autoPositionPositive, value );
    00250 }
    00251
    00252 void LineDiagram::LineDiagramType::paintValueTracker( PaintContext* ctx, const ValueTrackerAttributes& vt, const QPointF& at )
    00253 {
    00254     CartesianCoordinatePlane* plane = qobject_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() );
    00255     if( !plane )
    00256         return;
    00257
    00258     DataDimensionsList gridDimensions = ctx->coordinatePlane()->gridDimensionsList();
    00259     const QPointF bottomLeft( ctx->coordinatePlane()->translate(
    00260                               QPointF( plane->isHorizontalRangeReversed() ?
    00261                                            gridDimensions.at( 0 ).end :
    00262                                            gridDimensions.at( 0 ).start,
    00263                                        plane->isVerticalRangeReversed() ?
    00264                                            gridDimensions.at( 1 ).end :
    00265                                            gridDimensions.at( 1 ).start ) ) );
    00266     const QPointF markerPoint = at;
    00267     const QPointF ordinatePoint( bottomLeft.x(), at.y() );
    00268     const QPointF abscissaPoint( at.x(), bottomLeft.y() );
    00269
    00270     const QSizeF markerSize = vt.markerSize();
    00271     const QRectF ellipseMarker = QRectF( at.x() - markerSize.width() / 2,
    00272                                          at.y() - markerSize.height() / 2,
    00273                                          markerSize.width(), markerSize.height() );
    00274
    00275     const QPointF ordinateMarker[3] = {
    00276         QPointF( ordinatePoint.x(), at.y() + markerSize.height() / 2 ),
    00277         QPointF( ordinatePoint.x() + markerSize.width() / 2, at.y() ),
    00278         QPointF( ordinatePoint.x(), at.y() - markerSize.height() / 2 )
    00279     };
    00280
    00281     const QPointF abscissaMarker[3] = {
    00282         QPointF( at.x() + markerSize.width() / 2, abscissaPoint.y() ),
    00283         QPointF( at.x(), abscissaPoint.y() - markerSize.height() / 2 ),
    00284         QPointF( at.x() - markerSize.width() / 2, abscissaPoint.y() )
    00285     };
    00286
    00287     QPointF topLeft = ordinatePoint;
    00288     QPointF bottomRightOffset = abscissaPoint - topLeft;
    00289     QSizeF size( bottomRightOffset.x(), bottomRightOffset.y() );
    00290     QRectF area( topLeft, size );
    00291
    00292     PainterSaver painterSaver( ctx->painter() );
    00293     ctx->painter()->setPen( vt.pen() );
    00294     ctx->painter()->setBrush( QBrush() );
    00295
    00296     ctx->painter()->drawLine( markerPoint, ordinatePoint );
    00297     ctx->painter()->drawLine( markerPoint, abscissaPoint );
    00298
    00299     ctx->painter()->fillRect( area, vt.areaBrush() );
    00300
    00301     ctx->painter()->drawEllipse( ellipseMarker );
    00302
    00303     ctx->painter()->setBrush( vt.pen().color() );
    00304     ctx->painter()->drawPolygon( ordinateMarker, 3 );
    00305     ctx->painter()->drawPolygon( abscissaMarker, 3 );
    00306 }
    00307
    00308 CartesianDiagramDataCompressor& LineDiagram::LineDiagramType::compressor() const
    00309 {
    00310     return m_private->compressor;
    00311 }