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

Generated on Thu Mar 4 23:19:12 2010 for KD Chart 2 by  doxygen 1.5.4