# KDChartTernaryCoordinatePlane.cpp

Go to the documentation of this file.

    00001 /* -*- Mode: C++ -*-
    00002    KDChart - a multi-platform charting engine
    00003    */
    00004
    00005 /****************************************************************************
    00006  ** Copyright (C) 2005-2007 Klarälvdalens Datakonsult AB.  All rights reserved.
    00007  **
    00008  ** This file is part of the KD Chart library.
    00009  **
    00010  ** This file may be distributed and/or modified under the terms of the
    00011  ** GNU General Public License version 2 as published by the Free Software
    00012  ** Foundation and appearing in the file LICENSE.GPL included in the
    00013  ** packaging of this file.
    00014  **
    00015  ** Licensees holding valid commercial KD Chart licenses may use this file in
    00016  ** accordance with the KD Chart Commercial License Agreement provided with
    00017  ** the Software.
    00018  **
    00019  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    00020  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    00021  **
    00022  ** See http://www.kdab.net/kdchart for
    00023  **   information about KD Chart Commercial License Agreements.
    00024  **
    00025  ** Contact info@kdab.net if any conditions of this
    00026  ** licensing are not clear to you.
    00027  **
    00028  **********************************************************************/
    00029
    00030 #include <QtDebug>
    00031 #include <QPainter>
    00032
    00033 #include "KDChartPaintContext.h"
    00034 #include "KDChartPainterSaver_p.h"
    00035 #include "KDChartTernaryAxis.h"
    00036 #include "KDChartAbstractTernaryDiagram.h"
    00037 #include "KDChartTernaryCoordinatePlane.h"
    00038 #include "KDChartTernaryCoordinatePlane_p.h"
    00039
    00040 #include "TernaryConstants.h"
    00041
    00042 using namespace KDChart;
    00043
    00044 #define d d_func()
    00045
    00046 TernaryCoordinatePlane::Private::Private()
    00047     : AbstractCoordinatePlane::Private()
    00048 {
    00049 }
    00050
    00051 TernaryCoordinatePlane::TernaryCoordinatePlane( Chart* parent )
    00052     : AbstractCoordinatePlane( new Private(), parent )
    00053 {
    00054 }
    00055
    00056 TernaryCoordinatePlane::~TernaryCoordinatePlane()
    00057 {
    00058 }
    00059
    00060 void TernaryCoordinatePlane::init()
    00061 {
    00062 }
    00063
    00064 void TernaryCoordinatePlane::addDiagram( AbstractDiagram* diagram )
    00065 {
    00066     Q_ASSERT_X ( dynamic_cast<AbstractTernaryDiagram*>( diagram ),
    00067                  "TernaryCoordinatePlane::addDiagram", "Only ternary "
    00068                  "diagrams can be added to a ternary coordinate plane!" );
    00069     AbstractCoordinatePlane::addDiagram ( diagram );
    00070 //     connect ( diagram,  SIGNAL ( layoutChanged ( AbstractDiagram* ) ),
    00071 //               SLOT ( slotLayoutChanged ( AbstractDiagram* ) ) );
    00072 //     connect( diagram, SIGNAL( propertiesChanged() ),this, SIGNAL( propertiesChanged() ) );
    00073 }
    00074
    00075 void TernaryCoordinatePlane::layoutDiagrams()
    00076 {   // this is our "resize event":
    00077     // all diagrams always take the same space, nothing to be done here
    00078     // the "inner" margin (adjustments to diagram coordinates)
    00079     QRectF diagramNativeRectangle ( QPointF( 0.0, 0.0 ),
    00080                                     QSizeF( TriangleWidth, TriangleHeight ) );
    00081     QPair<QSizeF, QSizeF> margins = grid()->requiredMargins();
    00082     d->diagramRect = areaGeometry();
    00083     diagramNativeRectangle.adjust
    00084         (-margins.first.width(), -margins.first.height(),
    00085          margins.second.width(), margins.second.height() );
    00086
    00087     // the "outer" margin (distance between diagram contents and area,
    00088     // determined by axis label overlap
    00089     {
    00090         QSizeF topleft( 0.0, 0.0 );
    00091         QSizeF bottomRight( 0.0, 0.0 );
    00092         Q_FOREACH( AbstractDiagram* abstractDiagram, diagrams() ) {
    00093             AbstractTernaryDiagram* diagram =
    00094                 qobject_cast<AbstractTernaryDiagram*>( abstractDiagram );
    00095             Q_ASSERT( diagram );
    00096             Q_FOREACH( TernaryAxis* axis, diagram->axes() ) {
    00097                 QPair<QSizeF, QSizeF> margin = axis->requiredMargins();
    00098                 topleft = topleft.expandedTo( margin.first );
    00099                 bottomRight = bottomRight.expandedTo( margin.second );
    00100             }
    00101         }
    00102         d->diagramRectContainer =
    00103             d->diagramRect.adjusted( topleft.width(),
    00104                                      topleft.height(),
    00105                                      -bottomRight.width(),
    00106                                      -bottomRight.height() );
    00107     }
    00108
    00109     // now calculate isometric projection, x and y widget coordinate
    00110     // units, and location of (0.0, 0.0) in diagram coordinates
    00111     QPointF zeroZeroPoint = d->diagramRectContainer.bottomLeft();
    00112     double w = d->diagramRectContainer.width();
    00113     double h = d->diagramRectContainer.height();
    00114     double usableWidth;
    00115     double usableHeight;
    00116
    00117     if ( TriangleHeight * w > h ) {
    00118         // shorten width:
    00119         usableWidth = h / diagramNativeRectangle.height();
    00120         usableHeight = h;
    00121         zeroZeroPoint.setX( zeroZeroPoint.x() + ( w - usableWidth ) / 2 );
    00122     } else {
    00123         // reduce height:
    00124         usableWidth = w;
    00125         usableHeight = diagramNativeRectangle.height() * w;
    00126         zeroZeroPoint.setY( zeroZeroPoint.y() - ( h - usableHeight ) / 2 );
    00127     }
    00128     // the rectangle has 1 as it's width, and TriangleHeight as it's
    00129     // height - so this is how we translate that to widget coordinates:
    00130     d->xUnit = usableWidth / diagramNativeRectangle.width(); // only because we normalize the values to [0..1]
    00131     d->yUnit = -usableHeight / diagramNativeRectangle.height();
    00132
    00133     // now move zeroZeroPoint so that it does not include the tick marks
    00134     {
    00135         double descent = diagramNativeRectangle.height() - TriangleHeight;
    00136         double rightShift = -diagramNativeRectangle.x();
    00137         zeroZeroPoint += QPointF( rightShift * d->xUnit, descent * d->yUnit );
    00138     }
    00139
    00140     d->diagramRect.setBottomLeft( zeroZeroPoint );
    00141     d->diagramRect.setTopRight( QPointF( usableWidth, -usableHeight ) + zeroZeroPoint );
    00142 }
    00143
    00144 const QPointF TernaryCoordinatePlane::translate( const QPointF& point ) const
    00145 {
    00146     return QPointF( d->diagramRect.bottomLeft().x() + point.x() * d->xUnit,
    00147                     d->diagramRect.bottomLeft().y() + point.y() * d->yUnit );
    00148 }
    00149
    00150 QSize TernaryCoordinatePlane::minimumSizeHint() const
    00151 {
    00152     // FIXME temp
    00153     return QSize();
    00154 }
    00155
    00156 QSizePolicy TernaryCoordinatePlane::sizePolicy() const
    00157 {
    00158     return QSizePolicy( QSizePolicy::MinimumExpanding,
    00159                         QSizePolicy::MinimumExpanding );
    00160 }
    00161
    00162 void TernaryCoordinatePlane::paint( QPainter* painter )
    00163 {
    00164     PainterSaver s( painter );
    00165     // FIXME: this is not a good location for that:
    00166     painter->setRenderHint(QPainter::Antialiasing, true );
    00167
    00168 //     painter->setPen( QColor( "gold" ) );
    00169 //     painter->setBrush( QColor( "gold" ) );
    00170 //     painter->drawRect( d->diagramRectContainer );
    00171
    00172     AbstractDiagramList diags = diagrams();
    00173     if ( !diags.isEmpty() )
    00174     {
    00175         PaintContext ctx;
    00176         ctx.setPainter ( painter );
    00177         ctx.setCoordinatePlane ( this );
    00178         const QRectF drawArea( areaGeometry() );
    00179         ctx.setRectangle ( drawArea );
    00180
    00181         // enabling clipping so that we're not drawing outside
    00182 //         QRect clipRect = drawArea.toRect().adjusted( -1, -1, 1, 1 );
    00183 //         QRegion clipRegion( clipRect );
    00184 //         painter->setClipRegion( clipRegion );
    00185
    00186         // paint the coordinate system rulers:
    00187         Q_ASSERT( d->grid != 0 );
    00188         d->grid->drawGrid( &ctx );
    00189
    00190         // paint the diagrams:
    00191         for ( int i = 0; i < diags.size(); i++ )
    00192         {
    00193             PainterSaver diagramPainterSaver( painter );
    00194             diags[i]->paint ( &ctx );
    00195         }
    00196     }
    00197 }
    00198
    00199 DataDimensionsList TernaryCoordinatePlane::getDataDimensionsList() const
    00200 {   // not needed
    00201     return DataDimensionsList();
    00202 }
    00203
    00204 TernaryGrid* TernaryCoordinatePlane::grid() const
    00205 {
    00206     TernaryGrid* ternaryGrid = static_cast<TernaryGrid*>( d->grid );
    00207     Q_ASSERT( dynamic_cast<TernaryGrid*>( d->grid ) );
    00208     return ternaryGrid;
    00209 }
    00210
    00211 #undef d