void LineDiagram::LineDiagramType::paintValueTracker( PaintContext* ctx, const ValueTrackerAttributes& vt, const QPointF& at ) { CartesianCoordinatePlane* plane = qobject_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() ); if( !plane ) return; DataDimensionsList gridDimensions = ctx->coordinatePlane()->gridDimensionsList(); const QPointF bottomLeft( ctx->coordinatePlane()->translate( QPointF( plane->isHorizontalRangeReversed() ? gridDimensions.at( 0 ).end : gridDimensions.at( 0 ).start, plane->isVerticalRangeReversed() ? gridDimensions.at( 1 ).end : gridDimensions.at( 1 ).start ) ) ); const QPointF markerPoint = at; const QPointF ordinatePoint( bottomLeft.x(), at.y() ); const QPointF abscissaPoint( at.x(), bottomLeft.y() ); const QSizeF markerSize = vt.markerSize(); const QRectF ellipseMarker = QRectF( at.x() - markerSize.width() / 2, at.y() - markerSize.height() / 2, markerSize.width(), markerSize.height() ); const QPointF ordinateMarker[3] = { QPointF( ordinatePoint.x(), at.y() + markerSize.height() / 2 ), QPointF( ordinatePoint.x() + markerSize.width() / 2, at.y() ), QPointF( ordinatePoint.x(), at.y() - markerSize.height() / 2 ) }; const QPointF abscissaMarker[3] = { QPointF( at.x() + markerSize.width() / 2, abscissaPoint.y() ), QPointF( at.x(), abscissaPoint.y() - markerSize.height() / 2 ), QPointF( at.x() - markerSize.width() / 2, abscissaPoint.y() ) }; QPointF topLeft = ordinatePoint; QPointF bottomRightOffset = abscissaPoint - topLeft; QSizeF size( bottomRightOffset.x(), bottomRightOffset.y() ); QRectF area( topLeft, size ); PainterSaver painterSaver( ctx->painter() ); ctx->painter()->setPen( PrintingParameters::scalePen( vt.pen() ) ); ctx->painter()->setBrush( QBrush() ); ctx->painter()->drawLine( markerPoint, ordinatePoint ); ctx->painter()->drawLine( markerPoint, abscissaPoint ); ctx->painter()->fillRect( area, vt.areaBrush() ); ctx->painter()->drawEllipse( ellipseMarker ); ctx->painter()->setBrush( vt.pen().color() ); ctx->painter()->drawPolygon( ordinateMarker, 3 ); ctx->painter()->drawPolygon( abscissaMarker, 3 ); }
void Plotter::calcMergeRadius() { CartesianCoordinatePlane *plane = dynamic_cast< CartesianCoordinatePlane* >( coordinatePlane() ); Q_ASSERT( plane ); //Q_ASSERT( plane->translate( plane->translateBack( plane->visibleDiagramArea().topLeft() ) ) == plane->visibleDiagramArea().topLeft() ); QRectF range = plane->visibleDataRange(); //qDebug() << range; const qreal radius = std::sqrt( ( range.x() + range.width() ) * ( range.y() + range.height() ) ); //qDebug() << radius; //qDebug() << radius * d->mergeRadiusPercentage; //qDebug() << d->mergeRadiusPercentage; d->plotterCompressor.setMergeRadius( radius * d->mergeRadiusPercentage ); }
void MainWindow::on_fixPlaneSizeCB_toggled( bool checked ) { CartesianCoordinatePlane* plane = qobject_cast<CartesianCoordinatePlane*>( m_chart->coordinatePlane() ); if ( plane == 0 ) return; plane->setFixedDataCoordinateSpaceRelation( checked ); // just a little adjustment: // Reset the zoom settings to their initial values // when the releation-adjust checkbox is unchecked: if ( ! checked ) { m_chart->coordinatePlane()->setZoomFactorX( 1.0 ); m_chart->coordinatePlane()->setZoomFactorY( 1.0 ); m_chart->coordinatePlane()->setZoomCenter( QPointF(0.5, 0.5) ); } m_chart->update(); }
void DiagramTypeDialog::Private::createPlanes() { m_planes[ DiagramTypeDialog::Bar ] = m_chart->coordinatePlane(); m_planes[ DiagramTypeDialog::LyingBar ] = m_chart->coordinatePlane(); CartesianCoordinatePlane *linePlane = new CartesianCoordinatePlane; linePlane->addDiagram( new LineDiagram ); m_planes[ DiagramTypeDialog::Line ] = linePlane; CartesianCoordinatePlane *plotterPlane = new CartesianCoordinatePlane; plotterPlane->addDiagram( new KDChart::Plotter ); m_planes[ DiagramTypeDialog::Plotter ] = plotterPlane; PolarCoordinatePlane *piePlane = new PolarCoordinatePlane; piePlane->addDiagram( new PieDiagram ); m_planes[ DiagramTypeDialog::Pie ] = piePlane; }
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 CartesianGrid::drawGrid( PaintContext* context ) { //qDebug() << "KDChart::CartesianGrid::drawGrid( PaintContext* context ) called"; CartesianCoordinatePlane* plane = dynamic_cast<CartesianCoordinatePlane*>(context->coordinatePlane()); // This plane is used for tranlating the coordinates - not for the data boundaries PainterSaver p( context->painter() ); plane = dynamic_cast< CartesianCoordinatePlane* >( plane->sharedAxisMasterPlane( context->painter() ) ); Q_ASSERT_X ( plane, "CartesianGrid::drawGrid", "Bad function call: PaintContext::coodinatePlane() NOT a cartesian plane." ); const GridAttributes gridAttrsX( plane->gridAttributes( Qt::Horizontal ) ); const GridAttributes gridAttrsY( plane->gridAttributes( Qt::Vertical ) ); //qDebug() << "OK:"; if ( !gridAttrsX.isGridVisible() && !gridAttrsY.isGridVisible() ) return; //qDebug() << "A"; // important: Need to update the calculated mData, // before we may use it! updateData( context->coordinatePlane() ); if( plane->axesCalcModeX() == KDChart::AbstractCoordinatePlane::Logarithmic && mData.first().stepWidth == 0.0 ) mData.first().stepWidth = 1.0; if( plane->axesCalcModeY() == KDChart::AbstractCoordinatePlane::Logarithmic && mData.last().stepWidth == 0.0 ) mData.last().stepWidth = 1.0; // test for programming errors: critical Q_ASSERT_X ( mData.count() == 2, "CartesianGrid::drawGrid", "Error: updateData did not return exactly two dimensions." ); // test for invalid boundaries: non-critical if( !isBoundariesValid( mData ) ) return; //qDebug() << "B"; DataDimension dimX = mData.first(); const DataDimension& dimY = mData.last(); // test for other programming errors: critical Q_ASSERT_X ( dimX.stepWidth, "CartesianGrid::drawGrid", "Error: updateData returned a Zero step width for the X grid." ); Q_ASSERT_X ( dimY.stepWidth, "CartesianGrid::drawGrid", "Error: updateData returned a Zero step width for the Y grid." ); qreal numberOfUnitLinesX = qAbs( dimX.distance() / dimX.stepWidth ) + (dimX.isCalculated ? 1.0 : 0.0); qreal numberOfUnitLinesY = qAbs( dimY.distance() / dimY.stepWidth ) + (dimY.isCalculated ? 1.0 : 0.0); //qDebug("numberOfUnitLinesX: %f numberOfUnitLinesY: %f",numberOfUnitLinesX,numberOfUnitLinesY); // do not draw a Zero size grid (and do not divide by Zero) if( numberOfUnitLinesX <= 0.0 || numberOfUnitLinesY <= 0.0 ) return; //qDebug() << "C"; const QPointF p1 = plane->translate( QPointF(dimX.start, dimY.start) ); const QPointF p2 = plane->translate( QPointF(dimX.end, dimY.end) ); //qDebug() << "dimX.isCalculated:" << dimX.isCalculated << "dimY.isCalculated:" << dimY.isCalculated; //qDebug() << "dimX.start: " << dimX.start << "dimX.end: " << dimX.end; //qDebug() << "dimY.start: " << dimY.start << "dimY.end: " << dimY.end; //qDebug() << "p1:" << p1 << " p2:" << p2; const qreal screenRangeX = qAbs ( p1.x() - p2.x() ); const qreal screenRangeY = qAbs ( p1.y() - p2.y() ); /* * let us paint the grid at a smaller resolution * the user can disable at any time * by setting the grid attribute to false * Same Value as for Cartesian Axis */ static const qreal GridLineDistanceTreshold = 4.0; // <Treshold> pixels between each grid line const qreal MinimumPixelsBetweenLines = GridLineDistanceTreshold; //qDebug() << "x step " << dimX.stepWidth << " y step " << dimY.stepWidth; //qreal unitFactorX = 1.0; // qreal unitFactorY = 1.0; //FIXME(khz): Remove this code, and do the calculation in the grid calc function if( ! dimX.isCalculated ){ while( screenRangeX / numberOfUnitLinesX <= MinimumPixelsBetweenLines ){ dimX.stepWidth *= 10.0; dimX.subStepWidth *= 10.0; numberOfUnitLinesX = qAbs( dimX.distance() / dimX.stepWidth ); } } if( dimX.subStepWidth && (screenRangeX / (dimX.distance() / dimX.subStepWidth) <= MinimumPixelsBetweenLines) ){ dimX.subStepWidth = 0.0; //qDebug() << "de-activating grid sub steps: not enough space"; } const bool drawUnitLinesX = gridAttrsX.isGridVisible() && (screenRangeX / numberOfUnitLinesX > MinimumPixelsBetweenLines); const bool drawUnitLinesY = gridAttrsY.isGridVisible() && (screenRangeY / numberOfUnitLinesY > MinimumPixelsBetweenLines); const bool isLogarithmicX = dimX.isCalculated && (dimX.calcMode == AbstractCoordinatePlane::Logarithmic ); const bool isLogarithmicY = (dimY.calcMode == AbstractCoordinatePlane::Logarithmic ); /* while ( !drawUnitLinesX ) { unitFactorX *= 10.0; drawUnitLinesX = screenRangeX / (numberOfUnitLinesX / unitFactorX) > MinimumPixelsBetweenLines; } while ( !drawUnitLinesY ) { unitFactorY *= 10.0; drawUnitLinesY = screenRangeY / (numberOfUnitLinesY / unitFactorY) > MinimumPixelsBetweenLines; } */ const bool drawSubGridLinesX = isLogarithmicX || ((dimX.subStepWidth != 0.0) && (screenRangeX / (numberOfUnitLinesX / dimX.stepWidth * dimX.subStepWidth) > MinimumPixelsBetweenLines) && gridAttrsX.isSubGridVisible()); const bool drawSubGridLinesY = isLogarithmicY || ((dimY.subStepWidth != 0.0) && (screenRangeY / (numberOfUnitLinesY / dimY.stepWidth * dimY.subStepWidth) > MinimumPixelsBetweenLines) && gridAttrsY.isSubGridVisible()); qreal minValueX = qMin( dimX.start, dimX.end ); qreal maxValueX = qMax( dimX.start, dimX.end ); qreal minValueY = qMin( dimY.start, dimY.end ); qreal maxValueY = qMax( dimY.start, dimY.end ); AbstractGrid::adjustLowerUpperRange( minValueX, maxValueX, dimX.stepWidth, true, true ); AbstractGrid::adjustLowerUpperRange( minValueY, maxValueY, dimY.stepWidth, true, true ); if ( drawSubGridLinesX ) { context->painter()->setPen( PrintingParameters::scalePen( gridAttrsX.subGridPen() ) ); qreal f = minValueX; qreal fLogSubstep = minValueX; int logSubstep = 0; while ( f <= maxValueX ) { QPointF topPoint( f, maxValueY ); QPointF bottomPoint( f, minValueY ); topPoint = plane->translate( topPoint ); bottomPoint = plane->translate( bottomPoint ); context->painter()->drawLine( topPoint, bottomPoint ); if ( isLogarithmicX ){ if( logSubstep == 9 ){ fLogSubstep *= ( fLogSubstep > 0.0 ) ? 10.0 : 0.1; if( fLogSubstep == 0.0 ) fLogSubstep = pow( 10.0, floor( log10( dimX.start ) ) ); logSubstep = 0; f = fLogSubstep; } else { f += fLogSubstep; } ++logSubstep; }else{ f += dimX.subStepWidth; } if(maxValueX == 0 && minValueX == 0) break; } } if ( drawSubGridLinesY ) { context->painter()->setPen( PrintingParameters::scalePen( gridAttrsY.subGridPen() ) ); qreal f = minValueY; qreal fLogSubstep = minValueY; int logSubstep = 0; while ( f <= maxValueY ) { //qDebug() << "sub grid line Y at" << f; QPointF leftPoint( minValueX, f ); QPointF rightPoint( maxValueX, f ); leftPoint = plane->translate( leftPoint ); rightPoint = plane->translate( rightPoint ); context->painter()->drawLine( leftPoint, rightPoint ); if ( isLogarithmicY ){ if( logSubstep == 9 ){ fLogSubstep *= ( fLogSubstep > 0.0 ) ? 10.0 : 0.1; if( fLogSubstep == 0.0 ) fLogSubstep = pow( 10.0, floor( log10( dimY.start ) ) ); logSubstep = 0; f = fLogSubstep; } else { f += fLogSubstep; } ++logSubstep; }else{ f += dimY.subStepWidth; } if(maxValueY == 0 && minValueY == 0) break; } } const bool drawXZeroLineX = dimX.isCalculated && gridAttrsX.zeroLinePen().style() != Qt::NoPen; const bool drawZeroLineY = gridAttrsY.zeroLinePen().style() != Qt::NoPen; const bool drawOuterX = gridAttrsX.isOuterLinesVisible(); const bool drawOuterY = gridAttrsY.isOuterLinesVisible(); const QPointF bottomRightPoint = plane->translate( QPointF( maxValueX, minValueY ) ); if ( drawUnitLinesX || drawXZeroLineX ) { //qDebug() << "E"; if ( drawUnitLinesX ) context->painter()->setPen( PrintingParameters::scalePen( gridAttrsX.gridPen() ) ); // const qreal minX = dimX.start; qreal f = minValueX; while ( f <= maxValueX ) { // PENDING(khz) FIXME: make draving/not drawing of Zero line more sophisticated?: const bool zeroLineHere = drawXZeroLineX && (f == 0.0); if ( drawUnitLinesX || zeroLineHere ){ //qDebug("main grid line X at: %f --------------------------",f); QPointF topPoint( f, maxValueY ); QPointF bottomPoint( f, minValueY ); topPoint = plane->translate( topPoint ); bottomPoint = plane->translate( bottomPoint ); const qreal penWidth = context->painter()->pen().widthF(); if ( zeroLineHere ) context->painter()->setPen( PrintingParameters::scalePen( gridAttrsX.zeroLinePen() ) ); if ( drawOuterX || (topPoint.x()> 2 * penWidth && topPoint.x()<bottomRightPoint.x()-2.0 * penWidth) ) context->painter()->drawLine( topPoint, bottomPoint ); if ( zeroLineHere ) context->painter()->setPen( PrintingParameters::scalePen( gridAttrsX.gridPen() ) ); } if ( isLogarithmicX ) { f *= ( f > 0.0 ) ? 10.0 : 0.1; if( f == 0.0 ) f = pow( 10.0, floor( log10( dimX.start ) ) ); } else f += dimX.stepWidth; if(maxValueX == 0 && minValueX == 0) break; } // draw the last line if not logarithmic calculation // we need the in order to get the right grid line painted // when f + dimX.stepWidth jump over maxValueX if ( ! isLogarithmicX && drawOuterX ) context->painter()->drawLine( plane->translate( QPointF( maxValueX, maxValueY ) ), plane->translate( QPointF( maxValueX, minValueY ) ) ); } if ( drawUnitLinesY || drawZeroLineY ) { //qDebug() << "F"; if ( drawUnitLinesY ) context->painter()->setPen( PrintingParameters::scalePen( gridAttrsY.gridPen() ) ); //const qreal minY = dimY.start; //qDebug("minY: %f maxValueY: %f dimY.stepWidth: %f",minY,maxValueY,dimY.stepWidth); qreal f = minValueY; while ( f <= maxValueY ) { // PENDING(khz) FIXME: make draving/not drawing of Zero line more sophisticated?: //qDebug("main grid line Y at: %f",f); const bool zeroLineHere = (f == 0.0); if ( drawUnitLinesY || zeroLineHere ){ QPointF leftPoint( minValueX, f ); QPointF rightPoint( maxValueX, f ); leftPoint = plane->translate( leftPoint ); rightPoint = plane->translate( rightPoint ); if ( zeroLineHere ) context->painter()->setPen( PrintingParameters::scalePen( gridAttrsY.zeroLinePen() ) ); if ( drawOuterY || (leftPoint.y()>2.0 && leftPoint.y()<bottomRightPoint.y()-2.0) ) context->painter()->drawLine( leftPoint, rightPoint ); if ( zeroLineHere ) context->painter()->setPen( PrintingParameters::scalePen( gridAttrsY.gridPen() ) ); } if ( isLogarithmicY ) { f *= ( f > 0.0 ) ? 10.0 : 0.1; if( f == 0.0 ) f = pow( 10.0, floor( log10( dimY.start ) ) ); } else f += dimY.stepWidth; if(maxValueY == 0 && minValueY == 0) break; } } //qDebug() << "Z"; }
DataDimensionsList CartesianGrid::calculateGrid( const DataDimensionsList& rawDataDimensions ) const { Q_ASSERT_X ( rawDataDimensions.count() == 2, "CartesianGrid::calculateGrid", "Error: calculateGrid() expects a list with exactly two entries." ); CartesianCoordinatePlane* plane = dynamic_cast<CartesianCoordinatePlane*>( mPlane ); Q_ASSERT_X ( plane, "CartesianGrid::calculateGrid", "Error: PaintContext::calculatePlane() called, but no cartesian plane set." ); DataDimensionsList l( rawDataDimensions ); // rule: Returned list is either empty, or it is providing two // valid dimensions, complete with two non-Zero step widths. if( isBoundariesValid( l ) ) { const QPointF translatedBottomLeft( plane->translateBack( plane->geometry().bottomLeft() ) ); const QPointF translatedTopRight( plane->translateBack( plane->geometry().topRight() ) ); //qDebug() << "CartesianGrid::calculateGrid() first:" << l.first().start << l.first().end << " last:" << l.last().start << l.last().end; //qDebug() << "CartesianGrid::calculateGrid() translated x:" << translatedBottomLeft.x() << translatedTopRight.x() << " y:" << translatedBottomLeft.y() << translatedTopRight.y(); //qDebug() << "CartesianGrid::calculateGrid() raw data y-range :" << l.last().end - l.last().start; //qDebug() << "CartesianGrid::calculateGrid() translated y-range:" << translatedTopRight.y() - translatedBottomLeft.y(); /* Code is obsolete. The dataset dimension of the diagram should *never* be > 1. if( l.first().isCalculated && plane->autoAdjustGridToZoom() && plane->axesCalcModeX() == CartesianCoordinatePlane::Linear && plane->zoomFactorX() > 1.0 ) { l.first().start = translatedBottomLeft.x(); l.first().end = translatedTopRight.x(); } */ const GridAttributes gridAttrsX( plane->gridAttributes( Qt::Horizontal ) ); const GridAttributes gridAttrsY( plane->gridAttributes( Qt::Vertical ) ); const DataDimension dimX = calculateGridXY( l.first(), Qt::Horizontal, gridAttrsX.adjustLowerBoundToGrid(), gridAttrsX.adjustUpperBoundToGrid() ); if( dimX.stepWidth ){ //qDebug("CartesianGrid::calculateGrid() l.last().start: %f l.last().end: %f", l.last().start, l.last().end); //qDebug(" l.first().start: %f l.first().end: %f", l.first().start, l.first().end); // one time for the min/max value const DataDimension minMaxY = calculateGridXY( l.last(), Qt::Vertical, gridAttrsY.adjustLowerBoundToGrid(), gridAttrsY.adjustUpperBoundToGrid() ); if( plane->autoAdjustGridToZoom() && plane->axesCalcModeY() == CartesianCoordinatePlane::Linear && plane->zoomFactorY() > 1.0 ) { l.last().start = translatedBottomLeft.y(); l.last().end = translatedTopRight.y(); } // and one other time for the step width const DataDimension dimY = calculateGridXY( l.last(), Qt::Vertical, gridAttrsY.adjustLowerBoundToGrid(), gridAttrsY.adjustUpperBoundToGrid() ); if( dimY.stepWidth ){ l.first().start = dimX.start; l.first().end = dimX.end; l.first().stepWidth = dimX.stepWidth; l.first().subStepWidth = dimX.subStepWidth; l.last().start = minMaxY.start; l.last().end = minMaxY.end; l.last().stepWidth = dimY.stepWidth; l.last().subStepWidth = dimY.subStepWidth; //qDebug() << "CartesianGrid::calculateGrid() final grid y-range:" << l.last().end - l.last().start << " step width:" << l.last().stepWidth << endl; // calculate some reasonable subSteps if the // user did not set the sub grid but did set // the stepWidth. // FIXME (Johannes) // the last (y) dimension is not always the dimension for the ordinate! // since there's no way to check for the orientation of this dimension here, // we cannot automatically assume substep values //if ( dimY.subStepWidth == 0 ) // l.last().subStepWidth = dimY.stepWidth/2; //else // l.last().subStepWidth = dimY.subStepWidth; } } } //qDebug() << "CartesianGrid::calculateGrid() final grid Y-range:" << l.last().end - l.last().start << " substep width:" << l.last().subStepWidth; //qDebug() << "CartesianGrid::calculateGrid() final grid X-range:" << l.first().end - l.first().start << " substep width:" << l.first().subStepWidth; return l; }
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 ); }
void paintValueTracker( PaintContext* ctx, const ValueTrackerAttributes& vt, const QPointF& at ) { CartesianCoordinatePlane* plane = qobject_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() ); if ( !plane ) return; DataDimensionsList gridDimensions = ctx->coordinatePlane()->gridDimensionsList(); const QPointF bottomLeft( ctx->coordinatePlane()->translate( QPointF( plane->isHorizontalRangeReversed() ? gridDimensions.at( 0 ).end : gridDimensions.at( 0 ).start, plane->isVerticalRangeReversed() ? gridDimensions.at( 1 ).end : gridDimensions.at( 1 ).start ) ) ); const QPointF topRight( ctx->coordinatePlane()->translate( QPointF( plane->isHorizontalRangeReversed() ? gridDimensions.at( 0 ).start : gridDimensions.at( 0 ).end, plane->isVerticalRangeReversed() ? gridDimensions.at( 1 ).start : gridDimensions.at( 1 ).end ) ) ); const QPointF markerPoint = at; QPointF startPoint; if ( vt.orientations() & Qt::Horizontal ) { startPoint = QPointF( bottomLeft.x(), at.y() ); } else { startPoint = QPointF( at.x(), topRight.y() ); } QPointF endPoint; if ( vt.orientations() & Qt::Vertical ) { endPoint = QPointF( at.x(), bottomLeft.y() ); } else { endPoint = QPointF( topRight.x(), at.y() ); } const QSizeF markerSize = vt.markerSize(); const QRectF ellipseMarker = QRectF( at.x() - markerSize.width() / 2, at.y() - markerSize.height() / 2, markerSize.width(), markerSize.height() ); QPointF startMarker[3]; if ( vt.orientations() & Qt::Horizontal ) { startMarker[0] = startPoint + QPointF( 0, markerSize.height() / 2 ); startMarker[1] = startPoint + QPointF( markerSize.width() / 2, 0 ); startMarker[2] = startPoint - QPointF( 0, markerSize.height() / 2 ); } else { startMarker[0] = startPoint + QPointF( 0, markerSize.height() / 2 ); startMarker[1] = startPoint + QPointF( markerSize.width() / 2, 0 ); startMarker[2] = startPoint - QPointF( markerSize.width() / 2, 0 ); } QPointF endMarker[3]; if ( vt.orientations() & Qt::Vertical ) { endMarker[0] = endPoint + QPointF( markerSize.width() / 2, 0 ); endMarker[1] = endPoint - QPointF( 0, markerSize.height() / 2 ); endMarker[2] = endPoint - QPointF( markerSize.width() / 2, 0 ); } else { endMarker[0] = endPoint + QPointF( 0, markerSize.width() / 2 ); endMarker[1] = endPoint - QPointF( 0, markerSize.height() / 2 ); endMarker[2] = endPoint - QPointF( markerSize.width() / 2, 0 ); } QPointF topLeft = startPoint; QPointF bottomRightOffset = endPoint - topLeft; QSizeF size( bottomRightOffset.x(), bottomRightOffset.y() ); QRectF area( topLeft, size ); PainterSaver painterSaver( ctx->painter() ); ctx->painter()->setPen( PrintingParameters::scalePen( vt.linePen() ) ); ctx->painter()->setBrush( QBrush() ); ctx->painter()->drawLine( markerPoint, startPoint ); ctx->painter()->drawLine( markerPoint, endPoint ); ctx->painter()->fillRect( area, vt.areaBrush() ); ctx->painter()->setPen( PrintingParameters::scalePen( vt.markerPen() ) ); ctx->painter()->setBrush( vt.markerBrush() ); ctx->painter()->drawEllipse( ellipseMarker ); ctx->painter()->setPen( PrintingParameters::scalePen( vt.arrowBrush().color() ) ); ctx->painter()->setBrush( vt.arrowBrush() ); ctx->painter()->drawPolygon( startMarker, 3 ); ctx->painter()->drawPolygon( endMarker, 3 ); }