# KDChartPlotter_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 "KDChartPlotter.h"
    00031
    00032 #include "KDChartPlotter_p.h"
    00033
    00034 #include "KDChartValueTrackerAttributes.h"
    00035
    00036 using namespace KDChart;
    00037
    00038 Plotter::Private::Private( const Private& rhs )
    00039     : AbstractCartesianDiagram::Private( rhs )
    00040 {
    00041 }
    00042
    00043 void Plotter::Private::paintPolyline(
    00044     PaintContext* ctx,
    00045     const QBrush& brush, const QPen& pen,
    00046     const QPolygonF& points ) const
    00047 {
    00048     ctx->painter()->setBrush( brush );
    00049     ctx->painter()->setPen(
    00050         QPen( pen.color(),
    00051               pen.width(),
    00052               pen.style(),
    00053               Qt::FlatCap,
    00054               Qt::MiterJoin ) );
    00055 #if QT_VERSION > 0x040299
    00056     ctx->painter()->drawPolyline( points );
    00057 #else
    00058     // FIXME (Mirko) verify, this sounds reverse-logical
    00059     // For Qt versions older than 4.3 drawPolyline is VERY slow
    00060     // so we use traditional line segments drawing instead then.
    00061     for (int i = 0; i < points.size()-1; ++i)
    00062         ctx->painter()->drawLine( points.at(i), points.at(i+1) );
    00063 #endif
    00064 }
    00065
    00071 const QPointF Plotter::PlotterType::project(
    00072     QPointF point, QPointF maxLimits,
    00073     double z, const QModelIndex& index ) const
    00074 {
    00075     Q_UNUSED( maxLimits );
    00076     ThreeDLineAttributes td = diagram()->threeDLineAttributes( index );
    00077
    00078     //Pending Michel FIXME - the rotation does not work as expected atm
    00079     double xrad = DEGTORAD( td.lineXRotation() );
    00080     double yrad = DEGTORAD( td.lineYRotation() );
    00081     QPointF ret = QPointF(point.x()*cos( yrad ) + z * sin( yrad ) ,  point.y()*cos( xrad ) - z * sin( xrad ) );
    00082     return ret;
    00083 }
    00084
    00085 void Plotter::PlotterType::paintThreeDLines(
    00086     PaintContext* ctx, const QModelIndex& index,
    00087     const QPointF& from, const QPointF& to, const double depth  )
    00088 {
    00089     // retrieve the boundaries
    00090     const QPair< QPointF, QPointF > boundaries = diagram()->dataBoundaries();
    00091     const QPointF& maxLimits = boundaries.second;
    00092     const QPointF topLeft = project( from, maxLimits, depth, index  );
    00093     const QPointF topRight = project ( to, maxLimits, depth, index  );
    00094
    00095     const QPolygonF segment = QPolygonF() << from << topLeft << topRight << to;
    00096     const QBrush indexBrush ( diagram()->brush( index ) );
    00097     const PainterSaver painterSaver( ctx->painter() );
    00098
    00099     if( diagram()->antiAliasing() )
    00100         ctx->painter()->setRenderHint( QPainter::Antialiasing );
    00101
    00102     ctx->painter()->setBrush( indexBrush );
    00103     ctx->painter()->setPen( diagram()->pen( index ) ) ;
    00104
    00105     reverseMapper().addPolygon( index.row(), index.column(), segment );
    00106     ctx->painter()->drawPolygon( segment );
    00107 }
    00108
    00109 // this method is factored out from LineDiagram::paint, and contains
    00110 // the common parts of the method that  previously implemented all
    00111 // chart types in one
    00112 void Plotter::PlotterType::paintElements(
    00113     PaintContext* ctx,
    00114     DataValueTextInfoList& list,
    00115     LineAttributesInfoList& lineList,
    00116     LineAttributes::MissingValuesPolicy policy )
    00117 {
    00118     Q_UNUSED( policy );
    00119     // paint all lines and their attributes
    00120     PainterSaver painterSaver( ctx->painter() );
    00121     if ( diagram()->antiAliasing() )
    00122         ctx->painter()->setRenderHint ( QPainter::Antialiasing );
    00123     LineAttributesInfoListIterator itline ( lineList );
    00124
    00125     QBrush curBrush;
    00126     QPen curPen;
    00127     QPolygonF points;
    00128     while ( itline.hasNext() ) {
    00129         const LineAttributesInfo& lineInfo = itline.next();
    00130         const QModelIndex& index = lineInfo.index;
    00131         const ThreeDLineAttributes td = diagram()->threeDLineAttributes( index );
    00132         const ValueTrackerAttributes vt = diagram()->valueTrackerAttributes( index );
    00133
    00134         if( td.isEnabled() ){
    00135             paintThreeDLines( ctx, index, lineInfo.value, lineInfo.nextValue, td.depth() );
    00136         } else {
    00137             const QBrush br( diagram()->brush( index ) );
    00138             const QPen pn( diagram()->pen( index ) );
    00139             if( points.count() && points.last() == lineInfo.value && curBrush == br && curPen == pn ) {
    00140                 // line goes from last value in points to lineInfo.nextValue
    00141                 reverseMapper().addLine( lineInfo.index.row(), lineInfo.index.column(), points.last(), lineInfo.nextValue );
    00142                 points << lineInfo.nextValue;
    00143             } else {
    00144                 if( points.count() )
    00145                     paintPolyline( ctx, curBrush, curPen, points );
    00146                 curBrush = br;
    00147                 curPen   = pn;
    00148                 points.clear();
    00149                 // line goes from lineInfo.value to lineInfo,nextValue
    00150                 reverseMapper().addLine( lineInfo.index.row(), lineInfo.index.column(), lineInfo.value, lineInfo.nextValue );
    00151                 points << lineInfo.value << lineInfo.nextValue;
    00152             }
    00153         }
    00154
    00155         if( vt.isEnabled() )
    00156             paintValueTracker( ctx, vt, lineInfo.value );
    00157     }
    00158     if( points.count() )
    00159         paintPolyline( ctx, curBrush, curPen, points );
    00160     // paint all data value texts and the point markers
    00161     paintDataValueTextsAndMarkers( diagram(), ctx, list, true );
    00162 }
    00163
    00164 AttributesModel* Plotter::PlotterType::attributesModel() const
    00165 {
    00166     return m_private->attributesModel;
    00167 }
    00168
    00169 #if 0
    00170 QModelIndex LineDiagram::LineDiagramType::attributesModelRootIndex() const
    00171 {
    00172     return m_private->diagram->attributesModelRootIndex();
    00173 }
    00174
    00175 int LineDiagram::LineDiagramType::datasetDimension() const
    00176 {
    00177     return m_private->datasetDimension;
    00178 }
    00179 #endif
    00180
    00181 ReverseMapper& Plotter::PlotterType::reverseMapper()
    00182 {
    00183     return m_private->reverseMapper;
    00184 }
    00185
    00186 #if 0
    00187 LineAttributes::MissingValuesPolicy LineDiagram::LineDiagramType::getCellValues(
    00188     int row, int column,
    00189     bool shiftCountedXValuesByHalfSection,
    00190     double& valueX, double& valueY ) const
    00191 {
    00192     return m_private->diagram->getCellValues( row, column, shiftCountedXValuesByHalfSection,
    00193                                               valueX, valueY );
    00194 }
    00195
    00196 double LineDiagram::LineDiagramType::valueForCellTesting(
    00197     int row, int column,
    00198     bool& bOK,
    00199     bool showHiddenCellsAsInvalid) const
    00200 {
    00201     return m_private->diagram->valueForCellTesting( row, column, bOK, showHiddenCellsAsInvalid );
    00202 }
    00203 #endif
    00204
    00205 Plotter* Plotter::PlotterType::diagram() const
    00206 {
    00207     return m_private->diagram;
    00208 }
    00209
    00210 void Plotter::PlotterType::paintAreas(
    00211     PaintContext* ctx,
    00212     const QModelIndex& index, const QList< QPolygonF >& areas,
    00213     const uint transparency )
    00214 {
    00215     QColor trans = diagram()->brush( index ).color();
    00216     trans.setAlpha( transparency );
    00217     QPen indexPen = diagram()->pen(index);
    00218     indexPen.setColor( trans );
    00219     const PainterSaver painterSaver( ctx->painter() );
    00220
    00221     if( diagram()->antiAliasing() )
    00222         ctx->painter()->setRenderHint( QPainter::Antialiasing );
    00223
    00224     ctx->painter()->setPen( indexPen );
    00225     ctx->painter()->setBrush( trans );
    00226
    00227     QPainterPath path;
    00228     for( int i = 0; i < areas.count(); ++i )
    00229     {
    00230         const QPolygonF& p = areas[ i ];
    00231         path.addPolygon( p );
    00232         reverseMapper().addPolygon( index.row(), index.column(), p );
    00233         path.closeSubpath();
    00234     }
    00235     ctx->painter()->drawPath( path );
    00236 }
    00237
    00238 #if 0
    00239 double LineDiagram::LineDiagramType::valueForCell( int row, int column )
    00240 {
    00241     return diagram()->valueForCell( row, column );
    00242 }
    00243 #endif
    00244
    00245 void Plotter::PlotterType::appendDataValueTextInfoToList(
    00246             AbstractDiagram * diagram,
    00247             DataValueTextInfoList & list,
    00248             const QModelIndex & index,
    00249             const PositionPoints& points,
    00250             const Position& autoPositionPositive,
    00251             const Position& autoPositionNegative,
    00252             const qreal value )
    00253 {
    00254     Q_UNUSED( autoPositionNegative );
    00255     m_private->appendDataValueTextInfoToList( diagram, list, index, points,
    00256                                               autoPositionPositive, autoPositionPositive, value );
    00257 }
    00258
    00259 void Plotter::PlotterType::paintValueTracker( PaintContext* ctx, const ValueTrackerAttributes& vt, const QPointF& at )
    00260 {
    00261     CartesianCoordinatePlane* plane = qobject_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() );
    00262     if( !plane )
    00263         return;
    00264
    00265     DataDimensionsList gridDimensions = ctx->coordinatePlane()->gridDimensionsList();
    00266     const QPointF bottomLeft( ctx->coordinatePlane()->translate(
    00267                               QPointF( plane->isHorizontalRangeReversed() ?
    00268                                            gridDimensions.at( 0 ).end :
    00269                                            gridDimensions.at( 0 ).start,
    00270                                        plane->isVerticalRangeReversed() ?
    00271                                            gridDimensions.at( 1 ).end :
    00272                                            gridDimensions.at( 1 ).start ) ) );
    00273     const QPointF markerPoint = at;
    00274     const QPointF ordinatePoint( bottomLeft.x(), at.y() );
    00275     const QPointF abscissaPoint( at.x(), bottomLeft.y() );
    00276
    00277     const QSizeF markerSize = vt.markerSize();
    00278     const QRectF ellipseMarker = QRectF( at.x() - markerSize.width() / 2,
    00279                                          at.y() - markerSize.height() / 2,
    00280                                          markerSize.width(), markerSize.height() );
    00281
    00282     const QPointF ordinateMarker[3] = {
    00283         QPointF( ordinatePoint.x(), at.y() + markerSize.height() / 2 ),
    00284         QPointF( ordinatePoint.x() + markerSize.width() / 2, at.y() ),
    00285         QPointF( ordinatePoint.x(), at.y() - markerSize.height() / 2 )
    00286     };
    00287
    00288     const QPointF abscissaMarker[3] = {
    00289         QPointF( at.x() + markerSize.width() / 2, abscissaPoint.y() ),
    00290         QPointF( at.x(), abscissaPoint.y() - markerSize.height() / 2 ),
    00291         QPointF( at.x() - markerSize.width() / 2, abscissaPoint.y() )
    00292     };
    00293
    00294     QPointF topLeft = ordinatePoint;
    00295     QPointF bottomRightOffset = abscissaPoint - topLeft;
    00296     QSizeF size( bottomRightOffset.x(), bottomRightOffset.y() );
    00297     QRectF area( topLeft, size );
    00298
    00299     PainterSaver painterSaver( ctx->painter() );
    00300     ctx->painter()->setPen( vt.pen() );
    00301     ctx->painter()->setBrush( QBrush() );
    00302
    00303     ctx->painter()->drawLine( markerPoint, ordinatePoint );
    00304     ctx->painter()->drawLine( markerPoint, abscissaPoint );
    00305
    00306     ctx->painter()->fillRect( area, vt.areaBrush() );
    00307
    00308     ctx->painter()->drawEllipse( ellipseMarker );
    00309
    00310     ctx->painter()->setBrush( vt.pen().color() );
    00311     ctx->painter()->drawPolygon( ordinateMarker, 3 );
    00312     ctx->painter()->drawPolygon( abscissaMarker, 3 );
    00313 }
    00314
    00315 CartesianDiagramDataCompressor& Plotter::PlotterType::compressor() const
    00316 {
    00317     return m_private->compressor;
    00318 }