KDChartPlotter_p.cpp

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

Klarälvdalens Datakonsult AB (KDAB)
Qt-related services and products
http://www.kdab.com/
http://www.kdab.com/products/kd-chart/