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 }

Generated on Mon Sep 17 16:16:50 2007 for KD Chart 2 by  doxygen 1.5.1