KD Chart 2
[rev.2.5]
|
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