bool LineAttributes::operator==( const LineAttributes& r ) const { return missingValuesPolicy() == r.missingValuesPolicy() && displayArea() == r.displayArea() && transparency() == r.transparency() && areaBoundingDataset() == r.areaBoundingDataset(); }
LineAttributes::MissingValuesPolicy LineDiagram::getCellValues( int row, int column, bool shiftCountedXValuesByHalfSection, double& valueX, double& valueY ) const { LineAttributes::MissingValuesPolicy policy; bool bOK = true; valueX = ( datasetDimension() > 1 && column > 0 ) ? valueForCellTesting( row, column-1, bOK, true ) : ((shiftCountedXValuesByHalfSection ? 0.5 : 0.0) + row); if( bOK ) valueY = valueForCellTesting( row, column, bOK, true ); if( bOK ){ policy = LineAttributes::MissingValuesPolicyIgnored; }else{ // missing value: find out the policy QModelIndex index = model()->index( row, column, rootIndex() ); LineAttributes la = lineAttributes( index ); policy = la.missingValuesPolicy(); } return policy; }
void NormalLineDiagram::paint( PaintContext* ctx ) { reverseMapper().clear(); Q_ASSERT( dynamic_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() ) ); CartesianCoordinatePlane* plane = static_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() ); const int columnCount = compressor().modelDataColumns(); const int rowCount = compressor().modelDataRows(); if ( columnCount == 0 || rowCount == 0 ) return; // maybe blank out the area? // FIXME integrate column index retrieval to compressor: // the compressor should only pass through visiblel columns // int maxFound = 0; // { // find the last column number that is not hidden // for( int column = datasetDimension() - 1; // column < columnCount; // column += datasetDimension() ) // if( ! diagram()->isHidden( column ) ) // maxFound = column; // } // maxFound = columnCount; // ^^^ temp // Reverse order of data sets? bool rev = diagram()->reverseDatasetOrder(); DataValueTextInfoList textInfoList; LineAttributesInfoList lineList; for( int column = rev ? columnCount - 1 : 0; rev ? (column >= 0) : (column < columnCount); rev ? --column : ++column ) { LineAttributes laPreviousCell; CartesianDiagramDataCompressor::DataPoint lastPoint; qreal lastAreaBoundingValue = 0; // Get min. y value, used as lower or upper bounding for area highlighting const qreal minYValue = qMin(plane->visibleDataRange().bottom(), plane->visibleDataRange().top()); CartesianDiagramDataCompressor::CachePosition previousCellPosition; for ( int row = 0; row < rowCount; ++row ) { const CartesianDiagramDataCompressor::CachePosition position( row, column ); // get where to draw the line from: CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); const LineAttributes laCell = diagram()->lineAttributes( sourceIndex ); const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy(); // lower or upper bounding for the highlighted area qreal areaBoundingValue; if ( laCell.areaBoundingDataset() != -1 ) { const CartesianDiagramDataCompressor::CachePosition areaBoundingCachePosition( row, laCell.areaBoundingDataset() ); areaBoundingValue = compressor().data( areaBoundingCachePosition ).value; } else // Use min. y value (i.e. zero line in most cases) if no bounding dataset is set areaBoundingValue = minYValue; if( ISNAN( point.value ) ) { switch( policy ) { case LineAttributes::MissingValuesAreBridged: // we just bridge both values continue; case LineAttributes::MissingValuesShownAsZero: // set it to zero point.value = 0.0; break; case LineAttributes::MissingValuesHideSegments: // they're just hidden break; default: break; // hm.... } } // area corners, a + b are the line ends: const QPointF a( plane->translate( QPointF( diagram()->centerDataPoints() ? lastPoint.key + 0.5 : lastPoint.key, lastPoint.value ) ) ); const QPointF b( plane->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, point.value ) ) ); const QPointF c( plane->translate( QPointF( diagram()->centerDataPoints() ? lastPoint.key + 0.5 : lastPoint.key, lastAreaBoundingValue ) ) ); const QPointF d( plane->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, areaBoundingValue ) ) ); // add the line to the list: // add data point labels: const PositionPoints pts = PositionPoints( b, a, d, c ); // if necessary, add the area to the area list: QList<QPolygonF> areas; if ( !ISNAN( point.value ) && !ISNAN( lastPoint.value ) && laCell.displayArea() ) { areas << ( QPolygonF() << a << b << d << c );//polygon; } // add the pieces to painting if this is not hidden: if ( ! point.hidden && !ISNAN( point.value ) ) { appendDataValueTextInfoToList( diagram(), textInfoList, sourceIndex, &position, pts, Position::NorthWest, Position::SouthWest, point.value ); paintAreas( ctx, attributesModel()->mapToSource( lastPoint.index ), areas, laCell.transparency() ); // position 0 is not really painted, since it takes two points to make a line :-) if( row > 0 && !ISNAN( lastPoint.value ) ) lineList.append( LineAttributesInfo( sourceIndex, a, b ) ); } // wrap it up: previousCellPosition = position; laPreviousCell = laCell; lastAreaBoundingValue = areaBoundingValue; lastPoint = point; } } LineAttributes::MissingValuesPolicy policy = LineAttributes::MissingValuesAreBridged; //unused paintElements( ctx, textInfoList, lineList, policy ); }
void PercentLineDiagram::paint( PaintContext* ctx ) { reverseMapper().clear(); const int columnCount = compressor().modelDataColumns(); const int rowCount = compressor().modelDataRows(); // FIXME integrade column index retrieval to compressor: int maxFound = 0; // { // find the last column number that is not hidden // for( int iColumn = datasetDimension() - 1; // iColumn < columnCount; // iColumn += datasetDimension() ) // if( ! diagram()->isHidden( iColumn ) ) // maxFound = iColumn; // } maxFound = columnCount; // ^^^ temp const int lastVisibleColumn = maxFound - 1; DataValueTextInfoList list; LineAttributesInfoList lineList; LineAttributes::MissingValuesPolicy policy = LineAttributes::MissingValuesAreBridged; //FIXME(khz): add LineAttributes::MissingValuesPolicy support for LineDiagram::Stacked and ::Percent double maxValue = 100; // always 100% double sumValues = 0; QVector <double > percentSumValues; //calculate sum of values for each column and store for ( int row = 0; row < rowCount; ++row ) { for( int col = 0; col < columnCount; ++col ) { const CartesianDiagramDataCompressor::CachePosition position( row, col ); CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); const LineAttributes laCell = diagram()->lineAttributes( sourceIndex ); const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy(); if( ISNAN( point.value ) && policy == LineAttributes::MissingValuesAreBridged ) point.value = interpolateMissingValue( position ); if ( point.value > 0 ) sumValues += point.value; if ( col == lastVisibleColumn ) { percentSumValues << sumValues ; sumValues = 0; } } } QList<QPointF> bottomPoints; bool bFirstDataset = true; for( int column = 0; column < columnCount; ++column ) { //display area can be set by dataset ( == column) and/or by cell LineAttributes laPreviousCell; // by default no area is drawn QModelIndex indexPreviousCell; QList<QPolygonF> areas; QList<QPointF> points; for( int row = 0; row < rowCount; ++row ) { const CartesianDiagramDataCompressor::CachePosition position( row, column ); CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); const LineAttributes laCell = diagram()->lineAttributes( sourceIndex ); const bool bDisplayCellArea = laCell.displayArea(); double stackedValues = 0, nextValues = 0, nextKey = 0; for ( int column2 = column; column2 >= 0;//datasetDimension() - 1; column2 -= 1 )//datasetDimension() ) { const CartesianDiagramDataCompressor::CachePosition position( row, column2 ); CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy(); if( ISNAN( point.value ) && policy == LineAttributes::MissingValuesAreBridged ) point.value = interpolateMissingValue( position ); const double val = point.value; if( val > 0 ) stackedValues += val; //qDebug() << valueForCell( iRow, iColumn2 ); if ( row + 1 < rowCount ){ const CartesianDiagramDataCompressor::CachePosition position( row + 1, column2 ); CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy(); if( ISNAN( point.value ) && policy == LineAttributes::MissingValuesAreBridged ) point.value = interpolateMissingValue( position ); const double val = point.value; if( val > 0 ) nextValues += val; nextKey = point.key; } } if ( percentSumValues.at( row ) != 0 ) stackedValues = stackedValues / percentSumValues.at( row ) * maxValue; else stackedValues = 0.0; //qDebug() << stackedValues << endl; QPointF nextPoint = ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, stackedValues ) ); points << nextPoint; const QPointF ptNorthWest( nextPoint ); const QPointF ptSouthWest( bDisplayCellArea ? ( bFirstDataset ? ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, 0.0 ) ) : bottomPoints.at( row ) ) : nextPoint ); QPointF ptNorthEast; QPointF ptSouthEast; if ( row + 1 < rowCount ){ if ( percentSumValues.at( row + 1 ) != 0 ) nextValues = nextValues / percentSumValues.at( row + 1 ) * maxValue; else nextValues = 0.0; QPointF toPoint = ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? nextKey + 0.5 : nextKey, nextValues ) ); lineList.append( LineAttributesInfo( sourceIndex, nextPoint, toPoint ) ); ptNorthEast = toPoint; ptSouthEast = bDisplayCellArea ? ( bFirstDataset ? ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? nextKey + 0.5 : nextKey, 0.0 ) ) : bottomPoints.at( row + 1 ) ) : toPoint; if( areas.count() && laCell != laPreviousCell ){ paintAreas( ctx, indexPreviousCell, areas, laPreviousCell.transparency() ); areas.clear(); } if( bDisplayCellArea ){ QPolygonF poly; poly << ptNorthWest << ptNorthEast << ptSouthEast << ptSouthWest; areas << poly; laPreviousCell = laCell; indexPreviousCell = sourceIndex; }else{ //qDebug() << "no area shown for row"<<iRow<<" column"<<iColumn; } }else{ ptNorthEast = ptNorthWest; ptSouthEast = ptSouthWest; } if( !ISNAN( point.value ) ) { const PositionPoints pts( ptNorthWest, ptNorthEast, ptSouthEast, ptSouthWest ); appendDataValueTextInfoToList( diagram(), list, sourceIndex, &position, pts, Position::NorthWest, Position::SouthWest, point.value ); } } if( areas.count() ){ paintAreas( ctx, indexPreviousCell, areas, laPreviousCell.transparency() ); areas.clear(); } bottomPoints = points; bFirstDataset = false; } paintElements( ctx, list, lineList, policy ); }
void NormalLineDiagram::paint( PaintContext* ctx ) { reverseMapper().clear(); Q_ASSERT( dynamic_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() ) ); CartesianCoordinatePlane* plane = static_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() ); const int columnCount = compressor().modelDataColumns(); const int rowCount = compressor().modelDataRows(); if ( columnCount == 0 || rowCount == 0 ) return; // maybe blank out the area? // Reverse order of data sets? bool rev = diagram()->reverseDatasetOrder(); LabelPaintCache lpc; LineAttributesInfoList lineList; const int step = rev ? -1 : 1; const int end = rev ? -1 : columnCount; for ( int column = rev ? columnCount - 1 : 0; column != end; column += step ) { LineAttributes laPreviousCell; CartesianDiagramDataCompressor::DataPoint lastPoint; qreal lastAreaBoundingValue = 0; // Get min. y value, used as lower or upper bounding for area highlighting const qreal minYValue = qMin(plane->visibleDataRange().bottom(), plane->visibleDataRange().top()); CartesianDiagramDataCompressor::CachePosition previousCellPosition; for ( int row = 0; row < rowCount; ++row ) { const CartesianDiagramDataCompressor::CachePosition position( row, column ); // get where to draw the line from: CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); if ( point.hidden ) { continue; } const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); const LineAttributes laCell = diagram()->lineAttributes( sourceIndex ); const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy(); // lower or upper bounding for the highlighted area qreal areaBoundingValue; if ( laCell.areaBoundingDataset() != -1 ) { const CartesianDiagramDataCompressor::CachePosition areaBoundingCachePosition( row, laCell.areaBoundingDataset() ); areaBoundingValue = compressor().data( areaBoundingCachePosition ).value; } else { // Use min. y value (i.e. zero line in most cases) if no bounding dataset is set areaBoundingValue = minYValue; } if ( ISNAN( point.value ) ) { switch ( policy ) { case LineAttributes::MissingValuesAreBridged: // we just bridge both values continue; case LineAttributes::MissingValuesShownAsZero: // set it to zero point.value = 0.0; break; case LineAttributes::MissingValuesHideSegments: // they're just hidden break; default: break; // hm.... } } if ( !ISNAN( point.value ) ) { // area corners, a + b are the line ends: const qreal offset = diagram()->centerDataPoints() ? 0.5 : 0; const QPointF a( plane->translate( QPointF( lastPoint.key + offset, lastPoint.value ) ) ); const QPointF b( plane->translate( QPointF( point.key + offset, point.value ) ) ); const QPointF c( plane->translate( QPointF( lastPoint.key + offset, lastAreaBoundingValue ) ) ); const QPointF d( plane->translate( QPointF( point.key + offset, areaBoundingValue ) ) ); const PositionPoints pts = PositionPoints( b, a, d, c ); // add label m_private->addLabel( &lpc, sourceIndex, &position, pts, Position::NorthWest, Position::NorthWest, point.value ); // add line and area, if switched on and we have a current and previous value if ( !ISNAN( lastPoint.value ) ) { lineList.append( LineAttributesInfo( sourceIndex, a, b ) ); if ( laCell.displayArea() ) { QList<QPolygonF> areas; areas << ( QPolygonF() << a << b << d << c ); PaintingHelpers::paintAreas( m_private, ctx, attributesModel()->mapToSource( lastPoint.index ), areas, laCell.transparency() ); } } } previousCellPosition = position; laPreviousCell = laCell; lastAreaBoundingValue = areaBoundingValue; lastPoint = point; } } // paint the lines PaintingHelpers::paintElements( m_private, ctx, lpc, lineList ); }