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 "KDChartTernaryCoordinatePlane.h"
00031 #include "KDChartTernaryCoordinatePlane_p.h"
00032 
00033 #include <QtDebug>
00034 #include <QPainter>
00035 
00036 #include "KDChartPaintContext.h"
00037 #include "KDChartPainterSaver_p.h"
00038 #include "KDChartTernaryAxis.h"
00039 #include "KDChartAbstractTernaryDiagram.h"
00040 
00041 #include "TernaryConstants.h"
00042 
00043 using namespace KDChart;
00044 
00045 #define d d_func()
00046 
00047 TernaryCoordinatePlane::Private::Private()
00048     : AbstractCoordinatePlane::Private()
00049 {
00050 }
00051 
00052 TernaryCoordinatePlane::TernaryCoordinatePlane( Chart* parent )
00053     : AbstractCoordinatePlane( new Private(), parent )
00054 {
00055 }
00056 
00057 TernaryCoordinatePlane::~TernaryCoordinatePlane()
00058 {
00059 }
00060 
00061 void TernaryCoordinatePlane::init()
00062 {
00063 }
00064 
00065 void TernaryCoordinatePlane::addDiagram( AbstractDiagram* diagram )
00066 {
00067     Q_ASSERT_X ( dynamic_cast<AbstractTernaryDiagram*>( diagram ),
00068                  "TernaryCoordinatePlane::addDiagram", "Only ternary "
00069                  "diagrams can be added to a ternary coordinate plane!" );
00070     AbstractCoordinatePlane::addDiagram ( diagram );
00071 //     connect ( diagram,  SIGNAL ( layoutChanged ( AbstractDiagram* ) ),
00072 //               SLOT ( slotLayoutChanged ( AbstractDiagram* ) ) );
00073 //     connect( diagram, SIGNAL( propertiesChanged() ),this, SIGNAL( propertiesChanged() ) );
00074 }
00075 
00076 void TernaryCoordinatePlane::layoutDiagrams()
00077 {   // this is our "resize event":
00078     // all diagrams always take the same space, nothing to be done here
00079     // the "inner" margin (adjustments to diagram coordinates)
00080     QRectF diagramNativeRectangle ( QPointF( 0.0, 0.0 ),
00081                                     QSizeF( TriangleWidth, TriangleHeight ) );
00082     QPair<QSizeF, QSizeF> margins = grid()->requiredMargins();
00083     d->diagramRect = areaGeometry();
00084     diagramNativeRectangle.adjust
00085         (-margins.first.width(), -margins.first.height(),
00086          margins.second.width(), margins.second.height() );
00087 
00088     // the "outer" margin (distance between diagram contents and area,
00089     // determined by axis label overlap
00090     {
00091         QSizeF topleft( 0.0, 0.0 );
00092         QSizeF bottomRight( 0.0, 0.0 );
00093         Q_FOREACH( AbstractDiagram* abstractDiagram, diagrams() ) {
00094             AbstractTernaryDiagram* diagram =
00095                 qobject_cast<AbstractTernaryDiagram*>( abstractDiagram );
00096             Q_ASSERT( diagram );
00097             Q_FOREACH( TernaryAxis* axis, diagram->axes() ) {
00098                 QPair<QSizeF, QSizeF> margin = axis->requiredMargins();
00099                 topleft = topleft.expandedTo( margin.first );
00100                 bottomRight = bottomRight.expandedTo( margin.second );
00101             }
00102         }
00103         d->diagramRectContainer =
00104             d->diagramRect.adjusted( topleft.width(),
00105                                      topleft.height(),
00106                                      -bottomRight.width(),
00107                                      -bottomRight.height() );
00108     }
00109 
00110     // now calculate isometric projection, x and y widget coordinate
00111     // units, and location of (0.0, 0.0) in diagram coordinates
00112     QPointF zeroZeroPoint = d->diagramRectContainer.bottomLeft();
00113     double w = d->diagramRectContainer.width();
00114     double h = d->diagramRectContainer.height();
00115     double usableWidth;
00116     double usableHeight;
00117 
00118     if ( TriangleHeight * w > h ) {
00119         // shorten width:
00120         usableWidth = h / diagramNativeRectangle.height();
00121         usableHeight = h;
00122         zeroZeroPoint.setX( zeroZeroPoint.x() + ( w - usableWidth ) / 2 );
00123     } else {
00124         // reduce height:
00125         usableWidth = w;
00126         usableHeight = diagramNativeRectangle.height() * w;
00127         zeroZeroPoint.setY( zeroZeroPoint.y() - ( h - usableHeight ) / 2 );
00128     }
00129     // the rectangle has 1 as it's width, and TriangleHeight as it's
00130     // height - so this is how we translate that to widget coordinates:
00131     d->xUnit = usableWidth / diagramNativeRectangle.width(); // only because we normalize the values to [0..1]
00132     d->yUnit = -usableHeight / diagramNativeRectangle.height();
00133 
00134     // now move zeroZeroPoint so that it does not include the tick marks
00135     {
00136         double descent = diagramNativeRectangle.height() - TriangleHeight;
00137         double rightShift = -diagramNativeRectangle.x();
00138         zeroZeroPoint += QPointF( rightShift * d->xUnit, descent * d->yUnit );
00139     }
00140 
00141     d->diagramRect.setBottomLeft( zeroZeroPoint );
00142     d->diagramRect.setTopRight( QPointF( usableWidth, -usableHeight ) + zeroZeroPoint );
00143 }
00144 
00145 const QPointF TernaryCoordinatePlane::translate( const QPointF& point ) const
00146 {
00147     return QPointF( d->diagramRect.bottomLeft().x() + point.x() * d->xUnit,
00148                     d->diagramRect.bottomLeft().y() + point.y() * d->yUnit );
00149 }
00150 
00151 QSize TernaryCoordinatePlane::minimumSizeHint() const
00152 {
00153     // FIXME temp
00154     return QSize();
00155 }
00156 
00157 QSizePolicy TernaryCoordinatePlane::sizePolicy() const
00158 {
00159     return QSizePolicy( QSizePolicy::MinimumExpanding,
00160                         QSizePolicy::MinimumExpanding );
00161 }
00162 
00163 void TernaryCoordinatePlane::paint( QPainter* painter )
00164 {
00165     PainterSaver s( painter );
00166     // FIXME: this is not a good location for that:
00167     painter->setRenderHint(QPainter::Antialiasing, true );
00168 
00169 //     painter->setPen( QColor( "gold" ) );
00170 //     painter->setBrush( QColor( "gold" ) );
00171 //     painter->drawRect( d->diagramRectContainer );
00172 
00173     AbstractDiagramList diags = diagrams();
00174     if ( !diags.isEmpty() )
00175     {
00176         PaintContext ctx;
00177         ctx.setPainter ( painter );
00178         ctx.setCoordinatePlane ( this );
00179         const QRectF drawArea( areaGeometry() );
00180         ctx.setRectangle ( drawArea );
00181 
00182         // enabling clipping so that we're not drawing outside
00183 //         QRect clipRect = drawArea.toRect().adjusted( -1, -1, 1, 1 );
00184 //         QRegion clipRegion( clipRect );
00185 //         painter->setClipRegion( clipRegion );
00186 
00187         // paint the coordinate system rulers:
00188         Q_ASSERT( d->grid != 0 );
00189         d->grid->drawGrid( &ctx );
00190 
00191         // paint the diagrams:
00192         for ( int i = 0; i < diags.size(); i++ )
00193         {
00194             PainterSaver diagramPainterSaver( painter );
00195             diags[i]->paint ( &ctx );
00196         }
00197     }
00198 }
00199 
00200 DataDimensionsList TernaryCoordinatePlane::getDataDimensionsList() const
00201 {   // not needed
00202     return DataDimensionsList();
00203 }
00204 
00205 TernaryGrid* TernaryCoordinatePlane::grid() const
00206 {
00207     TernaryGrid* ternaryGrid = static_cast<TernaryGrid*>( d->grid );
00208     Q_ASSERT( dynamic_cast<TernaryGrid*>( d->grid ) );
00209     return ternaryGrid;
00210 }
00211 
00212 #undef d

Generated on Thu Mar 4 23:19:12 2010 for KD Chart 2 by  doxygen 1.5.4