KDChartTernaryCoordinatePlane.cpp

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