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