KD Chart 2
[rev.2.5]
|
00001 /**************************************************************************** 00002 ** Copyright (C) 2001-2012 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 <limits> 00024 00025 #include <QAbstractItemModel> 00026 00027 #include "KDChartBarDiagram.h" 00028 #include "KDChartLineDiagram.h" 00029 #include "KDChartTextAttributes.h" 00030 #include "KDChartAttributesModel.h" 00031 #include "KDChartAbstractCartesianDiagram.h" 00032 #include "KDChartNormalLineDiagram_p.h" 00033 #include "PaintingHelpers_p.h" 00034 00035 using namespace KDChart; 00036 using namespace std; 00037 00038 NormalLineDiagram::NormalLineDiagram( LineDiagram* d ) 00039 : LineDiagramType( d ) 00040 { 00041 } 00042 00043 LineDiagram::LineType NormalLineDiagram::type() const 00044 { 00045 return LineDiagram::Normal; 00046 } 00047 00048 const QPair< QPointF, QPointF > NormalLineDiagram::calculateDataBoundaries() const 00049 { 00050 const int rowCount = compressor().modelDataRows(); 00051 const int colCount = compressor().modelDataColumns(); 00052 const qreal xMin = 0.0; 00053 qreal xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0; 00054 if ( !diagram()->centerDataPoints() && diagram()->model() ) 00055 xMax -= 1; 00056 qreal yMin = std::numeric_limits< qreal >::quiet_NaN(); 00057 qreal yMax = std::numeric_limits< qreal >::quiet_NaN(); 00058 00059 for( int column = 0; column < colCount; ++column ) 00060 { 00061 for ( int row = 0; row < rowCount; ++row ) 00062 { 00063 const CartesianDiagramDataCompressor::CachePosition position( row, column ); 00064 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00065 const qreal value = ISNAN( point.value ) ? 0.0 : point.value; 00066 00067 if ( ISNAN( yMin ) ) { 00068 yMin = value; 00069 yMax = value; 00070 } else { 00071 yMin = qMin( yMin, value ); 00072 yMax = qMax( yMax, value ); 00073 } 00074 } 00075 } 00076 00077 // NOTE: calculateDataBoundaries must return the *real* data boundaries! 00078 // i.e. we may NOT fake yMin to be qMin( 0.0, yMin ) 00079 // (khz, 2008-01-24) 00080 const QPointF bottomLeft( QPointF( xMin, yMin ) ); 00081 const QPointF topRight( QPointF( xMax, yMax ) ); 00082 return QPair< QPointF, QPointF >( bottomLeft, topRight ); 00083 } 00084 00085 void NormalLineDiagram::paint( PaintContext* ctx ) 00086 { 00087 reverseMapper().clear(); 00088 Q_ASSERT( dynamic_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() ) ); 00089 CartesianCoordinatePlane* plane = static_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() ); 00090 const int columnCount = compressor().modelDataColumns(); 00091 const int rowCount = compressor().modelDataRows(); 00092 if ( columnCount == 0 || rowCount == 0 ) return; // maybe blank out the area? 00093 00094 // FIXME integrate column index retrieval to compressor: 00095 // the compressor should only pass through visiblel columns 00096 // int maxFound = 0; 00097 // { // find the last column number that is not hidden 00098 // for( int column = datasetDimension() - 1; 00099 // column < columnCount; 00100 // column += datasetDimension() ) 00101 // if( ! diagram()->isHidden( column ) ) 00102 // maxFound = column; 00103 // } 00104 // maxFound = columnCount; 00105 // ^^^ temp 00106 00107 // Reverse order of data sets? 00108 bool rev = diagram()->reverseDatasetOrder(); 00109 LabelPaintCache lpc; 00110 LineAttributesInfoList lineList; 00111 for( int column = rev ? columnCount - 1 : 0; 00112 rev ? (column >= 0) : (column < columnCount); 00113 rev ? --column : ++column ) { 00114 LineAttributes laPreviousCell; 00115 CartesianDiagramDataCompressor::DataPoint lastPoint; 00116 qreal lastAreaBoundingValue = 0; 00117 00118 // Get min. y value, used as lower or upper bounding for area highlighting 00119 const qreal minYValue = qMin(plane->visibleDataRange().bottom(), plane->visibleDataRange().top()); 00120 00121 CartesianDiagramDataCompressor::CachePosition previousCellPosition; 00122 for ( int row = 0; row < rowCount; ++row ) { 00123 const CartesianDiagramDataCompressor::CachePosition position( row, column ); 00124 // get where to draw the line from: 00125 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00126 00127 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); 00128 00129 const LineAttributes laCell = diagram()->lineAttributes( sourceIndex ); 00130 const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy(); 00131 00132 // lower or upper bounding for the highlighted area 00133 qreal areaBoundingValue; 00134 if ( laCell.areaBoundingDataset() != -1 ) { 00135 const CartesianDiagramDataCompressor::CachePosition areaBoundingCachePosition( row, laCell.areaBoundingDataset() ); 00136 areaBoundingValue = compressor().data( areaBoundingCachePosition ).value; 00137 } else 00138 // Use min. y value (i.e. zero line in most cases) if no bounding dataset is set 00139 areaBoundingValue = minYValue; 00140 00141 if( ISNAN( point.value ) ) 00142 { 00143 switch( policy ) 00144 { 00145 case LineAttributes::MissingValuesAreBridged: 00146 // we just bridge both values 00147 continue; 00148 case LineAttributes::MissingValuesShownAsZero: 00149 // set it to zero 00150 point.value = 0.0; 00151 break; 00152 case LineAttributes::MissingValuesHideSegments: 00153 // they're just hidden 00154 break; 00155 default: 00156 break; 00157 // hm.... 00158 } 00159 } 00160 00161 // area corners, a + b are the line ends: 00162 const QPointF a( plane->translate( QPointF( diagram()->centerDataPoints() ? lastPoint.key + 0.5 : lastPoint.key, lastPoint.value ) ) ); 00163 const QPointF b( plane->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, point.value ) ) ); 00164 const QPointF c( plane->translate( QPointF( diagram()->centerDataPoints() ? lastPoint.key + 0.5 : lastPoint.key, lastAreaBoundingValue ) ) ); 00165 const QPointF d( plane->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, areaBoundingValue ) ) ); 00166 // add the line to the list: 00167 // add data point labels: 00168 const PositionPoints pts = PositionPoints( b, a, d, c ); 00169 // if necessary, add the area to the area list: 00170 QList<QPolygonF> areas; 00171 if ( !ISNAN( point.value ) && !ISNAN( lastPoint.value ) && laCell.displayArea() ) { 00172 areas << ( QPolygonF() << a << b << d << c );//polygon; 00173 } 00174 // add the pieces to painting if this is not hidden: 00175 if ( ! point.hidden && !ISNAN( point.value ) ) 00176 { 00177 addLabel( &lpc, sourceIndex, &position, pts, Position::NorthWest, 00178 Position::SouthWest, point.value ); 00179 PaintingHelpers::paintAreas( m_private, ctx, attributesModel()->mapToSource( lastPoint.index ), 00180 areas, laCell.transparency() ); 00181 // position 0 is not really painted, since it takes two points to make a line :-) 00182 if( row > 0 && !ISNAN( lastPoint.value ) ) 00183 lineList.append( LineAttributesInfo( sourceIndex, a, b ) ); 00184 } 00185 00186 // wrap it up: 00187 previousCellPosition = position; 00188 laPreviousCell = laCell; 00189 lastAreaBoundingValue = areaBoundingValue; 00190 lastPoint = point; 00191 } 00192 00193 } 00194 00195 PaintingHelpers::paintElements( m_private, ctx, lpc, lineList ); 00196 }