KD Chart 2 [rev.2.4]
|
00001 /**************************************************************************** 00002 ** Copyright (C) 2001-2012 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.txt 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