00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "KDChartPolarCoordinatePlane.h"
00027 #include "KDChartPolarCoordinatePlane_p.h"
00028
00029 #include "KDChartPainterSaver_p.h"
00030 #include "KDChartChart.h"
00031 #include "KDChartPaintContext.h"
00032 #include "KDChartAbstractDiagram.h"
00033 #include "KDChartAbstractPolarDiagram.h"
00034 #include "KDChartPolarDiagram.h"
00035
00036 #include <math.h>
00037
00038 #include <QFont>
00039 #include <QList>
00040 #include <QtDebug>
00041 #include <QPainter>
00042 #include <QTimer>
00043
00044 #include <KDABLibFakes>
00045
00046 using namespace KDChart;
00047
00048 #define d d_func()
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118 PolarCoordinatePlane::PolarCoordinatePlane ( Chart* parent )
00119 : AbstractCoordinatePlane ( new Private(), parent )
00120 {
00121
00122 }
00123
00124 PolarCoordinatePlane::~PolarCoordinatePlane()
00125 {
00126
00127 }
00128
00129 void PolarCoordinatePlane::init()
00130 {
00131
00132 }
00133
00134 void PolarCoordinatePlane::addDiagram ( AbstractDiagram* diagram )
00135 {
00136 Q_ASSERT_X ( dynamic_cast<AbstractPolarDiagram*> ( diagram ),
00137 "PolarCoordinatePlane::addDiagram", "Only polar"
00138 "diagrams can be added to a polar coordinate plane!" );
00139 AbstractCoordinatePlane::addDiagram ( diagram );
00140 connect ( diagram, SIGNAL ( layoutChanged ( AbstractDiagram* ) ),
00141 SLOT ( slotLayoutChanged ( AbstractDiagram* ) ) );
00142
00143 }
00144
00145 void PolarCoordinatePlane::paint ( QPainter* painter )
00146 {
00147 AbstractDiagramList diags = diagrams();
00148 if ( d->coordinateTransformations.size() == diags.size() )
00149 {
00150 PaintContext ctx;
00151 ctx.setPainter ( painter );
00152 ctx.setCoordinatePlane ( this );
00153 ctx.setRectangle ( geometry() );
00154
00155
00156 const qreal oldZoomX = zoomFactorX();
00157 const qreal oldZoomY = zoomFactorY();
00158 d->newZoomX = oldZoomX;
00159 d->newZoomY = oldZoomY;
00160 for ( int i = 0; i < diags.size(); i++ )
00161 {
00162 d->currentTransformation = & ( d->coordinateTransformations[i] );
00163 qreal zoomX;
00164 qreal zoomY;
00165 PolarDiagram* polarDia = dynamic_cast<PolarDiagram*> ( diags[i] );
00166 if( polarDia ){
00167 polarDia->paint ( &ctx, true, zoomX, zoomY );
00168 d->newZoomX = qMin(d->newZoomX, zoomX);
00169 d->newZoomY = qMin(d->newZoomY, zoomY);
00170 }
00171 }
00172 d->currentTransformation = 0;
00173
00174
00175 if( d->newZoomX != oldZoomX || d->newZoomY != oldZoomY ){
00176
00177 QTimer::singleShot(10, this, SLOT(adjustZoomAndRepaint()));
00178 return;
00179 }
00180
00181
00182
00183
00184 d->currentTransformation = & ( d->coordinateTransformations.first() );
00185
00186 d->grid->drawGrid( &ctx );
00187
00188
00189 for ( int i = 0; i < diags.size(); i++ )
00190 {
00191 d->currentTransformation = & ( d->coordinateTransformations[i] );
00192 PainterSaver painterSaver( painter );
00193 PolarDiagram* polarDia = dynamic_cast<PolarDiagram*> ( diags[i] );
00194 if( polarDia ){
00195 qreal dummy1, dummy2;
00196 polarDia->paint ( &ctx, false, dummy1, dummy2 );
00197 }else{
00198 diags[i]->paint ( &ctx );
00199 }
00200 }
00201 d->currentTransformation = 0;
00202 }
00203 }
00204
00205
00206 void PolarCoordinatePlane::adjustZoomAndRepaint()
00207 {
00208 const qreal newZoom = qMin(d->newZoomX, d->newZoomY);
00209 setZoomFactors(newZoom, newZoom);
00210 update();
00211 }
00212
00213
00214 void PolarCoordinatePlane::resizeEvent ( QResizeEvent* )
00215 {
00216 d->initialResizeEventReceived = true;
00217 layoutDiagrams();
00218 }
00219
00220 void PolarCoordinatePlane::layoutDiagrams()
00221 {
00222
00223
00224
00225
00226
00227
00228 const QRect rect( areaGeometry() );
00229 d->contentRect = QRectF ( 1, 1, rect.width() - 3, rect.height() - 3 );
00230
00231 const ZoomParameters zoom = d->coordinateTransformations.isEmpty() ? ZoomParameters()
00232 : d->coordinateTransformations.front().zoom;
00233
00234 const qreal oldStartPosition = startPosition();
00235 d->coordinateTransformations.clear();
00236 Q_FOREACH( AbstractDiagram* diagram, diagrams() )
00237 {
00238 AbstractPolarDiagram *polarDiagram = dynamic_cast<AbstractPolarDiagram*>( diagram );
00239 Q_ASSERT( polarDiagram );
00240 QPair<QPointF, QPointF> dataBoundariesPair = polarDiagram->dataBoundaries();
00241
00242 const double angleUnit = 360 / polarDiagram->valueTotals();
00243
00244 const double radius = qAbs( dataBoundariesPair.first.y() ) + dataBoundariesPair.second.y();
00245
00246 const double diagramWidth = radius * 2;
00247 const double planeWidth = d->contentRect.width();
00248 const double planeHeight = d->contentRect.height();
00249 const double radiusUnit = qMin( planeWidth, planeHeight ) / diagramWidth;
00250
00251 QPointF coordinateOrigin = QPointF ( planeWidth / 2, planeHeight / 2 );
00252 coordinateOrigin += d->contentRect.topLeft();
00253
00254 CoordinateTransformation diagramTransposition;
00255 diagramTransposition.originTranslation = coordinateOrigin;
00256 diagramTransposition.radiusUnit = radiusUnit;
00257 diagramTransposition.angleUnit = angleUnit;
00258 diagramTransposition.startPosition = oldStartPosition;
00259 diagramTransposition.zoom = zoom;
00260 diagramTransposition.minValue = dataBoundariesPair.first.y() < 0 ? dataBoundariesPair.first.y() : 0.0;
00261 d->coordinateTransformations.append( diagramTransposition );
00262 }
00263 }
00264
00265 const QPointF PolarCoordinatePlane::translate( const QPointF& diagramPoint ) const
00266 {
00267 Q_ASSERT_X ( d->currentTransformation != 0, "PolarCoordinatePlane::translate",
00268 "Only call translate() from within paint()." );
00269 return d->currentTransformation->translate ( diagramPoint );
00270 }
00271
00272 const QPointF PolarCoordinatePlane::translatePolar( const QPointF& diagramPoint ) const
00273 {
00274 Q_ASSERT_X ( d->currentTransformation != 0, "PolarCoordinatePlane::translate",
00275 "Only call translate() from within paint()." );
00276 return d->currentTransformation->translatePolar ( diagramPoint );
00277 }
00278
00279 qreal PolarCoordinatePlane::angleUnit() const
00280 {
00281 Q_ASSERT_X ( d->currentTransformation != 0, "PolarCoordinatePlane::angleUnit",
00282 "Only call angleUnit() from within paint()." );
00283 return d->currentTransformation->angleUnit;
00284 }
00285
00286 qreal PolarCoordinatePlane::radiusUnit() const
00287 {
00288 Q_ASSERT_X ( d->currentTransformation != 0, "PolarCoordinatePlane::radiusUnit",
00289 "Only call radiusUnit() from within paint()." );
00290 return d->currentTransformation->radiusUnit;
00291 }
00292
00293 void PolarCoordinatePlane::slotLayoutChanged ( AbstractDiagram* )
00294 {
00295 if ( d->initialResizeEventReceived ) layoutDiagrams();
00296 }
00297
00298 void PolarCoordinatePlane::setStartPosition( qreal degrees )
00299 {
00300 Q_ASSERT_X ( diagram(), "PolarCoordinatePlane::setStartPosition",
00301 "setStartPosition() needs a diagram to be associated to the plane." );
00302 for( CoordinateTransformationList::iterator it = d->coordinateTransformations.begin();
00303 it != d->coordinateTransformations.end();
00304 ++it )
00305 {
00306 CoordinateTransformation& trans = *it;
00307 trans.startPosition = degrees;
00308 }
00309 }
00310
00311 qreal PolarCoordinatePlane::startPosition() const
00312 {
00313 return d->coordinateTransformations.isEmpty()
00314 ? 0.0
00315 : d->coordinateTransformations.first().startPosition;
00316 }
00317
00318 double PolarCoordinatePlane::zoomFactorX() const
00319 {
00320 return d->coordinateTransformations.isEmpty()
00321 ? 1.0
00322 : d->coordinateTransformations.first().zoom.xFactor;
00323 }
00324
00325 double PolarCoordinatePlane::zoomFactorY() const
00326 {
00327 return d->coordinateTransformations.isEmpty()
00328 ? 1.0
00329 : d->coordinateTransformations.first().zoom.yFactor;
00330 }
00331
00332 void PolarCoordinatePlane::setZoomFactors( double factorX, double factorY )
00333 {
00334 setZoomFactorX( factorX );
00335 setZoomFactorY( factorY );
00336 }
00337
00338 void PolarCoordinatePlane::setZoomFactorX( double factor )
00339 {
00340 for( CoordinateTransformationList::iterator it = d->coordinateTransformations.begin();
00341 it != d->coordinateTransformations.end();
00342 ++it )
00343 {
00344 CoordinateTransformation& trans = *it;
00345 trans.zoom.xFactor = factor;
00346 }
00347 }
00348
00349 void PolarCoordinatePlane::setZoomFactorY( double factor )
00350 {
00351 for( CoordinateTransformationList::iterator it = d->coordinateTransformations.begin();
00352 it != d->coordinateTransformations.end();
00353 ++it )
00354 {
00355 CoordinateTransformation& trans = *it;
00356 trans.zoom.yFactor = factor;
00357 }
00358 }
00359
00360 QPointF PolarCoordinatePlane::zoomCenter() const
00361 {
00362 return d->coordinateTransformations.isEmpty()
00363 ? QPointF( 0.5, 0.5 )
00364 : QPointF( d->coordinateTransformations.first().zoom.xCenter, d->coordinateTransformations.first().zoom.yCenter );
00365 }
00366
00367 void PolarCoordinatePlane::setZoomCenter( const QPointF& center )
00368 {
00369 for( CoordinateTransformationList::iterator it = d->coordinateTransformations.begin();
00370 it != d->coordinateTransformations.end();
00371 ++it )
00372 {
00373 CoordinateTransformation& trans = *it;
00374 trans.zoom.xCenter = center.x();
00375 trans.zoom.yCenter = center.y();
00376 }
00377 }
00378
00379 DataDimensionsList PolarCoordinatePlane::getDataDimensionsList() const
00380 {
00381 DataDimensionsList l;
00382
00383
00384
00385 return l;
00386 }
00387
00388 void KDChart::PolarCoordinatePlane::setGridAttributes(
00389 bool circular,
00390 const GridAttributes& a )
00391 {
00392 if( circular )
00393 d->gridAttributesCircular = a;
00394 else
00395 d->gridAttributesSagittal = a;
00396 setHasOwnGridAttributes( circular, true );
00397 update();
00398 emit propertiesChanged();
00399 }
00400
00401 void KDChart::PolarCoordinatePlane::resetGridAttributes(
00402 bool circular )
00403 {
00404 setHasOwnGridAttributes( circular, false );
00405 update();
00406 }
00407
00408 const GridAttributes KDChart::PolarCoordinatePlane::gridAttributes(
00409 bool circular ) const
00410 {
00411 if( hasOwnGridAttributes( circular ) ){
00412 if( circular )
00413 return d->gridAttributesCircular;
00414 else
00415 return d->gridAttributesSagittal;
00416 }else{
00417 return globalGridAttributes();
00418 }
00419 }
00420
00421 void KDChart::PolarCoordinatePlane::setHasOwnGridAttributes(
00422 bool circular, bool on )
00423 {
00424 if( circular )
00425 d->hasOwnGridAttributesCircular = on;
00426 else
00427 d->hasOwnGridAttributesSagittal = on;
00428 emit propertiesChanged();
00429 }
00430
00431 bool KDChart::PolarCoordinatePlane::hasOwnGridAttributes(
00432 bool circular ) const
00433 {
00434 return
00435 ( circular )
00436 ? d->hasOwnGridAttributesCircular
00437 : d->hasOwnGridAttributesSagittal;
00438 }