Example #1
0
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 );
    }
}
Example #2
0
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.";
                }
            }
        }
    }
}