KD Chart 2  [rev.2.5]
PaintingHelpers_p.cpp
Go to the documentation of this file.
00001 #include "PaintingHelpers_p.h"
00002 
00003 #include "KDChartGlobal.h"
00004 
00005 #include "KDChartAbstractDiagram.h"
00006 #include "KDChartAbstractDiagram_p.h"
00007 #include "KDChartCartesianCoordinatePlane.h"
00008 #include "KDChartLineDiagram.h"
00009 #include "KDChartValueTrackerAttributes.h"
00010 #include "KDChartPaintContext.h"
00011 #include "KDChartPainterSaver_p.h"
00012 #include "KDChartPlotter.h"
00013 #include "KDChartPrintingParameters.h"
00014 #include "KDChartThreeDLineAttributes.h"
00015 #include "ReverseMapper.h"
00016 
00017 namespace KDChart {
00018 namespace PaintingHelpers {
00019 
00025 const QPointF project( const QPointF& point, const ThreeDLineAttributes& tdAttributes )
00026 {
00027     //Pending Michel FIXME - the rotation does not work as expected atm
00028     qreal xrad = DEGTORAD( tdAttributes.lineXRotation() );
00029     qreal yrad = DEGTORAD( tdAttributes.lineYRotation() );
00030     return QPointF( point.x() * cos( yrad ) + tdAttributes.depth() * sin( yrad ),
00031                     point.y() * cos( xrad ) - tdAttributes.depth() * sin( xrad ) );
00032 }
00033 
00034 void paintPolyline( PaintContext* ctx, const QBrush& brush, const QPen& pen, const QPolygonF& points )
00035 {
00036     ctx->painter()->setBrush( brush );
00037     ctx->painter()->setPen( PrintingParameters::scalePen(
00038         QPen( pen.color(), pen.width(), pen.style(), Qt::FlatCap, Qt::MiterJoin ) ) );
00039 #if QT_VERSION > 0x040299
00040     ctx->painter()->drawPolyline( points );
00041 #else
00042     // FIXME (Mirko) verify, this sounds reverse-logical
00043     // For Qt versions older than 4.3 drawPolyline is VERY slow
00044     // so we use traditional line segments drawing instead then.
00045     for ( int i = 0; i < points.size()-1; ++i ) {
00046         ctx->painter()->drawLine( points.at( i ), points.at( i + 1 ) );
00047     }
00048 #endif
00049 }
00050 
00051 void paintThreeDLines( PaintContext* ctx, AbstractDiagram *diagram, const QModelIndex& index,
00052                        const QPointF& from, const QPointF& to, const ThreeDLineAttributes& tdAttributes,
00053                        ReverseMapper* reverseMapper )
00054 {
00055     const QPointF topLeft = project( from, tdAttributes );
00056     const QPointF topRight = project ( to, tdAttributes );
00057     const QPolygonF segment = QPolygonF() << from << topLeft << topRight << to;
00058 
00059     QBrush indexBrush( diagram->brush( index ) );
00060     indexBrush = tdAttributes.threeDBrush( indexBrush, QRectF(topLeft, topRight) );
00061 
00062     const PainterSaver painterSaver( ctx->painter() );
00063 
00064     ctx->painter()->setRenderHint( QPainter::Antialiasing, diagram->antiAliasing() );
00065     ctx->painter()->setBrush( indexBrush );
00066     ctx->painter()->setPen( PrintingParameters::scalePen( diagram->pen( index ) ) );
00067 
00068     reverseMapper->addPolygon( index.row(), index.column(), segment );
00069     ctx->painter()->drawPolygon( segment );
00070 }
00071 
00072 void paintValueTracker( PaintContext* ctx, const ValueTrackerAttributes& vt, const QPointF& at )
00073 {
00074     CartesianCoordinatePlane* plane = qobject_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() );
00075     if( !plane )
00076         return;
00077 
00078     DataDimensionsList gridDimensions = ctx->coordinatePlane()->gridDimensionsList();
00079     const QPointF bottomLeft( ctx->coordinatePlane()->translate(
00080                               QPointF( plane->isHorizontalRangeReversed() ?
00081                                            gridDimensions.at( 0 ).end :
00082                                            gridDimensions.at( 0 ).start,
00083                                        plane->isVerticalRangeReversed() ?
00084                                            gridDimensions.at( 1 ).end :
00085                                            gridDimensions.at( 1 ).start ) ) );
00086     const QPointF topRight( ctx->coordinatePlane()->translate(
00087                             QPointF( plane->isHorizontalRangeReversed() ?
00088                                          gridDimensions.at( 0 ).start :
00089                                          gridDimensions.at( 0 ).end,
00090                                      plane->isVerticalRangeReversed() ?
00091                                          gridDimensions.at( 1 ).start :
00092                                          gridDimensions.at( 1 ).end ) ) );
00093     const QPointF markerPoint = at;
00094 
00095     QPointF startPoint;
00096     if ( vt.orientations() & Qt::Horizontal ) {
00097         startPoint = QPointF( bottomLeft.x(), at.y() );
00098     } else {
00099         startPoint = QPointF( at.x(), topRight.y() );
00100     }
00101 
00102     QPointF endPoint;
00103     if ( vt.orientations() & Qt::Vertical ) {
00104         endPoint = QPointF( at.x(), bottomLeft.y() );
00105     } else {
00106         endPoint = QPointF( topRight.x(), at.y() );
00107     }
00108 
00109     const QSizeF markerSize = vt.markerSize();
00110     const QRectF ellipseMarker = QRectF( at.x() - markerSize.width() / 2,
00111                                          at.y() - markerSize.height() / 2,
00112                                          markerSize.width(), markerSize.height() );
00113 
00114     QPointF startMarker[3];
00115     if ( vt.orientations() & Qt::Horizontal ) {
00116         startMarker[0] = startPoint + QPointF( 0,  markerSize.height() / 2 );
00117         startMarker[1] = startPoint + QPointF( markerSize.width() / 2, 0 );
00118         startMarker[2] = startPoint - QPointF( 0, markerSize.height() / 2 );
00119     } else {
00120         startMarker[0] = startPoint + QPointF( 0, markerSize.height() / 2 );
00121         startMarker[1] = startPoint + QPointF( markerSize.width() / 2, 0 );
00122         startMarker[2] = startPoint - QPointF( markerSize.width() / 2, 0 );
00123     }
00124 
00125     QPointF endMarker[3];
00126 
00127     if ( vt.orientations() & Qt::Vertical ) {
00128         endMarker[0] = endPoint + QPointF( markerSize.width() / 2, 0 );
00129         endMarker[1] = endPoint - QPointF( 0, markerSize.height() / 2 );
00130         endMarker[2] = endPoint - QPointF( markerSize.width() / 2, 0 );
00131     } else {
00132         endMarker[0] = endPoint + QPointF( 0,  markerSize.width() / 2 );
00133         endMarker[1] = endPoint - QPointF( 0, markerSize.height() / 2 );
00134         endMarker[2] = endPoint - QPointF( markerSize.width() / 2, 0 );
00135     }
00136 
00137     QPointF topLeft = startPoint;
00138     QPointF bottomRightOffset = endPoint - topLeft;
00139     QSizeF size( bottomRightOffset.x(), bottomRightOffset.y() );
00140     QRectF area( topLeft, size );
00141 
00142     PainterSaver painterSaver( ctx->painter() );
00143     ctx->painter()->setPen( PrintingParameters::scalePen( vt.linePen() ) );
00144     ctx->painter()->setBrush( QBrush() );
00145     ctx->painter()->drawLine( markerPoint, startPoint );
00146     ctx->painter()->drawLine( markerPoint, endPoint );
00147 
00148     ctx->painter()->fillRect( area, vt.areaBrush() );
00149 
00150     ctx->painter()->setPen( PrintingParameters::scalePen( vt.markerPen() ) );
00151     ctx->painter()->setBrush( vt.markerBrush() );
00152     ctx->painter()->drawEllipse( ellipseMarker );
00153 
00154     ctx->painter()->setPen( PrintingParameters::scalePen( vt.arrowBrush().color() ) );
00155     ctx->painter()->setBrush( vt.arrowBrush() );
00156     ctx->painter()->drawPolygon( startMarker, 3 );
00157     ctx->painter()->drawPolygon( endMarker, 3 );
00158 }
00159 
00160 // ### for BC reasons we cannot insert a common interface for LineDiagram and Plotter into the class
00161 //     hierarchy, so we have to use hacks to use their common methods
00162 static ThreeDLineAttributes threeDLineAttributes( AbstractDiagram* diagram, const QModelIndex& index )
00163 {
00164     if ( Plotter *plotter = qobject_cast< Plotter* >( diagram ) ) {
00165         return plotter->threeDLineAttributes( index );
00166     } else if ( LineDiagram *lineDiagram = qobject_cast< LineDiagram* >( diagram ) ) {
00167         return lineDiagram->threeDLineAttributes( index );
00168     }
00169     Q_ASSERT( false );
00170     return ThreeDLineAttributes();
00171 }
00172 
00173 static ValueTrackerAttributes valueTrackerAttributes( AbstractDiagram* diagram, const QModelIndex& index )
00174 {
00175     if ( Plotter *plotter = qobject_cast< Plotter* >( diagram ) ) {
00176         return plotter->valueTrackerAttributes( index );
00177     } else if ( LineDiagram *lineDiagram = qobject_cast< LineDiagram* >( diagram ) ) {
00178         return lineDiagram->valueTrackerAttributes( index );
00179     }
00180     Q_ASSERT( false );
00181     return ValueTrackerAttributes();
00182 }
00183 
00184 void paintElements( AbstractDiagram::Private *diagramPrivate, PaintContext* ctx,
00185                     const LabelPaintCache& lpc, const LineAttributesInfoList& lineList )
00186 {
00187     AbstractDiagram* diagram = diagramPrivate->diagram;
00188     // paint all lines and their attributes
00189     const PainterSaver painterSaver( ctx->painter() );
00190     ctx->painter()->setRenderHint( QPainter::Antialiasing, diagram->antiAliasing() );
00191 
00192     QBrush curBrush;
00193     QPen curPen;
00194     QPolygonF points;
00195     KDAB_FOREACH ( const LineAttributesInfo& lineInfo, lineList ) {
00196         const QModelIndex& index = lineInfo.index;
00197         const ThreeDLineAttributes td = threeDLineAttributes( diagram, index );
00198         const ValueTrackerAttributes vt = valueTrackerAttributes( diagram, index );
00199 
00200         if ( td.isEnabled() ) {
00201             PaintingHelpers::paintThreeDLines( ctx, diagram, index, lineInfo.value,
00202                                                lineInfo.nextValue, td, &diagramPrivate->reverseMapper );
00203         } else {
00204             const QBrush br( diagram->brush( index ) );
00205             const QPen pn( diagram->pen( index ) );
00206             if( points.count() && points.last() == lineInfo.value && curBrush == br && curPen == pn ) {
00207                 // line goes from last value in points to lineInfo.nextValue
00208                 diagramPrivate->reverseMapper.addLine( lineInfo.index.row(), lineInfo.index.column(),
00209                                                        points.last(), lineInfo.nextValue );
00210                 points << lineInfo.nextValue;
00211             } else {
00212                 if ( points.count() ) {
00213                     PaintingHelpers::paintPolyline( ctx, curBrush, curPen, points );
00214                 }
00215                 curBrush = br;
00216                 curPen = pn;
00217                 points.clear();
00218                 // line goes from lineInfo.value to lineInfo,nextValue
00219                 diagramPrivate->reverseMapper.addLine( lineInfo.index.row(), lineInfo.index.column(),
00220                                                        lineInfo.value, lineInfo.nextValue );
00221                 points << lineInfo.value << lineInfo.nextValue;
00222             }
00223         }
00224     }
00225     if ( points.count() ) {
00226         PaintingHelpers::paintPolyline( ctx, curBrush, curPen, points );
00227     }
00228 
00229     KDAB_FOREACH ( const LineAttributesInfo& lineInfo, lineList ) {
00230         const QModelIndex& index = lineInfo.index;
00231         const ValueTrackerAttributes vt = valueTrackerAttributes( diagram, index );
00232         if ( vt.isEnabled() ) {
00233             PaintingHelpers::paintValueTracker( ctx, vt, lineInfo.nextValue );
00234         }
00235     }
00236 
00237     // paint all data value texts and the point markers
00238     diagramPrivate->paintDataValueTextsAndMarkers( ctx, lpc, true );
00239 }
00240 
00241 void paintAreas( AbstractDiagram::Private* diagramPrivate, PaintContext* ctx, const QModelIndex& index,
00242                  const QList< QPolygonF >& areas, uint opacity )
00243 {
00244     AbstractDiagram* diagram = diagramPrivate->diagram;
00245     QPainterPath path;
00246     for( int i = 0; i < areas.count(); ++i )
00247     {
00248         const QPolygonF& p = areas[ i ];
00249         path.addPolygon( p );
00250         diagramPrivate->reverseMapper.addPolygon( index.row(), index.column(), p );
00251         path.closeSubpath();
00252     }
00253 
00254     ThreeDLineAttributes threeDAttrs = threeDLineAttributes( diagram, index );
00255     QBrush trans = diagram->brush( index );
00256     if( threeDAttrs.isEnabled() ) {
00257         trans = threeDAttrs.threeDBrush( trans, path.boundingRect() );
00258     }
00259     QColor transColor = trans.color();
00260     transColor.setAlpha( opacity );
00261     trans.setColor(transColor);
00262     QPen indexPen = diagram->pen(index);
00263     indexPen.setBrush( trans );
00264     const PainterSaver painterSaver( ctx->painter() );
00265 
00266     ctx->painter()->setRenderHint( QPainter::Antialiasing, diagram->antiAliasing() );
00267     ctx->painter()->setPen( PrintingParameters::scalePen( indexPen ) );
00268     ctx->painter()->setBrush( trans );
00269 
00270     ctx->painter()->drawPath( path );
00271 }
00272 
00273 } // namespace PaintingHelpers
00274 } // namespace KDChart
 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/