void TernaryAxis::paintCtx (PaintContext * paintContext) { QPainter* p = paintContext->painter(); TernaryCoordinatePlane* plane = (TernaryCoordinatePlane*) paintContext->coordinatePlane(); // QObject* refArea = plane->parent(); QRectF titleArea; // paint the axis label (across the triangle, that one): QList<PrerenderedLabel*> labels; labels << m_label << m_fifty; Q_FOREACH( PrerenderedLabel* label, labels ) { const QPixmap& pixmap = label->pixmap(); QPointF point = plane->translate( label->position() ) - label->referencePointLocation(); p->drawPixmap( point, pixmap ); } }
void TernaryGrid::drawGrid( PaintContext* context ) { static const int GridLineDistanceTreshold = 20; // <Treshold> pixels between each grid line QPainter& painter = *context->painter(); // recover from pointer madness PainterSaver s( &painter ); // can i have a reference based version of that? TernaryCoordinatePlane* plane = dynamic_cast<TernaryCoordinatePlane*>(context->coordinatePlane()); Q_ASSERT_X ( plane, "TernaryGrid::drawGrid", "Bad function call: PaintContext::coodinatePlane() NOT a ternary plane." ); // translate the points and see how many grid lines we can draw: const int MaxDepth = 3; qreal xPixels = plane->translate( TriangleBottomRight ).x() - plane->translate( TriangleBottomLeft ).x(); int granularity = 20; if ( xPixels > 10 * GridLineDistanceTreshold ) granularity = 10; if ( xPixels > 20 * GridLineDistanceTreshold ) granularity = 5; m_tickInfo.clear(); for ( int i = granularity; i < 100; i+=granularity ) { TickInfo tick( ( 1.0 * i ) / 100.0, 2 ); if ( i % 10 == 0 ) tick.depth = 1; if ( i % 20 == 0 ) tick.depth = 0; m_tickInfo.append( tick ); } QVector<QLineF> lines[MaxDepth]; {Q_FOREACH( const TickInfo& tick, m_tickInfo ) { const qreal& percent = tick.percentage; { // draw parallels to B TernaryPoint ternaryStart( percent, 1.0 - percent ); TernaryPoint ternaryEnd( 0.0, 1.0 - percent ); QPointF start( translate( ternaryStart ) ); QPointF end( translate( ternaryEnd ) ); lines[tick.depth].append( QLineF( plane->translate( start ), plane->translate( end ) ) ); } { // draw parallels to C TernaryPoint ternaryStart( percent, 0.0 ); TernaryPoint ternaryEnd( 0.0, percent ); QPointF start( translate( ternaryStart ) ); QPointF end( translate( ternaryEnd ) ); lines[tick.depth].append( QLineF( plane->translate( start ), plane->translate( end ) ) ); } { // draw parallels to A TernaryPoint ternaryStart( percent, 1.0 - percent ); TernaryPoint ternaryEnd( percent, 0.0 ); QPointF start( translate( ternaryStart ) ); QPointF end( translate( ternaryEnd ) ); lines[tick.depth].append( QLineF( plane->translate( start ), plane->translate( end ) ) ); } }} // now draw the lines: painter.setPen( PrintingParameters::scalePen( QPen( QColor( "lightgray" ), 1 ) ) ); painter.setBrush( QColor( "lightgray" ) ); painter.drawLines( lines[2] ); painter.setPen( PrintingParameters::scalePen( QPen( QColor( "gray" ), 1 ) ) ); painter.setBrush( QColor( "gray" ) ); painter.drawLines( lines[1] ); painter.setPen( PrintingParameters::scalePen( QPen( QColor( "darkslategray" ), 1 ) ) ); painter.setBrush( QColor( "darkslategray" ) ); painter.drawLines( lines[0] ); // now draw the triangle (this could be part of the axis, in fact): painter.setPen( PrintingParameters::scalePen( QPen( Qt::black, 1 ) ) ); // make sure this does not fill, otherwise it wipes the contents // of the triangle (doh!): painter.setBrush( Qt::NoBrush ); QPolygonF points; points << plane->translate( TriangleBottomLeft ) << plane->translate( TriangleBottomRight ) << plane->translate( TriangleTop ); painter.drawPolygon( points ); // now draw the ticks: painter.setPen( PrintingParameters::scalePen( QPen( Qt::black ) ) ); painter.setBrush( Qt::black ); QVector<QLineF> ticks; // prepare list of percentages, then calculate lines: QVector<TickInfo> percentages( m_tickInfo ); // I have commented those out, I think it looks ugly if they are // enabled: // percentages.prepend( 0.0 ); // percentages.append( 1.0 ); // FIXME this may need a predicate that takes eplison into account // (but it does not hurt, since it will not make the painter // paint two lines): percentages.erase( std::unique( percentages.begin(), percentages.end() ), percentages.end() ); {Q_FOREACH( const TickInfo& tick, percentages ) { const qreal& percent = tick.percentage; { // BC axis markers: const QPointF markerDistance( FullMarkerDistanceBC / ( tick.depth + 1 ) ); QPointF start( percent, 0.0 ); ticks.append( QLineF( plane->translate( start ), plane->translate( start - markerDistance ) ) ); } { // AC axis markers: const QPointF markerDistance( FullMarkerDistanceAC / ( tick.depth + 1 ) ); const QPointF start( TriangleBottomRight + percent * AxisVector_C_A ); const QPointF end( start + markerDistance ); ticks.append( QLineF( plane->translate( start ), plane->translate( end ) ) ); } { // AB axis markers: const QPointF markerDistance( FullMarkerDistanceBA / ( tick.depth +1 ) ); const QPointF start( percent * AxisVector_B_A ); const QPointF end( start + markerDistance ); ticks.append( QLineF( plane->translate( start ), plane->translate( end ) ) ); } }} painter.drawLines( ticks ); }
void TernaryPointDiagram::paint (PaintContext *paintContext) { d->reverseMapper.clear(); d->paint( paintContext ); // sanity checks: if ( model() == 0 ) return; QPainter* p = paintContext->painter(); PainterSaver s( p ); TernaryCoordinatePlane* plane = static_cast< TernaryCoordinatePlane* >( paintContext->coordinatePlane() ); Q_ASSERT( plane ); qreal x, y, z; // for some reason(?) TernaryPointDiagram is using per-diagram DVAs only: const DataValueAttributes attrs( dataValueAttributes() ); d->forgetAlreadyPaintedDataValues(); int columnCount = model()->columnCount( rootIndex() ); for (int column=0; column<columnCount; column+=datasetDimension() ) { int numrows = model()->rowCount( rootIndex() ); for ( int row = 0; row < numrows; row++ ) { QModelIndex base = model()->index( row, column, rootIndex() ); // checked // see if there is data otherwise skip if ( ! model()->data( base ).isNull() ) { p->setPen( PrintingParameters::scalePen( pen( base ) ) ); p->setBrush( brush( base ) ); // retrieve data x = qMax( model()->data( model()->index( row, column+0, rootIndex() ) ).toReal(), // checked 0.0 ); y = qMax( model()->data( model()->index( row, column+1, rootIndex() ) ).toReal(), // checked 0.0 ); z = qMax( model()->data( model()->index( row, column+2, rootIndex() ) ).toReal(), // checked 0.0 ); // fix messed up data values (paint as much as possible) qreal total = x + y + z; if ( fabs( total ) > 3 * std::numeric_limits<qreal>::epsilon() ) { TernaryPoint tPunkt( x / total, y / total ); QPointF diagramLocation = translate( tPunkt ); QPointF widgetLocation = plane->translate( diagramLocation ); paintMarker( p, model()->index( row, column, rootIndex() ), widgetLocation ); // checked QString text = tr( "(%1, %2, %3)" ) .arg( x * 100, 0, 'f', 0 ) .arg( y * 100, 0, 'f', 0 ) .arg( z * 100, 0, 'f', 0 ); d->paintDataValueText( p, attrs, widgetLocation, true, text, true ); } else { // ignore and do not paint this point, garbage data qDebug() << "TernaryPointDiagram::paint: data point x/y/z:" << x << "/" << y << "/" << z << "ignored, unusable."; } } } } }