/*
   KDChart - a multi-platform charting engine
   */

/****************************************************************************
 ** Copyright (C) 2001-2003 Klarälvdalens Datakonsult AB.  All rights reserved.
 **
 ** This file is part of the KDChart library.
 **
 ** This file may be distributed and/or modified under the terms of the
 ** GNU General Public License version 2 as published by the Free Software
 ** Foundation and appearing in the file LICENSE.GPL included in the
 ** packaging of this file.
 **
 ** Licensees holding valid commercial KDChart licenses may use this file in
 ** accordance with the KDChart Commercial License Agreement provided with
 ** the Software.
 **
 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** See http://www.klaralvdalens-datakonsult.se/?page=products for
 **   information about KDChart Commercial License Agreements.
 **
 ** Contact info@klaralvdalens-datakonsult.se if any conditions of this
 ** licensing are not clear to you.
 **
 **********************************************************************/
#include "KDChartPolarPainter.h"
#include <KDChartParams.h>
#include <KDChartAxisParams.h>
#include "KDChartAxesPainter.h"
#include "KDDrawText.h"

#include <tqpainter.h>

/**
  \class KDChartPolarPainter KDChartPolarPainter.h

  \brief A chart painter implementation that can paint polar charts.
*/

/**
  Constructor. Sets up internal data structures as necessary.

  \param params the KDChartParams structure that defines the chart
  \param data the data that will be displayed as a chart
*/
KDChartPolarPainter::KDChartPolarPainter( KDChartParams* params ) :
    KDChartPainter( params )
{
    // This constructor intentionally left blank so far; we cannot setup the
    // geometry yet since we do not know the size of the painter.
}


/**
  Destructor.
*/
KDChartPolarPainter::~KDChartPolarPainter()
{
    // intentionally left blank
}


