00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "KDChartLineDiagram.h"
00024 #include "KDChartDataValueAttributes.h"
00025
00026 #include "KDChartLineDiagram_p.h"
00027
00028 using namespace KDChart;
00029 using namespace std;
00030
00031 LineDiagram::Private::Private( const Private& rhs )
00032 : AbstractCartesianDiagram::Private( rhs )
00033 {
00034 }
00035
00036 void LineDiagram::Private::paintPolyline(
00037 PaintContext* ctx,
00038 const QBrush& brush, const QPen& pen,
00039 const QPolygonF& points ) const
00040 {
00041 ctx->painter()->setBrush( brush );
00042 ctx->painter()->setPen( PrintingParameters::scalePen(
00043 QPen( pen.color(),
00044 pen.width(),
00045 pen.style(),
00046 Qt::FlatCap,
00047 Qt::MiterJoin ) ) );
00048 #if QT_VERSION > 0x040299
00049 ctx->painter()->drawPolyline( points );
00050 #else
00051
00052
00053
00054 for (int i = 0; i < points.size()-1; ++i)
00055 ctx->painter()->drawLine( points.at(i), points.at(i+1) );
00056 #endif
00057 }
00058
00064 const QPointF LineDiagram::LineDiagramType::project(
00065 QPointF point, QPointF maxLimits,
00066 double z, const QModelIndex& index ) const
00067 {
00068 Q_UNUSED( maxLimits );
00069 ThreeDLineAttributes td = diagram()->threeDLineAttributes( index );
00070
00071
00072 double xrad = DEGTORAD( td.lineXRotation() );
00073 double yrad = DEGTORAD( td.lineYRotation() );
00074 QPointF ret = QPointF(point.x()*cos( yrad ) + z * sin( yrad ) , point.y()*cos( xrad ) - z * sin( xrad ) );
00075 return ret;
00076 }
00077
00078 void LineDiagram::LineDiagramType::paintThreeDLines(
00079 PaintContext* ctx, const QModelIndex& index,
00080 const QPointF& from, const QPointF& to, const double depth )
00081 {
00082
00083 const QPair< QPointF, QPointF > boundaries = diagram()->dataBoundaries();
00084 const QPointF& maxLimits = boundaries.second;
00085 const QPointF topLeft = project( from, maxLimits, depth, index );
00086 const QPointF topRight = project ( to, maxLimits, depth, index );
00087
00088 const QPolygonF segment = QPolygonF() << from << topLeft << topRight << to;
00089 const QBrush indexBrush ( diagram()->brush( index ) );
00090 const PainterSaver painterSaver( ctx->painter() );
00091
00092 if( diagram()->antiAliasing() )
00093 ctx->painter()->setRenderHint( QPainter::Antialiasing );
00094
00095 ctx->painter()->setBrush( indexBrush );
00096 ctx->painter()->setPen( PrintingParameters::scalePen( diagram()->pen( index ) ) );
00097
00098 reverseMapper().addPolygon( index.row(), index.column(), segment );
00099 ctx->painter()->drawPolygon( segment );
00100 }
00101
00102
00103
00104
00105 void LineDiagram::LineDiagramType::paintElements(
00106 PaintContext* ctx,
00107 DataValueTextInfoList& list,
00108 LineAttributesInfoList& lineList,
00109 LineAttributes::MissingValuesPolicy policy )
00110 {
00111 Q_UNUSED( policy );
00112
00113 const PainterSaver painterSaver( ctx->painter() );
00114 if ( diagram()->antiAliasing() )
00115 ctx->painter()->setRenderHint ( QPainter::Antialiasing );
00116 LineAttributesInfoListIterator itline ( lineList );
00117
00118 QBrush curBrush;
00119 QPen curPen;
00120 QPolygonF points;
00121 while ( itline.hasNext() ) {
00122 const LineAttributesInfo& lineInfo = itline.next();
00123 const QModelIndex& index = lineInfo.index;
00124 const ThreeDLineAttributes td = diagram()->threeDLineAttributes( index );
00125 const ValueTrackerAttributes vt = diagram()->valueTrackerAttributes( index );
00126
00127 if( td.isEnabled() ){
00128 paintThreeDLines( ctx, index, lineInfo.value, lineInfo.nextValue, td.depth() );
00129 } else {
00130 const QBrush br( diagram()->brush( index ) );
00131 const QPen pn( diagram()->pen( index ) );
00132 if( points.count() && points.last() == lineInfo.value && curBrush == br && curPen == pn ) {
00133
00134 reverseMapper().addLine( lineInfo.index.row(), lineInfo.index.column(), points.last(), lineInfo.nextValue );
00135 points << lineInfo.nextValue;
00136 } else {
00137 if( points.count() )
00138 paintPolyline( ctx, curBrush, curPen, points );
00139 curBrush = br;
00140 curPen = pn;
00141 points.clear();
00142
00143 reverseMapper().addLine( lineInfo.index.row(), lineInfo.index.column(), lineInfo.value, lineInfo.nextValue );
00144 points << lineInfo.value << lineInfo.nextValue;
00145 }
00146 }
00147
00148 if( vt.isEnabled() )
00149 paintValueTracker( ctx, vt, lineInfo.value );
00150 }
00151 if( points.count() )
00152 paintPolyline( ctx, curBrush, curPen, points );
00153
00154 paintDataValueTextsAndMarkers( diagram(), ctx, list, true );
00155 }
00156
00157 AttributesModel* LineDiagram::LineDiagramType::attributesModel() const
00158 {
00159 return m_private->attributesModel;
00160 }
00161
00162 QModelIndex LineDiagram::LineDiagramType::attributesModelRootIndex() const
00163 {
00164 return m_private->diagram->attributesModelRootIndex();
00165 }
00166
00167 int LineDiagram::LineDiagramType::datasetDimension() const
00168 {
00169 return m_private->datasetDimension;
00170 }
00171
00172 ReverseMapper& LineDiagram::LineDiagramType::reverseMapper()
00173 {
00174 return m_private->reverseMapper;
00175 }
00176
00177 LineAttributes::MissingValuesPolicy LineDiagram::LineDiagramType::getCellValues(
00178 int row, int column,
00179 bool shiftCountedXValuesByHalfSection,
00180 double& valueX, double& valueY ) const
00181 {
00182 return m_private->diagram->getCellValues( row, column, shiftCountedXValuesByHalfSection,
00183 valueX, valueY );
00184 }
00185
00186 double LineDiagram::LineDiagramType::valueForCellTesting(
00187 int row, int column,
00188 bool& bOK,
00189 bool showHiddenCellsAsInvalid) const
00190 {
00191 return m_private->diagram->valueForCellTesting( row, column, bOK, showHiddenCellsAsInvalid );
00192 }
00193
00194 LineDiagram* LineDiagram::LineDiagramType::diagram() const
00195 {
00196 return m_private->diagram;
00197 }
00198
00199 void LineDiagram::LineDiagramType::paintAreas(
00200 PaintContext* ctx,
00201 const QModelIndex& index, const QList< QPolygonF >& areas,
00202 const uint transparency )
00203 {
00204 QColor trans = diagram()->brush( index ).color();
00205 trans.setAlpha( transparency );
00206 QPen indexPen = diagram()->pen(index);
00207 indexPen.setColor( trans );
00208 const PainterSaver painterSaver( ctx->painter() );
00209
00210 if( diagram()->antiAliasing() )
00211 ctx->painter()->setRenderHint( QPainter::Antialiasing );
00212
00213 ctx->painter()->setPen( PrintingParameters::scalePen( indexPen ) );
00214 ctx->painter()->setBrush( trans );
00215
00216 QPainterPath path;
00217 for( int i = 0; i < areas.count(); ++i )
00218 {
00219 const QPolygonF& p = areas[ i ];
00220 path.addPolygon( p );
00221 reverseMapper().addPolygon( index.row(), index.column(), p );
00222 path.closeSubpath();
00223 }
00224 ctx->painter()->drawPath( path );
00225 }
00226
00227 double LineDiagram::LineDiagramType::valueForCell( int row, int column )
00228 {
00229 return diagram()->valueForCell( row, column );
00230 }
00231
00232 void LineDiagram::LineDiagramType::appendDataValueTextInfoToList(
00233 AbstractDiagram * diagram,
00234 DataValueTextInfoList & list,
00235 const QModelIndex & index,
00236 const CartesianDiagramDataCompressor::CachePosition * position,
00237 const PositionPoints& points,
00238 const Position& autoPositionPositive,
00239 const Position& autoPositionNegative,
00240 const qreal value )
00241 {
00242 Q_UNUSED( autoPositionNegative );
00243 m_private->appendDataValueTextInfoToList( diagram, list, index, position, points,
00244 autoPositionPositive, autoPositionPositive, value );
00245 }
00246
00247 void LineDiagram::LineDiagramType::paintValueTracker( PaintContext* ctx, const ValueTrackerAttributes& vt, const QPointF& at )
00248 {
00249 CartesianCoordinatePlane* plane = qobject_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() );
00250 if( !plane )
00251 return;
00252
00253 DataDimensionsList gridDimensions = ctx->coordinatePlane()->gridDimensionsList();
00254 const QPointF bottomLeft( ctx->coordinatePlane()->translate(
00255 QPointF( plane->isHorizontalRangeReversed() ?
00256 gridDimensions.at( 0 ).end :
00257 gridDimensions.at( 0 ).start,
00258 plane->isVerticalRangeReversed() ?
00259 gridDimensions.at( 1 ).end :
00260 gridDimensions.at( 1 ).start ) ) );
00261 const QPointF markerPoint = at;
00262 const QPointF ordinatePoint( bottomLeft.x(), at.y() );
00263 const QPointF abscissaPoint( at.x(), bottomLeft.y() );
00264
00265 const QSizeF markerSize = vt.markerSize();
00266 const QRectF ellipseMarker = QRectF( at.x() - markerSize.width() / 2,
00267 at.y() - markerSize.height() / 2,
00268 markerSize.width(), markerSize.height() );
00269
00270 const QPointF ordinateMarker[3] = {
00271 QPointF( ordinatePoint.x(), at.y() + markerSize.height() / 2 ),
00272 QPointF( ordinatePoint.x() + markerSize.width() / 2, at.y() ),
00273 QPointF( ordinatePoint.x(), at.y() - markerSize.height() / 2 )
00274 };
00275
00276 const QPointF abscissaMarker[3] = {
00277 QPointF( at.x() + markerSize.width() / 2, abscissaPoint.y() ),
00278 QPointF( at.x(), abscissaPoint.y() - markerSize.height() / 2 ),
00279 QPointF( at.x() - markerSize.width() / 2, abscissaPoint.y() )
00280 };
00281
00282 QPointF topLeft = ordinatePoint;
00283 QPointF bottomRightOffset = abscissaPoint - topLeft;
00284 QSizeF size( bottomRightOffset.x(), bottomRightOffset.y() );
00285 QRectF area( topLeft, size );
00286
00287 PainterSaver painterSaver( ctx->painter() );
00288 ctx->painter()->setPen( PrintingParameters::scalePen( vt.pen() ) );
00289 ctx->painter()->setBrush( QBrush() );
00290
00291 ctx->painter()->drawLine( markerPoint, ordinatePoint );
00292 ctx->painter()->drawLine( markerPoint, abscissaPoint );
00293
00294 ctx->painter()->fillRect( area, vt.areaBrush() );
00295
00296 ctx->painter()->drawEllipse( ellipseMarker );
00297
00298 ctx->painter()->setBrush( vt.pen().color() );
00299 ctx->painter()->drawPolygon( ordinateMarker, 3 );
00300 ctx->painter()->drawPolygon( abscissaMarker, 3 );
00301 }
00302
00303 CartesianDiagramDataCompressor& LineDiagram::LineDiagramType::compressor() const
00304 {
00305 return m_private->compressor;
00306 }
00307
00308 double LineDiagram::LineDiagramType::interpolateMissingValue( const CartesianDiagramDataCompressor::CachePosition& pos ) const
00309 {
00310 double leftValue = std::numeric_limits< double >::quiet_NaN();
00311 double rightValue = std::numeric_limits< double >::quiet_NaN();
00312 int missingCount = 1;
00313
00314 const int column = pos.second;
00315 const int row = pos.first;
00316 const int rowCount = compressor().modelDataRows();
00317
00318
00319 for( int r1 = row - 1; r1 > 0; --r1 )
00320 {
00321 const CartesianDiagramDataCompressor::CachePosition position( r1, column );
00322 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00323 leftValue = point.value;
00324 if( !ISNAN( point.value ) )
00325 break;
00326 ++missingCount;
00327 }
00328 for( int r2 = row + 1; r2 < rowCount; ++r2 )
00329 {
00330 const CartesianDiagramDataCompressor::CachePosition position( r2, column );
00331 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00332 rightValue = point.value;
00333 if( !ISNAN( point.value ) )
00334 break;
00335 ++missingCount;
00336 }
00337 if( !ISNAN( leftValue ) && !ISNAN( rightValue ) )
00338 return leftValue + ( rightValue - leftValue ) / ( missingCount + 1 );
00339 else
00340 return std::numeric_limits< double >::quiet_NaN();
00341 }