kchart

KDChartPolarPainter.cpp

00001 /* -*- Mode: C++ -*-
00002    KDChart - a multi-platform charting engine
00003    */
00004 
00005 /****************************************************************************
00006  ** Copyright (C) 2001-2003 Klarälvdalens Datakonsult AB.  All rights reserved.
00007  **
00008  ** This file is part of the KDChart 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 KDChart licenses may use this file in
00016  ** accordance with the KDChart 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.klaralvdalens-datakonsult.se/?page=products for
00023  **   information about KDChart Commercial License Agreements.
00024  **
00025  ** Contact info@klaralvdalens-datakonsult.se if any conditions of this
00026  ** licensing are not clear to you.
00027  **
00028  **********************************************************************/
00029 #include "KDChartPolarPainter.h"
00030 #include <KDChartParams.h>
00031 #include <KDChartAxisParams.h>
00032 #include "KDChartAxesPainter.h"
00033 #include "KDDrawText.h"
00034 
00035 #include <qpainter.h>
00036 
00049 KDChartPolarPainter::KDChartPolarPainter( KDChartParams* params ) :
00050     KDChartPainter( params )
00051 {
00052     // This constructor intentionally left blank so far; we cannot setup the
00053     // geometry yet since we do not know the size of the painter.
00054 }
00055 
00056 
00060 KDChartPolarPainter::~KDChartPolarPainter()
00061 {
00062     // intentionally left blank
00063 }
00064 
00065 
00077 void KDChartPolarPainter::paintData( QPainter* painter,
00078                                      KDChartTableDataBase* data,
00079                                      bool paint2nd,
00080                                      KDChartDataRegionList* regions )
00081 {
00082     uint chart = paint2nd ? 1 : 0;
00083 
00084     QRect ourClipRect( _dataRect );
00085     ourClipRect.setBottom( ourClipRect.bottom() - 1 ); // protect axes
00086     ourClipRect.setLeft( ourClipRect.left() + 1 );
00087     ourClipRect.setRight( ourClipRect.right() - 1 );
00088     //
00089     // PENDING(khz) adjust the clip rect if neccessary...
00090     //
00091 
00092     const QWMatrix & world = painter->worldMatrix();
00093     ourClipRect =
00094 #if COMPAT_QT_VERSION >= 0x030000
00095         world.mapRect( ourClipRect );
00096 #else
00097     world.map( ourClipRect );
00098 #endif
00099 
00100     painter->setClipRect( ourClipRect );
00101 
00102 
00103     uint datasetStart, datasetEnd;
00104     findChartDatasets( data, paint2nd, chart, datasetStart, datasetEnd );
00105 
00106 
00107     painter->translate( _dataRect.x(), _dataRect.y() );
00108 
00109 
00110     // Number of values: If -1, use all values, otherwise use the
00111     // specified number of values.
00112     int numValues = 0;
00113     if ( params()->numValues() != -1 )
00114         numValues = params()->numValues();
00115     else
00116         numValues = data->usedCols();
00117 
00118     // compute position
00119     int size = QMIN( _dataRect.width(), _dataRect.height() ); // initial size
00120 
00121     const double minSizeP1000 = size / 1000.0;
00122 
00123     int x = ( _dataRect.width() == size ) ? 0 : ( ( _dataRect.width() - size ) / 2 );
00124     int y = ( _dataRect.height() == size ) ? 0 : ( ( _dataRect.height() - size ) / 2 );
00125     QRect position( x, y, size, size );
00126 
00127     QPoint center( position.width() / 2 + position.x(),
00128                    position.height() / 2 + position.y() );
00129 
00130 
00131     double maxValue;
00132     switch ( params()->polarChartSubType() ) {
00133         case KDChartParams::PolarNormal:
00134             maxValue = data->maxValue();
00135             break;
00136         case KDChartParams::PolarPercent:
00137             maxValue = 100.0;
00138             break;
00139         default:
00140             maxValue = QMAX( data->maxColSum(), 0.0 );
00141     }
00142 
00143     double pixelsPerUnit = 0.0;
00144     // the / 2 in the next line is there because we need the space in
00145     // both directions
00146     pixelsPerUnit = (position.height() / maxValue / 2) * 1000 / 1250;
00147 
00148     QMap < int, double > currentValueSums;
00149     if (    params()->polarChartSubType() == KDChartParams::PolarStacked
00150             || params()->polarChartSubType() == KDChartParams::PolarPercent )
00151         // this array is only used for stacked and percent polar
00152         // charts, no need to waste time initializing it for normal
00153         // ones
00154         for ( int value = 0; value < numValues; value++ )
00155             currentValueSums[ value ] = 0.0;
00156     QMap < int, double > totalValueSums;
00157 
00158 
00159     /*
00160        axes schema: use AxisPosSagittal for sagittal 'axis' lines
00161        use AxisPosCircular for circular 'axis'
00162        */
00163     const KDChartAxisParams & paraSagittal = params()->axisParams( KDChartAxisParams::AxisPosSagittal );
00164     const KDChartAxisParams & paraCircular = params()->axisParams( KDChartAxisParams::AxisPosCircular );
00165 
00166     int sagittalLineWidth = 0 <= paraSagittal.axisLineWidth()
00167         ? paraSagittal.axisLineWidth()
00168         : -1 * static_cast < int > (   paraSagittal.axisLineWidth()
00169                 * minSizeP1000 );
00170     ( ( KDChartAxisParams& ) paraSagittal ).setAxisTrueLineWidth( sagittalLineWidth );
00171     int sagittalGridLineWidth
00172         = (    KDCHART_AXIS_GRID_AUTO_LINEWIDTH
00173                 == paraSagittal.axisGridLineWidth() )
00174         ? sagittalLineWidth
00175         : (   ( 0 <= paraSagittal.axisGridLineWidth() )
00176                 ? paraSagittal.axisGridLineWidth()
00177                 : -1 * static_cast < int > (   paraSagittal.axisGridLineWidth()
00178                     * minSizeP1000 ) );
00179 
00180     int circularLineWidth = 0 <= paraCircular.axisLineWidth()
00181         ? paraCircular.axisLineWidth()
00182         : -1 * static_cast < int > (   paraCircular.axisLineWidth()
00183                 * minSizeP1000 );
00184     ( ( KDChartAxisParams& ) paraCircular ).setAxisTrueLineWidth( circularLineWidth );
00185     int circularGridLineWidth
00186         = (    KDCHART_AXIS_GRID_AUTO_LINEWIDTH
00187                 == paraCircular.axisGridLineWidth() )
00188         ? circularLineWidth
00189         : (   ( 0 <= paraCircular.axisGridLineWidth() )
00190                 ? paraCircular.axisGridLineWidth()
00191                 : -1 * static_cast < int > (   paraCircular.axisGridLineWidth()
00192                     * minSizeP1000 ) );
00193 
00194     QFont actFont;
00195     int labels = 0;
00196     double currentRadiusPPU = position.height() / 2.0;
00197 
00198     // draw the "axis" circles
00199     if( paraCircular.axisShowGrid()
00200             || paraCircular.axisVisible()
00201             || paraCircular.axisLabelsVisible() ) {
00202 
00203         double radiusPPU = maxValue * pixelsPerUnit;
00204         double pDelimDelta = 0.0;
00205 
00206         // calculate label texts
00207         QStringList* labelTexts = 0;
00208         ((KDChartParams*)params())->setAxisArea( KDChartAxisParams::AxisPosCircular,
00209                                                  QRect( 0,
00210                                                      0,
00211                                                      static_cast<int>( radiusPPU ),
00212                                                      static_cast<int>( radiusPPU ) ) );
00213 
00214         double delimLen = 20.0 * minSizeP1000; // per mille of area
00215         KDChartAxisParams::AxisPos basicPos;
00216         QPoint orig, dest;
00217         double dDummy;
00218         double nSubDelimFactor = 0.0;
00219         double nTxtHeight = 0.0;
00220         double pTextsX = 0.0;
00221         double pTextsY = 0.0;
00222         double pTextsW = 0.0;
00223         double pTextsH = 0.0;
00224         int textAlign = Qt::AlignHCenter | Qt::AlignVCenter;
00225         bool isLogarithmic = false;
00226         bool isDateTime = false;
00227         bool autoDtLabels = false;
00228         QDateTime dtLow;
00229         QDateTime dtHigh;
00230         KDChartAxisParams::ValueScale dtDeltaScale;
00231         KDChartAxesPainter::calculateLabelTexts(
00232                 painter,
00233                 *data,
00234                 *params(),
00235                 KDChartAxisParams::AxisPosCircular,
00236                 minSizeP1000,
00237                 delimLen,
00238                 // start of reference parameters
00239                 basicPos,
00240                 orig,
00241                 dest,
00242                 dDummy,dDummy,dDummy,dDummy,
00243                 nSubDelimFactor,
00244                 pDelimDelta,
00245                 nTxtHeight,
00246                 pTextsX,
00247                 pTextsY,
00248                 pTextsW,
00249                 pTextsH,
00250                 textAlign,
00251                 isLogarithmic,
00252                 isDateTime,
00253                 autoDtLabels,
00254                 dtLow,
00255                 dtHigh,
00256                 dtDeltaScale );
00257                 labelTexts = ( QStringList* ) paraCircular.axisLabelTexts();
00258         if( paraCircular.axisLabelsVisible() ) {
00259 //qDebug("\nnTxtHeight: "+QString::number(nTxtHeight));
00260             // calculate font size
00261             actFont = paraCircular.axisLabelsFont();
00262             if ( paraCircular.axisLabelsFontUseRelSize() ) {
00263 //qDebug("paraCircular.axisLabelsFontUseRelSize() is TRUE");
00264                 actFont.setPointSizeFloat( nTxtHeight );
00265             }
00266             QFontMetrics fm( actFont );
00267             QString strMax;
00268             int maxLabelsWidth = 0;
00269             for ( QStringList::Iterator it = labelTexts->begin();
00270                     it != labelTexts->end();
00271                     ++it ) {
00272                 if ( fm.width( *it ) > maxLabelsWidth ) {
00273                     maxLabelsWidth = fm.width( *it );
00274                     strMax = *it;
00275                 }
00276             }
00277             while ( fm.width( strMax ) > pTextsW
00278                     && 6.0 < nTxtHeight ) {
00279                 nTxtHeight -= 0.5;
00280                 actFont.setPointSizeFloat( nTxtHeight );
00281                 fm = QFontMetrics( actFont );
00282             }
00283             painter->setFont( actFont );
00284         }
00285 
00286         double radiusDelta = pDelimDelta;
00287 
00288         labels = labelTexts
00289             ? labelTexts->count()
00290             : 0;
00291         if( labels )
00292             currentRadiusPPU = -radiusDelta;
00293         for( int iLabel = 0; iLabel < labels; ++iLabel ) {
00294             //while( currentRadius < maxValue ) {
00295             //double currentRadiusPPU = currentRadius;
00296             currentRadiusPPU += radiusDelta;
00297             double currentRadiusPPU2 = currentRadiusPPU * 2;
00298             int circularAxisAngle = ( currentRadiusPPU != 0.0 ) ? ( static_cast < int > (4.0 * radiusPPU / currentRadiusPPU) ) : 0;
00299             if( paraCircular.axisShowGrid() ) {
00300                 painter->setPen( QPen( paraCircular.axisGridColor(),
00301                             circularGridLineWidth ) );
00302                 painter->drawEllipse( static_cast<int>( center.x() - currentRadiusPPU ),
00303                         static_cast<int>( center.y() - currentRadiusPPU ),
00304                         static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ) );
00305             }
00306             if( paraCircular.axisVisible() ) {
00307                 painter->setPen( QPen( paraCircular.axisLineColor(),
00308                             circularLineWidth ) );
00309                 if( params()->polarDelimAtPos( KDChartEnums::PosTopCenter ) )
00310                     painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
00311                             static_cast<int>( center.y() - currentRadiusPPU ),
00312                             static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
00313                             (90 - circularAxisAngle/2) * 16,
00314                             circularAxisAngle * 16 );
00315                 if( params()->polarDelimAtPos( KDChartEnums::PosBottomCenter ) )
00316                     painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
00317                             static_cast<int>( center.y() - currentRadiusPPU ),
00318                             static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
00319                             (270 - circularAxisAngle/2) * 16,
00320                             circularAxisAngle * 16 );
00321 
00322                 if( params()->polarDelimAtPos( KDChartEnums::PosCenterRight ) )
00323                     painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
00324                             static_cast<int>( center.y() - currentRadiusPPU ),
00325                             static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
00326                             (0 - circularAxisAngle/2) * 16,
00327                             circularAxisAngle * 16 );
00328                 if( params()->polarDelimAtPos( KDChartEnums::PosCenterLeft ) )
00329                     painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
00330                             static_cast<int>( center.y() - currentRadiusPPU ),
00331                             static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
00332                             (180 - circularAxisAngle/2) * 16,
00333                             circularAxisAngle * 16 );
00334 
00335                 if( params()->polarDelimAtPos( KDChartEnums::PosTopRight ) )
00336                     painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
00337                             static_cast<int>( center.y() - currentRadiusPPU ),
00338                             static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
00339                             (45 - circularAxisAngle/2) * 16,
00340                             circularAxisAngle * 16 );
00341                 if( params()->polarDelimAtPos( KDChartEnums::PosBottomLeft ) )
00342                     painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
00343                             static_cast<int>( center.y() - currentRadiusPPU ),
00344                             static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
00345                             (225 - circularAxisAngle/2) * 16,
00346                             circularAxisAngle * 16 );
00347 
00348                 if( params()->polarDelimAtPos( KDChartEnums::PosBottomRight ) )
00349                     painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
00350                             static_cast<int>( center.y() - currentRadiusPPU ),
00351                             static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
00352                             (315 - circularAxisAngle/2) * 16,
00353                             circularAxisAngle * 16 );
00354                 if( params()->polarDelimAtPos( KDChartEnums::PosTopLeft ) )
00355                     painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
00356                             static_cast<int>( center.y() - currentRadiusPPU ),
00357                             static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
00358                             (135 - circularAxisAngle/2) * 16,
00359                             circularAxisAngle * 16 );
00360             }
00361             if( paraCircular.axisLabelsVisible() ) {
00362                 const bool rotate = params()->polarRotateCircularLabels();
00363                 painter->setPen( QPen( paraCircular.axisLabelsColor(),
00364                                        circularLineWidth ) );
00365                 const QString& txt = (*labelTexts)[ iLabel ];
00366                 if( params()->polarLabelsAtPos( KDChartEnums::PosTopCenter ) )
00367                     paintCircularAxisLabel( painter, rotate, 90, center, currentRadiusPPU, txt,
00368                             Qt::AlignBottom | Qt::AlignHCenter, iLabel );
00369 
00370                 if( params()->polarLabelsAtPos( KDChartEnums::PosBottomCenter ) )
00371                     paintCircularAxisLabel( painter, rotate, 270, center, currentRadiusPPU, txt,
00372                             Qt::AlignTop | Qt::AlignHCenter, iLabel );
00373 
00374                 if( params()->polarLabelsAtPos( KDChartEnums::PosCenterRight ) )
00375                     paintCircularAxisLabel( painter, rotate,   0, center, currentRadiusPPU, txt,
00376                             Qt::AlignVCenter | Qt::AlignRight, iLabel );
00377 
00378                 if( params()->polarLabelsAtPos( KDChartEnums::PosCenterLeft ) )
00379                     paintCircularAxisLabel( painter, rotate, 180, center, currentRadiusPPU, txt,
00380                             Qt::AlignVCenter | Qt::AlignLeft, iLabel );
00381 
00382                 if( params()->polarLabelsAtPos( KDChartEnums::PosTopRight ) )
00383                     paintCircularAxisLabel( painter, rotate,  45, center, currentRadiusPPU, txt,
00384                             Qt::AlignBottom | Qt::AlignRight, iLabel );
00385 
00386                 if( params()->polarLabelsAtPos( KDChartEnums::PosBottomLeft ) )
00387                     paintCircularAxisLabel( painter, rotate, 225, center, currentRadiusPPU, txt,
00388                             Qt::AlignTop | Qt::AlignLeft, iLabel );
00389 
00390                 if( params()->polarLabelsAtPos( KDChartEnums::PosBottomRight ) )
00391                     paintCircularAxisLabel( painter, rotate, 315, center, currentRadiusPPU, txt,
00392                             Qt::AlignTop | Qt::AlignRight, iLabel );
00393 
00394                 if( params()->polarLabelsAtPos( KDChartEnums::PosTopLeft ) )
00395                     paintCircularAxisLabel( painter, rotate, 135, center, currentRadiusPPU, txt,
00396                             Qt::AlignBottom | Qt::AlignLeft, iLabel );
00397             }
00398         }
00399     }
00400 
00401 
00402     double circularSpan = params()->polarChartSubType() == KDChartParams::PolarPercent
00403         ? 100.0
00404         : paraCircular.trueAxisHigh() - paraCircular.trueAxisLow();
00405     double radius = currentRadiusPPU;
00406     if(    !labels
00407             || params()->polarChartSubType() == KDChartParams::PolarPercent )
00408         radius = (position.width() / 2.0) * 1000.0 / 1250.0;
00409 
00410     if( params()->polarChartSubType() != KDChartParams::PolarPercent )
00411         pixelsPerUnit = labels ? currentRadiusPPU / circularSpan
00412             : (position.height() / maxValue / 2.0) * 1000.0 / 1250.0;
00413     else
00414         pixelsPerUnit = (position.height() / 100.0 / 2.0) * 1000.0 / 1250.0;
00415 
00416     // draw the sagittal grid and axis lines
00417     if(    paraSagittal.axisShowGrid()
00418             || paraSagittal.axisVisible()
00419             || paraSagittal.axisLabelsVisible() ) {
00420 
00421         // calculate label texts
00422         QStringList* labelTexts = 0;
00423         bool onlyDefaultLabels = true;
00424         if( paraSagittal.axisLabelsVisible() ) {
00425             ((KDChartParams*)params())->setAxisArea( KDChartAxisParams::AxisPosSagittal,
00426                                                     QRect( 0,
00427                                                         0,
00428                                                         static_cast < int > ( 2.0 * M_PI * radius ),
00429                                                         static_cast < int > ( 0.5 * radius ) ) );
00430             double delimLen = 20.0 * minSizeP1000; // per mille of area
00431             KDChartAxisParams::AxisPos basicPos;
00432             QPoint orig, dest;
00433             double dDummy;
00434             double nSubDelimFactor = 0.0;
00435             double pDelimDelta = 0.0;
00436             double nTxtHeight = 0.0;
00437             double pTextsX = 0.0;
00438             double pTextsY = 0.0;
00439             double pTextsW = 0.0;
00440             double pTextsH = 0.0;
00441             int textAlign = Qt::AlignCenter;
00442             bool isLogarithmic = false;
00443             bool isDateTime = false;
00444             bool autoDtLabels = false;
00445             QDateTime dtLow;
00446             QDateTime dtHigh;
00447             KDChartAxisParams::ValueScale dtDeltaScale;
00448             KDChartAxesPainter::calculateLabelTexts(
00449                     painter,
00450                     *data,
00451                     *params(),
00452                     KDChartAxisParams::AxisPosSagittal,
00453                     minSizeP1000,
00454                     delimLen,
00455                     // start of reference parameters
00456                     basicPos,
00457                     orig,
00458                     dest,
00459                     dDummy,dDummy,dDummy,dDummy,
00460                     nSubDelimFactor,
00461                     pDelimDelta,
00462                     nTxtHeight,
00463                     pTextsX,
00464                     pTextsY,
00465                     pTextsW,
00466                     pTextsH,
00467                     textAlign,
00468                     isLogarithmic,
00469                     isDateTime,
00470                     autoDtLabels,
00471                     dtLow,
00472                     dtHigh,
00473                     dtDeltaScale );
00474                     labelTexts = ( QStringList* ) paraSagittal.axisLabelTexts();
00475                     // calculate font size
00476                     actFont = paraSagittal.axisLabelsFont();
00477                     if ( paraSagittal.axisLabelsFontUseRelSize() ) {
00478                         actFont.setPointSizeFloat( nTxtHeight );
00479                     }
00480                     QFontMetrics fm( actFont );
00481                     QString strMax;
00482                     int maxLabelsWidth = 0;
00483                     for ( QStringList::Iterator it = labelTexts->begin();
00484                             it != labelTexts->end();
00485                             ++it ) {
00486                         if ( fm.width( *it ) > maxLabelsWidth ) {
00487                             maxLabelsWidth = fm.width( *it );
00488                             strMax = *it;
00489                         }
00490                         if ( !(*it).startsWith( "Item ") )
00491                             onlyDefaultLabels = false;
00492                     }
00493                     while ( fm.width( strMax ) > pTextsW && 6.0 < nTxtHeight ) {
00494                         nTxtHeight -= 0.5;
00495                         actFont.setPointSizeFloat( nTxtHeight );
00496                         fm = QFontMetrics( actFont );
00497                     }
00498                     painter->setFont( actFont );
00499         }
00500 
00501         int currentAngle = params()->polarZeroDegreePos();
00502         if(    -360 > currentAngle
00503                 ||  360 < currentAngle )
00504             currentAngle = 0;
00505         if( 0 > currentAngle )
00506             currentAngle += 360;
00507         int r1 = static_cast < int > ( radius * 1050 / 1000 );
00508         int r2 = static_cast < int > ( radius * 1100 / 1000 );
00509         int r3 = static_cast < int > ( radius * 1175 / 1000 );
00510         QPoint pt1, pt2, pt3;
00511         uint nLabels = labelTexts->count();
00512         int angleBetweenRays = 360 / nLabels;
00513         for( uint value = 0; value < nLabels; ++value ) {
00514             pt1 = center + polarToXY( r1, currentAngle );
00515             pt2 = center + polarToXY( r2, currentAngle );
00516             pt3 = center + polarToXY( r3, currentAngle );
00517 
00518             //pt3 = painter->worldMatrix().map( pt3 );
00519 
00520             if( paraSagittal.axisShowGrid() ) {
00521                 painter->setPen( QPen( paraSagittal.axisGridColor(),
00522                             sagittalGridLineWidth ) );
00523                 painter->drawLine( center, pt1 );
00524             }
00525             if( paraSagittal.axisVisible() ) {
00526                 painter->setPen( QPen( paraSagittal.axisLineColor(),
00527                             sagittalLineWidth ) );
00528                 painter->drawLine( pt1, pt2 );
00529             }
00530             if(    paraSagittal.axisLabelsVisible()
00531                     && labelTexts
00532                     && labelTexts->count() > value ) {
00533                 painter->setPen( QPen( paraSagittal.axisLabelsColor(),
00534                             sagittalLineWidth ) );
00535                 QString label(   onlyDefaultLabels
00536                         ? QString::number( currentAngle )
00537                         : (*labelTexts)[ value ] );
00538 
00539                 KDDrawText::drawRotatedText( painter,
00540                         currentAngle+90,
00541                         painter->worldMatrix().map(pt3),
00542                         label,
00543                         0,
00544                         Qt::AlignCenter );
00545             }
00546             currentAngle += angleBetweenRays;
00547         }
00548     }
00549 
00550 
00551     // Now draw the data
00552     int dataLinesWidth = 0 <= params()->polarLineWidth()
00553         ? params()->polarLineWidth()
00554         : -1 * static_cast < int > (   params()->polarLineWidth()
00555                 * minSizeP1000 );
00556     painter->setBrush( Qt::NoBrush );
00557     for ( unsigned int dataset = datasetStart; dataset <= datasetEnd; dataset++ ) {
00558         painter->setPen( QPen( params()->dataColor( dataset ),
00559                     dataLinesWidth ) );
00560         QPointArray points( numValues );
00561         int totalPoints = 0;
00562         double valueTotal = 0.0; // Will only be used for Percent
00563         int angleBetweenRays = 360 / numValues;
00564         QVariant vValY;
00565         for ( int value = 0; value < numValues; value++ ) {
00566             if( params()->polarChartSubType() == KDChartParams::PolarPercent )
00567                 valueTotal = data->colAbsSum( value );
00568             // the value determines the angle, the dataset only the color
00569             if( data->cellCoord( dataset, value, vValY, 1 ) &&
00570                 QVariant::Double == vValY.type() ){
00571                 const double cellValue = vValY.toDouble();
00572                 double drawValue;
00573                 if ( params()->polarChartSubType() == KDChartParams::PolarStacked )
00574                     drawValue = ( cellValue + currentValueSums[ value ] ) * pixelsPerUnit;
00575                 else if( params()->polarChartSubType() == KDChartParams::PolarPercent ) {
00576                     drawValue = (   ( cellValue + currentValueSums[ value ] )
00577                             / valueTotal * static_cast<double>( radius ) );
00578                 } else
00579                     drawValue = cellValue * pixelsPerUnit;
00580 
00581                 // record the point for drawing the polygon later
00582                 int drawAngle = value * angleBetweenRays;
00583                 QPoint drawPoint( center + polarToXY( static_cast<int>( drawValue ),
00584                                   drawAngle ) );
00585                 points.setPoint( totalPoints, drawPoint );
00586                 totalPoints++;
00587                 KDChartDataRegion* datReg = 0;
00588                 // the marker can be drawn now
00589                 if( params()->polarMarker() ) {
00590                     int xsize = params()->polarMarkerSize().width();
00591                     int ysize = params()->polarMarkerSize().height();
00592                     datReg = drawMarker( painter,
00593                                         params(),
00594                                         _areaWidthP1000, _areaHeightP1000,
00595                                         _dataRect.x(), _dataRect.y(),
00596                                         params()->polarMarkerStyle( dataset ),
00597                                         params()->dataColor( dataset ),
00598                                         drawPoint,
00599                                         dataset, value, chart,
00600                                         regions,
00601                                         xsize ? &xsize : 0,
00602                                         ysize ? &ysize : 0 );
00603                     painter->setPen( QPen( params()->dataColor( dataset ),
00604                                     dataLinesWidth ) );
00605                 }
00606                 if ( regions ) {
00607                     bool bMustAppendDatReg = 0 == datReg;
00608                     if( bMustAppendDatReg ){
00609                         QRect rect( QPoint( drawPoint.x() - 1,
00610                                             drawPoint.y() - 1 ),
00611                                     QSize( 3, 3 ) );
00612                         datReg = new KDChartDataRegion( dataset,
00613                                                         value,
00614                                                         chart,
00615                                                         rect );
00616                     }
00617                     datReg->points[ KDChartEnums::PosTopLeft ] =
00618                         drawPoint + _dataRect.topLeft();
00619 
00620                     datReg->points[     KDChartEnums::PosTopCenter ]    =
00621                         datReg->points[ KDChartEnums::PosTopLeft ];
00622                     datReg->points[     KDChartEnums::PosTopRight ]     =
00623                         datReg->points[ KDChartEnums::PosTopLeft ];
00624                     datReg->points[     KDChartEnums::PosBottomLeft ]   =
00625                         datReg->points[ KDChartEnums::PosTopLeft ];
00626                     datReg->points[     KDChartEnums::PosBottomCenter ] =
00627                         datReg->points[ KDChartEnums::PosTopLeft ];
00628                     datReg->points[     KDChartEnums::PosBottomRight ]  =
00629                         datReg->points[ KDChartEnums::PosTopLeft ];
00630                     datReg->points[     KDChartEnums::PosCenterLeft ]   =
00631                         datReg->points[ KDChartEnums::PosTopLeft ];
00632                     datReg->points[     KDChartEnums::PosCenter ]       =
00633                         datReg->points[ KDChartEnums::PosTopLeft ];
00634                     datReg->points[     KDChartEnums::PosCenterRight ]  =
00635                         datReg->points[ KDChartEnums::PosTopLeft ];
00636                     /*
00637                     // test the center positions:
00638                     painter->drawEllipse( datReg->points[ KDChartEnums::PosCenterLeft ].x() - 2,
00639                     datReg->points[ KDChartEnums::PosCenterLeft ].y() - 2,  5, 5);
00640                     */
00641                     datReg->startAngle = drawAngle;
00642                     datReg->angleLen   = drawAngle;
00643                     if( bMustAppendDatReg )
00644                         regions->append( datReg );
00645                 }
00646                 // calculate running sum for stacked and percent
00647                 if ( params()->polarChartSubType() == KDChartParams::PolarStacked ||
00648                         params()->polarChartSubType() == KDChartParams::PolarPercent )
00649                     currentValueSums[ value ] += cellValue;
00650             }
00651         }
00652         painter->drawPolygon( points );
00653     }
00654 
00655     painter->translate( -_dataRect.x(), -_dataRect.y() );
00656 }
00657 
00658 
00659 /*
00660   Helper methode being called by KDChartPolarPainter::paintData()
00661 */
00662 void KDChartPolarPainter::paintCircularAxisLabel( QPainter* painter,
00663         bool rotate,
00664         int txtAngle,
00665         QPoint center,
00666         double currentRadiusPPU,
00667         const QString& txt,
00668         int align,
00669         int step )
00670 {
00671     if( !rotate && (0 != (align & (Qt::AlignLeft | Qt::AlignRight) ) ) )
00672         currentRadiusPPU += center.x()*0.01;
00673     KDDrawText::drawRotatedText(
00674             painter,
00675             rotate ? txtAngle - 90 : 0,
00676             painter->worldMatrix().map(center - polarToXY( static_cast<int>( currentRadiusPPU ), txtAngle )),
00677             txt,
00678             0,
00679             step
00680             ? (rotate ? Qt::AlignBottom | Qt::AlignHCenter : align)
00681             : Qt::AlignCenter,
00682             false,0,false,
00683             false );
00684 }
00685 
00686 /*
00699 void KDChartPolarPainter::drawMarker( QPainter* painter,
00700         KDChartParams::PolarMarkerStyle style,
00701         const QColor& color,
00702         const QPoint& p,
00703         uint, //dataset,
00704         uint, //value,
00705         uint, //chart,
00706         double minSizeP1000,
00707         QRegion& region )
00708 {
00709     int xsize = params()->polarMarkerSize().width();
00710     if ( 0 > xsize )
00711         xsize = -1 * static_cast < int > ( xsize * minSizeP1000 );
00712     int ysize = params()->polarMarkerSize().height();
00713     if ( 0 > ysize )
00714         ysize = -1 * static_cast < int > ( ysize * minSizeP1000 );
00715     int xsize2 = xsize / 2;
00716     int ysize2 = ysize / 2;
00717     painter->setPen( color );
00718     switch ( style ) {
00719         case KDChartParams::PolarMarkerSquare: {
00720                                                   painter->save();
00721                                                   painter->setBrush( color );
00722                                                   QRect rect( QPoint( p.x() - xsize2, p.y() - ysize2 ), QPoint( p.x() + xsize2, p.y() + ysize2 ) );
00723                                                   painter->drawRect( rect );
00724                                                   // Don't use rect for drawing after this!
00725                                                   rect.moveBy( _dataRect.x(), _dataRect.y() );
00726                                                   region = QRegion( rect );
00727                                                   painter->restore();
00728                                                   break;
00729                                               }
00730         case KDChartParams::PolarMarkerDiamond: {
00731                                                     painter->save();
00732                                                     painter->setBrush( color );
00733                                                     QPointArray points( 4 );
00734                                                     points.setPoint( 0, p.x() - xsize2, p.y() );
00735                                                     points.setPoint( 1, p.x(), p.y() - ysize2 );
00736                                                     points.setPoint( 2, p.x() + xsize2, p.y() );
00737                                                     points.setPoint( 3, p.x(), p.y() + ysize2 );
00738                                                     painter->drawPolygon( points );
00739                                                     // Don't use points for drawing after this!
00740                                                     points.translate( _dataRect.x(), _dataRect.y() );
00741                                                     region = QRegion( points );
00742                                                     painter->restore();
00743                                                     break;
00744                                                 }
00745         case KDChartParams::PolarMarkerCircle:
00746         default: {
00747                     painter->save();
00748                     painter->setBrush( color );
00749                     painter->drawEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
00750                     QPointArray points;
00751                     points.makeEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
00752                     // Don't use points for drawing after this!
00753                     points.translate( _dataRect.x(), _dataRect.y() );
00754                     if( points.size() > 0 )
00755                         region = QRegion( points );
00756                     else
00757                         region = QRegion();
00758                     painter->restore();
00759                 }
00760     };
00761 }*/
00762 
00763 #define DEGTORAD(d) (d)*M_PI/180
00764 
00765 QPoint KDChartPolarPainter::polarToXY( int radius, int angle )
00766 {
00767     double anglerad = DEGTORAD( static_cast<double>( angle ) );
00768     QPoint ret( static_cast<int>( cos( anglerad ) * radius ),
00769             static_cast<int>( sin( anglerad ) * radius ) );
00770     return ret;
00771 }
00772 
00773 
00787 QString KDChartPolarPainter::fallbackLegendText( uint dataset ) const
00788 {
00789     return QObject::tr( "Series " ) + QString::number( dataset + 1 );
00790 }
00791 
00792 
00802 uint KDChartPolarPainter::numLegendFallbackTexts( KDChartTableDataBase* data ) const
00803 {
00804     return data->usedRows();
00805 }
KDE Home | KDE Accessibility Home | Description of Access Keys