/**
  Paints the actual data area. Data regions will only be added if \a
  regions is not 0 and the chart is configured to be drawn with
  markers.

  \param painter the TQPainter onto which the chart should be painted
  \param data the data that will be displayed as a chart
  \param paint2nd specifies whether the main chart or the additional chart is to be drawn now
  \param regions a pointer to a list of regions that will be filled
  with regions representing the data segments, if not null
*/
void KDChartPolarPainter::paintData( TQPainter* painter,
                                     KDChartTableDataBase* data,
                                     bool paint2nd,
                                     KDChartDataRegionList* regions )
{
    uint chart = paint2nd ? 1 : 0;

    TQRect ourClipRect( _dataRect );
    ourClipRect.setBottom( ourClipRect.bottom() - 1 ); // protect axes
    ourClipRect.setLeft( ourClipRect.left() + 1 );
    ourClipRect.setRight( ourClipRect.right() - 1 );
    //
    // PENDING(khz) adjust the clip rect if neccessary...
    //

    const TQWMatrix & world = painter->worldMatrix();
    ourClipRect = world.mapRect( ourClipRect );
    painter->setClipRect( ourClipRect );


    uint datasetStart, datasetEnd;
    findChartDatasets( data, paint2nd, chart, datasetStart, datasetEnd );


    painter->translate( _dataRect.x(), _dataRect.y() );


    // Number of values: If -1, use all values, otherwise use the
    // specified number of values.
    int numValues = 0;
    if ( params()->numValues() != -1 )
        numValues = params()->numValues();
    else
        numValues = data->usedCols();

    // compute position
    int size = TQMIN( _dataRect.width(), _dataRect.height() ); // initial size

    const double minSizeP1000 = size / 1000.0;

    int x = ( _dataRect.width() == size ) ? 0 : ( ( _dataRect.width() - size ) / 2 );
    int y = ( _dataRect.height() == size ) ? 0 : ( ( _dataRect.height() - size ) / 2 );
    TQRect position( x, y, size, size );

    TQPoint center( position.width() / 2 + position.x(),
                   position.height() / 2 + position.y() );


    double maxValue;
    switch ( params()->polarChartSubType() ) {
        case KDChartParams::PolarNormal:
            maxValue = data->maxValue();
            break;
        case KDChartParams::PolarPercent:
            maxValue = 100.0;
            break;
        default:
            maxValue = TQMAX( data->maxColSum(), 0.0 );
    }

    double pixelsPerUnit = 0.0;
    // the / 2 in the next line is there because we need the space in
    // both directions
    pixelsPerUnit = (position.height() / maxValue / 2) * 1000 / 1250;

    TQMap < int, double > currentValueSums;
    if (    params()->polarChartSubType() == KDChartParams::PolarStacked
            || params()->polarChartSubType() == KDChartParams::PolarPercent )
        // this array is only used for stacked and percent polar
        // charts, no need to waste time initializing it for normal
        // ones
        for ( int value = 0; value < numValues; value++ )
            currentValueSums[ value ] = 0.0;
    TQMap < int, double > totalValueSums;


    /*
       axes schema: use AxisPosSagittal for sagittal 'axis' lines
       use AxisPosCircular for circular 'axis'
       */
    const KDChartAxisParams & paraSagittal = params()->axisParams( KDChartAxisParams::AxisPosSagittal );
    const KDChartAxisParams & paraCircular = params()->axisParams( KDChartAxisParams::AxisPosCircular );

    int sagittalLineWidth = 0 <= paraSagittal.axisLineWidth()
        ? paraSagittal.axisLineWidth()
        : -1 * static_cast < int > (   paraSagittal.axisLineWidth()
                * minSizeP1000 );
    ( ( KDChartAxisParams& ) paraSagittal ).setAxisTrueLineWidth( sagittalLineWidth );
    int sagittalGridLineWidth
        = (    KDCHART_AXIS_GRID_AUTO_LINEWIDTH
                == paraSagittal.axisGridLineWidth() )
        ? sagittalLineWidth
        : (   ( 0 <= paraSagittal.axisGridLineWidth() )
                ? paraSagittal.axisGridLineWidth()
                : -1 * static_cast < int > (   paraSagittal.axisGridLineWidth()
                    * minSizeP1000 ) );

    int circularLineWidth = 0 <= paraCircular.axisLineWidth()
        ? paraCircular.axisLineWidth()
        : -1 * static_cast < int > (   paraCircular.axisLineWidth()
                * minSizeP1000 );
    ( ( KDChartAxisParams& ) paraCircular ).setAxisTrueLineWidth( circularLineWidth );
    int circularGridLineWidth
        = (    KDCHART_AXIS_GRID_AUTO_LINEWIDTH
                == paraCircular.axisGridLineWidth() )
        ? circularLineWidth
        : (   ( 0 <= paraCircular.axisGridLineWidth() )
                ? paraCircular.axisGridLineWidth()
                : -1 * static_cast < int > (   paraCircular.axisGridLineWidth()
                    * minSizeP1000 ) );

    TQFont actFont;
    int labels = 0;
    double currentRadiusPPU = position.height() / 2.0;

    // draw the "axis" circles
    if( paraCircular.axisShowGrid()
            || paraCircular.axisVisible()
            || paraCircular.axisLabelsVisible() ) {

        double radiusPPU = maxValue * pixelsPerUnit;
        double pDelimDelta = 0.0;

        // calculate label texts
        TQStringList* labelTexts = 0;
        ((KDChartParams*)params())->setAxisArea( KDChartAxisParams::AxisPosCircular,
                                                 TQRect( 0,
                                                     0,
                                                     static_cast<int>( radiusPPU ),
                                                     static_cast<int>( radiusPPU ) ) );

        double delimLen = 20.0 * minSizeP1000; // per mille of area
        KDChartAxisParams::AxisPos basicPos;
        TQPoint orig, dest;
        double dDummy;
        double nSubDelimFactor = 0.0;
        double nTxtHeight = 0.0;
        double pTextsX = 0.0;
        double pTextsY = 0.0;
        double pTextsW = 0.0;
        double pTextsH = 0.0;
        int textAlign = TQt::AlignHCenter | TQt::AlignVCenter;
        bool isLogarithmic = false;
        bool isDateTime = false;
        bool autoDtLabels = false;
        TQDateTime dtLow;
        TQDateTime dtHigh;
        KDChartAxisParams::ValueScale dtDeltaScale;
        KDChartAxesPainter::calculateLabelTexts(
                painter,
                *data,
                *params(),
                KDChartAxisParams::AxisPosCircular,
                minSizeP1000,
                delimLen,
                // start of reference parameters
                basicPos,
                orig,
                dest,
                dDummy,dDummy,dDummy,dDummy,
                nSubDelimFactor,
                pDelimDelta,
                nTxtHeight,
                pTextsX,
                pTextsY,
                pTextsW,
                pTextsH,
                textAlign,
                isLogarithmic,
                isDateTime,
                autoDtLabels,
                dtLow,
                dtHigh,
                dtDeltaScale );
                labelTexts = ( TQStringList* ) paraCircular.axisLabelTexts();
        if( paraCircular.axisLabelsVisible() ) {
//tqDebug("\nnTxtHeight: "+TQString::number(nTxtHeight));
            // calculate font size
            actFont = paraCircular.axisLabelsFont();
            if ( paraCircular.axisLabelsFontUseRelSize() ) {
//tqDebug("paraCircular.axisLabelsFontUseRelSize() is true");
                actFont.setPointSizeFloat( nTxtHeight );
            }
            TQFontMetrics fm( actFont );
            TQString strMax;
            int maxLabelsWidth = 0;
            for ( TQStringList::Iterator it = labelTexts->begin();
                    it != labelTexts->end();
                    ++it ) {
                if ( fm.width( *it ) > maxLabelsWidth ) {
                    maxLabelsWidth = fm.width( *it );
                    strMax = *it;
                }
            }
            while ( fm.width( strMax ) > pTextsW
                    && 6.0 < nTxtHeight ) {
                nTxtHeight -= 0.5;
                actFont.setPointSizeFloat( nTxtHeight );
                fm = TQFontMetrics( actFont );
            }
            painter->setFont( actFont );
        }

        double radiusDelta = pDelimDelta;

        labels = labelTexts
            ? labelTexts->count()
            : 0;
        if( labels )
            currentRadiusPPU = -radiusDelta;
        for( int iLabel = 0; iLabel < labels; ++iLabel ) {
            //while( currentRadius < maxValue ) {
            //double currentRadiusPPU = currentRadius;
            currentRadiusPPU += radiusDelta;
            double currentRadiusPPU2 = currentRadiusPPU * 2;
            int circularAxisAngle = ( currentRadiusPPU != 0.0 ) ? ( static_cast < int > (4.0 * radiusPPU / currentRadiusPPU) ) : 0;
            if( paraCircular.axisShowGrid() ) {
                painter->setPen( TQPen( paraCircular.axisGridColor(),
                            circularGridLineWidth ) );
                painter->drawEllipse( static_cast<int>( center.x() - currentRadiusPPU ),
                        static_cast<int>( center.y() - currentRadiusPPU ),
                        static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ) );
            }
            if( paraCircular.axisVisible() ) {
                painter->setPen( TQPen( paraCircular.axisLineColor(),
                            circularLineWidth ) );
                if( params()->polarDelimAtPos( KDChartEnums::PosTopCenter ) )
                    painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
                            static_cast<int>( center.y() - currentRadiusPPU ),
                            static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
                            (90 - circularAxisAngle/2) * 16,
                            circularAxisAngle * 16 );
                if( params()->polarDelimAtPos( KDChartEnums::PosBottomCenter ) )
                    painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
                            static_cast<int>( center.y() - currentRadiusPPU ),
                            static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
                            (270 - circularAxisAngle/2) * 16,
                            circularAxisAngle * 16 );

                if( params()->polarDelimAtPos( KDChartEnums::PosCenterRight ) )
                    painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
                            static_cast<int>( center.y() - currentRadiusPPU ),
                            static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
                            (0 - circularAxisAngle/2) * 16,
                            circularAxisAngle * 16 );
                if( params()->polarDelimAtPos( KDChartEnums::PosCenterLeft ) )
                    painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
                            static_cast<int>( center.y() - currentRadiusPPU ),
                            static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
                            (180 - circularAxisAngle/2) * 16,
                            circularAxisAngle * 16 );

                if( params()->polarDelimAtPos( KDChartEnums::PosTopRight ) )
                    painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
                            static_cast<int>( center.y() - currentRadiusPPU ),
                            static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
                            (45 - circularAxisAngle/2) * 16,
                            circularAxisAngle * 16 );
                if( params()->polarDelimAtPos( KDChartEnums::PosBottomLeft ) )
                    painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
                            static_cast<int>( center.y() - currentRadiusPPU ),
                            static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
                            (225 - circularAxisAngle/2) * 16,
                            circularAxisAngle * 16 );

                if( params()->polarDelimAtPos( KDChartEnums::PosBottomRight ) )
                    painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
                            static_cast<int>( center.y() - currentRadiusPPU ),
                            static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
                            (315 - circularAxisAngle/2) * 16,
                            circularAxisAngle * 16 );
                if( params()->polarDelimAtPos( KDChartEnums::PosTopLeft ) )
                    painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
                            static_cast<int>( center.y() - currentRadiusPPU ),
                            static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
                            (135 - circularAxisAngle/2) * 16,
                            circularAxisAngle * 16 );
            }
            if( paraCircular.axisLabelsVisible() ) {
                const bool rotate = params()->polarRotateCircularLabels();
                painter->setPen( TQPen( paraCircular.axisLabelsColor(),
                                       circularLineWidth ) );
                const TQString& txt = (*labelTexts)[ iLabel ];
                if( params()->polarLabelsAtPos( KDChartEnums::PosTopCenter ) )
                    paintCircularAxisLabel( painter, rotate, 90, center, currentRadiusPPU, txt,
                            TQt::AlignBottom | TQt::AlignHCenter, iLabel );

                if( params()->polarLabelsAtPos( KDChartEnums::PosBottomCenter ) )
                    paintCircularAxisLabel( painter, rotate, 270, center, currentRadiusPPU, txt,
                            TQt::AlignTop | TQt::AlignHCenter, iLabel );

                if( params()->polarLabelsAtPos( KDChartEnums::PosCenterRight ) )
                    paintCircularAxisLabel( painter, rotate,   0, center, currentRadiusPPU, txt,
                            TQt::AlignVCenter | TQt::AlignRight, iLabel );

                if( params()->polarLabelsAtPos( KDChartEnums::PosCenterLeft ) )
                    paintCircularAxisLabel( painter, rotate, 180, center, currentRadiusPPU, txt,
                            TQt::AlignVCenter | TQt::AlignLeft, iLabel );

                if( params()->polarLabelsAtPos( KDChartEnums::PosTopRight ) )
                    paintCircularAxisLabel( painter, rotate,  45, center, currentRadiusPPU, txt,
                            TQt::AlignBottom | TQt::AlignRight, iLabel );

                if( params()->polarLabelsAtPos( KDChartEnums::PosBottomLeft ) )
                    paintCircularAxisLabel( painter, rotate, 225, center, currentRadiusPPU, txt,
                            TQt::AlignTop | TQt::AlignLeft, iLabel );

                if( params()->polarLabelsAtPos( KDChartEnums::PosBottomRight ) )
                    paintCircularAxisLabel( painter, rotate, 315, center, currentRadiusPPU, txt,
                            TQt::AlignTop | TQt::AlignRight, iLabel );

                if( params()->polarLabelsAtPos( KDChartEnums::PosTopLeft ) )
                    paintCircularAxisLabel( painter, rotate, 135, center, currentRadiusPPU, txt,
                            TQt::AlignBottom | TQt::AlignLeft, iLabel );
            }
        }
    }


    double circularSpan = params()->polarChartSubType() == KDChartParams::PolarPercent
        ? 100.0
        : paraCircular.trueAxisHigh() - paraCircular.trueAxisLow();
    double radius = currentRadiusPPU;
    if(    !labels
            || params()->polarChartSubType() == KDChartParams::PolarPercent )
        radius = (position.width() / 2.0) * 1000.0 / 1250.0;

    if( params()->polarChartSubType() != KDChartParams::PolarPercent )
        pixelsPerUnit = labels ? currentRadiusPPU / circularSpan
            : (position.height() / maxValue / 2.0) * 1000.0 / 1250.0;
    else
        pixelsPerUnit = (position.height() / 100.0 / 2.0) * 1000.0 / 1250.0;

    // draw the sagittal grid and axis lines
    if(    paraSagittal.axisShowGrid()
            || paraSagittal.axisVisible()
            || paraSagittal.axisLabelsVisible() ) {

        // calculate label texts
        TQStringList* labelTexts = 0;
        bool onlyDefaultLabels = true;
        if( paraSagittal.axisLabelsVisible() ) {
            ((KDChartParams*)params())->setAxisArea( KDChartAxisParams::AxisPosSagittal,
                                                    TQRect( 0,
                                                        0,
                                                        static_cast < int > ( 2.0 * M_PI * radius ),
                                                        static_cast < int > ( 0.5 * radius ) ) );
            double delimLen = 20.0 * minSizeP1000; // per mille of area
            KDChartAxisParams::AxisPos basicPos;
            TQPoint orig, dest;
            double dDummy;
            double nSubDelimFactor = 0.0;
            double pDelimDelta = 0.0;
            double nTxtHeight = 0.0;
            double pTextsX = 0.0;
            double pTextsY = 0.0;
            double pTextsW = 0.0;
            double pTextsH = 0.0;
            int textAlign = TQt::AlignCenter;
            bool isLogarithmic = false;
            bool isDateTime = false;
            bool autoDtLabels = false;
            TQDateTime dtLow;
            TQDateTime dtHigh;
            KDChartAxisParams::ValueScale dtDeltaScale;
            KDChartAxesPainter::calculateLabelTexts(
                    painter,
                    *data,
                    *params(),
                    KDChartAxisParams::AxisPosSagittal,
                    minSizeP1000,
                    delimLen,
                    // start of reference parameters
                    basicPos,
                    orig,
                    dest,
                    dDummy,dDummy,dDummy,dDummy,
                    nSubDelimFactor,
                    pDelimDelta,
                    nTxtHeight,
                    pTextsX,
                    pTextsY,
                    pTextsW,
                    pTextsH,
                    textAlign,
                    isLogarithmic,
                    isDateTime,
                    autoDtLabels,
                    dtLow,
                    dtHigh,
                    dtDeltaScale );
                    labelTexts = ( TQStringList* ) paraSagittal.axisLabelTexts();
                    // calculate font size
                    actFont = paraSagittal.axisLabelsFont();
                    if ( paraSagittal.axisLabelsFontUseRelSize() ) {
                        actFont.setPointSizeFloat( nTxtHeight );
                    }
                    TQFontMetrics fm( actFont );
                    TQString strMax;
                    int maxLabelsWidth = 0;
                    for ( TQStringList::Iterator it = labelTexts->begin();
                            it != labelTexts->end();
                            ++it ) {
                        if ( fm.width( *it ) > maxLabelsWidth ) {
                            maxLabelsWidth = fm.width( *it );
                            strMax = *it;
                        }
                        if ( !(*it).startsWith( "Item ") )
                            onlyDefaultLabels = false;
                    }
                    while ( fm.width( strMax ) > pTextsW && 6.0 < nTxtHeight ) {
                        nTxtHeight -= 0.5;
                        actFont.setPointSizeFloat( nTxtHeight );
                        fm = TQFontMetrics( actFont );
                    }
                    painter->setFont( actFont );
        }

        int currentAngle = params()->polarZeroDegreePos();
        if(    -360 > currentAngle
                ||  360 < currentAngle )
            currentAngle = 0;
        if( 0 > currentAngle )
            currentAngle += 360;
        int r1 = static_cast < int > ( radius * 1050 / 1000 );
        int r2 = static_cast < int > ( radius * 1100 / 1000 );
        int r3 = static_cast < int > ( radius * 1175 / 1000 );
        TQPoint pt1, pt2, pt3;
        uint nLabels = labelTexts->count();
        int angleBetweenRays = 360 / nLabels;
        for( uint value = 0; value < nLabels; ++value ) {
            pt1 = center + polarToXY( r1, currentAngle );
            pt2 = center + polarToXY( r2, currentAngle );
            pt3 = center + polarToXY( r3, currentAngle );

            //pt3 = painter->worldMatrix().map( pt3 );

            if( paraSagittal.axisShowGrid() ) {
                painter->setPen( TQPen( paraSagittal.axisGridColor(),
                            sagittalGridLineWidth ) );
                painter->drawLine( center, pt1 );
            }
            if( paraSagittal.axisVisible() ) {
                painter->setPen( TQPen( paraSagittal.axisLineColor(),
                            sagittalLineWidth ) );
                painter->drawLine( pt1, pt2 );
            }
            if(    paraSagittal.axisLabelsVisible()
                    && labelTexts
                    && labelTexts->count() > value ) {
                painter->setPen( TQPen( paraSagittal.axisLabelsColor(),
                            sagittalLineWidth ) );
                TQString label(   onlyDefaultLabels
                        ? TQString::number( currentAngle )
                        : (*labelTexts)[ value ] );

                KDDrawText::drawRotatedText( painter,
                        currentAngle+90,
                        painter->worldMatrix().map(pt3),
                        label,
                        0,
                        TQt::AlignCenter );
            }
            currentAngle += angleBetweenRays;
        }
    }


    // Now draw the data
    int dataLinesWidth = 0 <= params()->polarLineWidth()
        ? params()->polarLineWidth()
        : -1 * static_cast < int > (   params()->polarLineWidth()
                * minSizeP1000 );
    painter->setBrush( TQt::NoBrush );
    for ( unsigned int dataset = datasetStart; dataset <= datasetEnd; dataset++ ) {
        painter->setPen( TQPen( params()->dataColor( dataset ),
                    dataLinesWidth ) );
        TQPointArray points( numValues );
        int totalPoints = 0;
        double valueTotal = 0.0; // Will only be used for Percent
        int angleBetweenRays = 360 / numValues;
        TQVariant vValY;
        for ( int value = 0; value < numValues; value++ ) {
            if( params()->polarChartSubType() == KDChartParams::PolarPercent )
                valueTotal = data->colAbsSum( value );
            // the value determines the angle, the dataset only the color
            if( data->cellCoord( dataset, value, vValY, 1 ) &&
                TQVariant::Double == vValY.type() ){
                const double cellValue = vValY.toDouble();
                double drawValue;
                if ( params()->polarChartSubType() == KDChartParams::PolarStacked )
                    drawValue = ( cellValue + currentValueSums[ value ] ) * pixelsPerUnit;
                else if( params()->polarChartSubType() == KDChartParams::PolarPercent ) {
                    drawValue = (   ( cellValue + currentValueSums[ value ] )
                            / valueTotal * static_cast<double>( radius ) );
                } else
                    drawValue = cellValue * pixelsPerUnit;

                // record the point for drawing the polygon later
                int drawAngle = value * angleBetweenRays;
                TQPoint drawPoint( center + polarToXY( static_cast<int>( drawValue ),
                                  drawAngle ) );
                points.setPoint( totalPoints, drawPoint );
                totalPoints++;
                KDChartDataRegion* datReg = 0;
                // the marker can be drawn now
                if( params()->polarMarker() ) {
                    int xsize = params()->polarMarkerSize().width();
                    int ysize = params()->polarMarkerSize().height();
                    datReg = drawMarker( painter,
                                        params(),
                                        _areaWidthP1000, _areaHeightP1000,
                                        _dataRect.x(), _dataRect.y(),
                                        params()->polarMarkerStyle( dataset ),
                                        params()->dataColor( dataset ),
                                        drawPoint,
                                        dataset, value, chart,
                                        regions,
                                        xsize ? &xsize : 0,
                                        ysize ? &ysize : 0 );
                    painter->setPen( TQPen( params()->dataColor( dataset ),
                                    dataLinesWidth ) );
                }
                if ( regions ) {
                    bool bMustAppendDatReg = 0 == datReg;
                    if( bMustAppendDatReg ){
                        TQRect rect( TQPoint( drawPoint.x() - 1,
                                            drawPoint.y() - 1 ),
                                    TQSize( 3, 3 ) );
                        datReg = new KDChartDataRegion( dataset,
                                                        value,
                                                        chart,
                                                        rect );
                    }
                    datReg->points[ KDChartEnums::PosTopLeft ] =
                        drawPoint + _dataRect.topLeft();

                    datReg->points[     KDChartEnums::PosTopCenter ]    =
                        datReg->points[ KDChartEnums::PosTopLeft ];
                    datReg->points[     KDChartEnums::PosTopRight ]     =
                        datReg->points[ KDChartEnums::PosTopLeft ];
                    datReg->points[     KDChartEnums::PosBottomLeft ]   =
                        datReg->points[ KDChartEnums::PosTopLeft ];
                    datReg->points[     KDChartEnums::PosBottomCenter ] =
                        datReg->points[ KDChartEnums::PosTopLeft ];
                    datReg->points[     KDChartEnums::PosBottomRight ]  =
                        datReg->points[ KDChartEnums::PosTopLeft ];
                    datReg->points[     KDChartEnums::PosCenterLeft ]   =
                        datReg->points[ KDChartEnums::PosTopLeft ];
                    datReg->points[     KDChartEnums::PosCenter ]       =
                        datReg->points[ KDChartEnums::PosTopLeft ];
                    datReg->points[     KDChartEnums::PosCenterRight ]  =
                        datReg->points[ KDChartEnums::PosTopLeft ];
                    /*
                    // test the center positions:
                    painter->drawEllipse( datReg->points[ KDChartEnums::PosCenterLeft ].x() - 2,
                    datReg->points[ KDChartEnums::PosCenterLeft ].y() - 2,  5, 5);
                    */
                    datReg->startAngle = drawAngle;
                    datReg->angleLen   = drawAngle;
                    if( bMustAppendDatReg )
                        regions->append( datReg );
                }
                // calculate running sum for stacked and percent
                if ( params()->polarChartSubType() == KDChartParams::PolarStacked ||
                        params()->polarChartSubType() == KDChartParams::PolarPercent )
                    currentValueSums[ value ] += cellValue;
            }
        }
        painter->drawPolygon( points );
    }

    painter->translate( -_dataRect.x(), -_dataRect.y() );
}


