KDChartLineDiagram_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 "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     // FIXME (Mirko) verify, this sounds reverse-logical
00052     // For Qt versions older than 4.3 drawPolyline is VERY slow
00053     // so we use traditional line segments drawing instead then.
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     //Pending Michel FIXME - the rotation does not work as expected atm
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     // retrieve the boundaries
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 // this method is factored out from LineDiagram::paint, and contains
00103 // the common parts of the method that  previously implemented all
00104 // chart types in one
00105 void LineDiagram::LineDiagramType::paintElements(
00106     PaintContext* ctx,
00107     DataValueTextInfoList& list,
00108     LineAttributesInfoList& lineList,
00109     LineAttributes::MissingValuesPolicy policy )
00110 {
00111     Q_UNUSED( policy );
00112     // paint all lines and their attributes
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                 // line goes from last value in points to lineInfo.nextValue
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                 // line goes from lineInfo.value to lineInfo,nextValue
00143                 reverseMapper().addLine( lineInfo.index.row(), lineInfo.index.column(), lineInfo.value, lineInfo.nextValue );
00144                 points << lineInfo.value << lineInfo.nextValue;
00145             }
00146         }
00147     }
00148     if( points.count() )
00149         paintPolyline( ctx, curBrush, curPen, points );
00150 
00151     itline.toFront();
00152     while ( itline.hasNext() ) {
00153         const LineAttributesInfo& lineInfo = itline.next();
00154         const QModelIndex& index = lineInfo.index;
00155         const ValueTrackerAttributes vt = diagram()->valueTrackerAttributes( index );
00156         if( vt.isEnabled() )
00157             paintValueTracker( ctx, vt, lineInfo.value );
00158     }
00159 
00160     // paint all data value texts and the point markers
00161     paintDataValueTextsAndMarkers( diagram(), ctx, list, true );
00162 }
00163 
00164 AttributesModel* LineDiagram::LineDiagramType::attributesModel() const
00165 {
00166     return m_private->attributesModel;
00167 }
00168 
00169 QModelIndex LineDiagram::LineDiagramType::attributesModelRootIndex() const
00170 {
00171     return m_private->diagram->attributesModelRootIndex();
00172 }
00173 
00174 int LineDiagram::LineDiagramType::datasetDimension() const
00175 {
00176     return m_private->datasetDimension;
00177 }
00178 
00179 ReverseMapper& LineDiagram::LineDiagramType::reverseMapper()
00180 {
00181     return m_private->reverseMapper;
00182 }
00183 
00184 LineAttributes::MissingValuesPolicy LineDiagram::LineDiagramType::getCellValues(
00185     int row, int column,
00186     bool shiftCountedXValuesByHalfSection,
00187     double& valueX, double& valueY ) const
00188 {
00189     return m_private->diagram->getCellValues( row, column, shiftCountedXValuesByHalfSection,
00190                                               valueX, valueY );
00191 }
00192 
00193 double LineDiagram::LineDiagramType::valueForCellTesting(
00194     int row, int column,
00195     bool& bOK,
00196     bool showHiddenCellsAsInvalid) const
00197 {
00198     return m_private->diagram->valueForCellTesting( row, column, bOK, showHiddenCellsAsInvalid );
00199 }
00200 
00201 LineDiagram* LineDiagram::LineDiagramType::diagram() const
00202 {
00203     return m_private->diagram;
00204 }
00205 
00206 void LineDiagram::LineDiagramType::paintAreas(
00207     PaintContext* ctx,
00208     const QModelIndex& index, const QList< QPolygonF >& areas,
00209     const uint transparency )
00210 {
00211     QColor trans = diagram()->brush( index ).color();
00212     trans.setAlpha( transparency );
00213     QPen indexPen = diagram()->pen(index);
00214     indexPen.setColor( trans );
00215     const PainterSaver painterSaver( ctx->painter() );
00216 
00217     if( diagram()->antiAliasing() )
00218         ctx->painter()->setRenderHint( QPainter::Antialiasing );
00219 
00220     ctx->painter()->setPen( PrintingParameters::scalePen( indexPen ) );
00221     ctx->painter()->setBrush( trans );
00222 
00223     QPainterPath path;
00224     for( int i = 0; i < areas.count(); ++i )
00225     {
00226         const QPolygonF& p = areas[ i ];
00227         path.addPolygon( p );
00228         reverseMapper().addPolygon( index.row(), index.column(), p );
00229         path.closeSubpath();
00230     }
00231     ctx->painter()->drawPath( path );
00232 }
00233 
00234 double LineDiagram::LineDiagramType::valueForCell( int row, int column )
00235 {
00236     return diagram()->valueForCell( row, column );
00237 }
00238 
00239 void LineDiagram::LineDiagramType::appendDataValueTextInfoToList(
00240             AbstractDiagram * diagram,
00241             DataValueTextInfoList & list,
00242             const QModelIndex & index,
00243             const CartesianDiagramDataCompressor::CachePosition * position,
00244             const PositionPoints& points,
00245             const Position& autoPositionPositive,
00246             const Position& autoPositionNegative,
00247             const qreal value )
00248 {
00249     Q_UNUSED( autoPositionNegative );
00250     m_private->appendDataValueTextInfoToList( diagram, list, index, position, points,
00251                                               autoPositionPositive, autoPositionPositive, value );
00252 }
00253 
00254 void LineDiagram::LineDiagramType::paintValueTracker( PaintContext* ctx, const ValueTrackerAttributes& vt, const QPointF& at )
00255 {
00256     CartesianCoordinatePlane* plane = qobject_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() );
00257     if( !plane )
00258         return;
00259 
00260     DataDimensionsList gridDimensions = ctx->coordinatePlane()->gridDimensionsList();
00261     const QPointF bottomLeft( ctx->coordinatePlane()->translate(
00262                               QPointF( plane->isHorizontalRangeReversed() ?
00263                                            gridDimensions.at( 0 ).end :
00264                                            gridDimensions.at( 0 ).start,
00265                                        plane->isVerticalRangeReversed() ?
00266                                            gridDimensions.at( 1 ).end :
00267                                            gridDimensions.at( 1 ).start ) ) );
00268     const QPointF markerPoint = at;
00269     const QPointF ordinatePoint( bottomLeft.x(), at.y() );
00270     const QPointF abscissaPoint( at.x(), bottomLeft.y() );
00271 
00272     const QSizeF markerSize = vt.markerSize();
00273     const QRectF ellipseMarker = QRectF( at.x() - markerSize.width() / 2,
00274                                          at.y() - markerSize.height() / 2,
00275                                          markerSize.width(), markerSize.height() );
00276 
00277     const QPointF ordinateMarker[3] = {
00278         QPointF( ordinatePoint.x(), at.y() + markerSize.height() / 2 ),
00279         QPointF( ordinatePoint.x() + markerSize.width() / 2, at.y() ),
00280         QPointF( ordinatePoint.x(), at.y() - markerSize.height() / 2 )
00281     };
00282 
00283     const QPointF abscissaMarker[3] = {
00284         QPointF( at.x() + markerSize.width() / 2, abscissaPoint.y() ),
00285         QPointF( at.x(), abscissaPoint.y() - markerSize.height() / 2 ),
00286         QPointF( at.x() - markerSize.width() / 2, abscissaPoint.y() )
00287     };
00288 
00289     QPointF topLeft = ordinatePoint;
00290     QPointF bottomRightOffset = abscissaPoint - topLeft;
00291     QSizeF size( bottomRightOffset.x(), bottomRightOffset.y() );
00292     QRectF area( topLeft, size );
00293 
00294     PainterSaver painterSaver( ctx->painter() );
00295     ctx->painter()->setPen( PrintingParameters::scalePen( vt.pen() ) );
00296     ctx->painter()->setBrush( QBrush() );
00297 
00298     ctx->painter()->drawLine( markerPoint, ordinatePoint );
00299     ctx->painter()->drawLine( markerPoint, abscissaPoint );
00300 
00301     ctx->painter()->fillRect( area, vt.areaBrush() );
00302 
00303     ctx->painter()->drawEllipse( ellipseMarker );
00304 
00305     ctx->painter()->setBrush( vt.pen().color() );
00306     ctx->painter()->drawPolygon( ordinateMarker, 3 );
00307     ctx->painter()->drawPolygon( abscissaMarker, 3 );
00308 }
00309 
00310 CartesianDiagramDataCompressor& LineDiagram::LineDiagramType::compressor() const
00311 {
00312     return m_private->compressor;
00313 }
00314 
00315 double LineDiagram::LineDiagramType::interpolateMissingValue( const CartesianDiagramDataCompressor::CachePosition& pos ) const
00316 {
00317     double leftValue = std::numeric_limits< double >::quiet_NaN();
00318     double rightValue = std::numeric_limits< double >::quiet_NaN();
00319     int missingCount = 1;
00320 
00321     const int column = pos.second;
00322     const int row = pos.first;
00323     const int rowCount = compressor().modelDataRows();
00324 
00325     // iterate back and forth to find valid values
00326     for( int r1 = row - 1; r1 > 0; --r1 )
00327     {
00328         const CartesianDiagramDataCompressor::CachePosition position( r1, column );
00329         const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00330         leftValue = point.value;
00331         if( !ISNAN( point.value ) )
00332             break;
00333         ++missingCount;
00334     }
00335     for( int r2 = row + 1; r2 < rowCount; ++r2 )
00336     {
00337         const CartesianDiagramDataCompressor::CachePosition position( r2, column );
00338         const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00339         rightValue = point.value;
00340         if( !ISNAN( point.value ) )
00341             break;
00342         ++missingCount;
00343     }
00344     if( !ISNAN( leftValue ) && !ISNAN( rightValue ) )
00345         return leftValue + ( rightValue - leftValue ) / ( missingCount + 1 );
00346     else
00347         return std::numeric_limits< double >::quiet_NaN();
00348 }
 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/