00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
00058
00059
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
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
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
00109
00110
00111 void LineDiagram::LineDiagramType::paintElements(
00112 PaintContext* ctx,
00113 DataValueTextInfoList& list,
00114 LineAttributesInfoList& lineList,
00115 LineAttributes::MissingValuesPolicy policy )
00116 {
00117 Q_UNUSED( policy );
00118
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
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
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
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 }