/*
  Helper methode being called by KDChartPolarPainter::paintData()
*/
void KDChartPolarPainter::paintCircularAxisLabel( TQPainter* painter,
        bool rotate,
        int txtAngle,
        TQPoint center,
        double currentRadiusPPU,
        const TQString& txt,
        int align,
        int step )
{
    if( !rotate && (0 != (align & (TQt::AlignLeft | TQt::AlignRight) ) ) )
        currentRadiusPPU += center.x()*0.01;
    KDDrawText::drawRotatedText(
            painter,
            rotate ? txtAngle - 90 : 0,
            painter->worldMatrix().map(center - polarToXY( static_cast<int>( currentRadiusPPU ), txtAngle )),
            txt,
            0,
            step
            ? (rotate ? TQt::AlignBottom | TQt::AlignHCenter : align)
            : TQt::AlignCenter,
            false,0,false,
            false );
}


/*!
  Draws the marker for one data point according to the specified style.

  \param painter the painter to draw on
  \param style what kind of marker is drawn (square, diamond or circle)
  \param color the color in which to draw the marker
  \param p the center of the marker
  \param dataset the dataset which this marker represents
  \param value the value which this marker represents
  \param regions a list of regions for data points, a new region for the new
  marker will be appended to this list if it is not 0
*//*
void KDChartPolarPainter::drawMarker( TQPainter* painter,
        KDChartParams::PolarMarkerStyle style,
        const TQColor& color,
        const TQPoint& p,
        uint, //dataset,
        uint, //value,
        uint, //chart,
        double minSizeP1000,
        TQRegion& region )
{
    int xsize = params()->polarMarkerSize().width();
    if ( 0 > xsize )
        xsize = -1 * static_cast < int > ( xsize * minSizeP1000 );
    int ysize = params()->polarMarkerSize().height();
    if ( 0 > ysize )
        ysize = -1 * static_cast < int > ( ysize * minSizeP1000 );
    int xsize2 = xsize / 2;
    int ysize2 = ysize / 2;
    painter->setPen( color );
    switch ( style ) {
        case KDChartParams::PolarMarkerSquare: {
                                                  painter->save();
                                                  painter->setBrush( color );
                                                  TQRect rect( TQPoint( p.x() - xsize2, p.y() - ysize2 ), TQPoint( p.x() + xsize2, p.y() + ysize2 ) );
                                                  painter->drawRect( rect );
                                                  // Don't use rect for drawing after this!
                                                  rect.moveBy( _dataRect.x(), _dataRect.y() );
                                                  region = TQRegion( rect );
                                                  painter->restore();
                                                  break;
                                              }
        case KDChartParams::PolarMarkerDiamond: {
                                                    painter->save();
                                                    painter->setBrush( color );
                                                    TQPointArray points( 4 );
                                                    points.setPoint( 0, p.x() - xsize2, p.y() );
                                                    points.setPoint( 1, p.x(), p.y() - ysize2 );
                                                    points.setPoint( 2, p.x() + xsize2, p.y() );
                                                    points.setPoint( 3, p.x(), p.y() + ysize2 );
                                                    painter->drawPolygon( points );
                                                    // Don't use points for drawing after this!
                                                    points.translate( _dataRect.x(), _dataRect.y() );
                                                    region = TQRegion( points );
                                                    painter->restore();
                                                    break;
                                                }
        case KDChartParams::PolarMarkerCircle:
        default: {
                    painter->save();
                    painter->setBrush( color );
                    painter->drawEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
                    TQPointArray points;
                    points.makeEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
                    // Don't use points for drawing after this!
                    points.translate( _dataRect.x(), _dataRect.y() );
                    if( points.size() > 0 )
                        region = TQRegion( points );
                    else
                        region = TQRegion();
                    painter->restore();
                }
    };
}*/

#define DEGTORAD(d) (d)*M_PI/180

TQPoint KDChartPolarPainter::polarToXY( int radius, int angle )
{
    double anglerad = DEGTORAD( static_cast<double>( angle ) );
    TQPoint ret( static_cast<int>( cos( anglerad ) * radius ),
            static_cast<int>( sin( anglerad ) * radius ) );
    return ret;
}


/**
  This method is a specialization that returns a fallback legend text
  appropriate for polar charts where the fallbacks should come from
  the values, not from the datasets.

  This method is only used when automatic legends are used, because
  manual and first-column legends do not need fallback texts.

  \param uint dataset the dataset number for which to generate a
  fallback text
  \return the fallback text to use for describing the specified
  dataset in the legend
*/
TQString KDChartPolarPainter::fallbackLegendText( uint dataset ) const
{
    return TQObject::tr( "Series " ) + TQString::number( dataset + 1 );
}


/**
  This methods returns the number of elements to be shown in the
  legend in case fallback texts are used.

  This method is only used when automatic legends are used, because
  manual and first-column legends do not need fallback texts.

  \return the number of fallback texts to use
*/
uint KDChartPolarPainter::numLegendFallbackTexts( KDChartTableDataBase* data ) const
{
    return data->usedRows();
}
