kchart

KDChartLinesPainter.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 "KDChartLinesPainter.h"
00030 #include <KDChartParams.h>
00031 #include <KDChartPropertySet.h>
00032 
00033 #include <qpainter.h>
00034 
00035 #if COMPAT_QT_VERSION >= 0x030000
00036 #include <qvaluevector.h>
00037 #else
00038 #include <qarray.h>
00039 #endif
00040 
00041 #include <stdlib.h>
00042 
00055 KDChartLinesPainter::KDChartLinesPainter( KDChartParams* params ) :
00056     KDChartAxesPainter( params )
00057 {
00058     // This constructor intentionally left blank so far; we cannot setup the
00059     // geometry yet since we do not know the size of the painter.
00060 }
00061 
00062 
00066 KDChartLinesPainter::~KDChartLinesPainter()
00067 {
00068     // intentionally left blank
00069 }
00070 
00071 
00082 void KDChartLinesPainter::paintData( QPainter* painter,
00083                                      KDChartTableDataBase* data,
00084                                      bool paint2nd,
00085                                      KDChartDataRegionList* regions )
00086 {
00087     paintDataInternal( painter, data,
00088                        true,   // center points
00089                        params()->lineMarker() && !params()->threeDLines(),  // line markers yes/no, 3D lines have no markers
00090                        false,  // not an area
00091                        paint2nd,
00092                        regions );
00093 }
00094 
00115 void KDChartLinesPainter::paintDataInternal( QPainter* painter,
00116                                              KDChartTableDataBase* data,
00117                                              bool centerThePoints,
00118                                              bool drawMarkers,
00119                                              bool isArea,
00120                                              bool paint2nd,
00121                                              KDChartDataRegionList* regions )
00122 {
00123     mCenterThePoints = centerThePoints;
00124     mDrawMarkers = drawMarkers;
00125     mIsArea = isArea;
00126     mChartType = paint2nd ? params()->additionalChartType()
00127         : params()->chartType();
00128 
00129     KDChartAxesPainter::paintData( painter, data, paint2nd, regions );
00130 }
00131 
00132 
00133 #define DEGTORAD(d) (d)*M_PI/180
00134 
00140 QPoint KDChartLinesPainter::project( int x, int y, int z )
00141 {
00142 
00143     double xrad = DEGTORAD( params()->threeDLineXRotation() );
00144     double yrad = DEGTORAD( params()->threeDLineYRotation() );
00145     QPoint ret( static_cast<int>( x*cos( yrad ) + z * sin( yrad ) ),
00146                 static_cast<int>( y*cos( xrad ) - z * sin( xrad ) ) );
00147     return ret;
00148 }
00149 
00150 bool KDChartLinesPainter::isNormalMode() const
00151 {
00152     return KDChartParams::LineNormal == params()->lineChartSubType();
00153 }
00154 
00155 int KDChartLinesPainter::clipShiftUp( bool, double ) const
00156 {
00157     return 0;
00158 }
00159 
00160 
00161 class MyPoint
00162 {
00163 public:
00164     MyPoint() : bValid( false ), bSkipThis( false ), cellValue( 0.0 ) {}
00165     void set( int x, int y, double value ) {
00166         bValid = true;
00167         p.setX( x );
00168         p.setY( y );
00169         cellValue = value;
00170     }
00171     void setSkipThis( bool skipThis ) {
00172         bSkipThis = skipThis;
00173     }
00174     QPoint p;
00175     bool   bValid;
00176     bool   bSkipThis;
00177     double cellValue;
00178 };
00179 
00180 
00181 void KDChartLinesPainter::specificPaintData( QPainter* painter,
00182                                              const QRect& /*ourClipRect*/,
00183                                              KDChartTableDataBase* data,
00184                                              KDChartDataRegionList* regions,
00185                                              const KDChartAxisParams* ordinatePara,
00186                                              bool /*bNormalMode*/,
00187                                              uint chart,
00188                                              double logWidth,
00189                                              double /*areaWidthP1000*/,
00190                                              double logHeight,
00191                                              double axisYOffset,
00192                                              double minColumnValue,
00193                                              double maxColumnValue,
00194                                              double columnValueDistance,
00195                                              uint /*chartDatasetStart*/,
00196                                              uint /*chartDatasetEnd*/,
00197                                              uint datasetStart,
00198                                              uint datasetEnd )
00199 {
00200     if( !data ) return;
00201 
00202 
00203     abscissaInfos ai;
00204     ai.bCenterThePoints = mCenterThePoints;
00205     calculateAbscissaInfos( *params(), *data,
00206                             datasetStart, datasetEnd,
00207                             logWidth, _dataRect,
00208                             ai );
00209     mCenterThePoints = ai.bCenterThePoints;
00210 
00211     bool bOrdinateDecreasing = ordinatePara
00212         ? ordinatePara->axisValuesDecreasing()
00213         : false;
00214     bool bOrdinateIsLogarithmic
00215         = ordinatePara
00216         ? (KDChartAxisParams::AxisCalcLogarithmic == ordinatePara->axisCalcMode())
00217         : false;
00218 
00219     //const double ordinatePixelsPerUnit = logHeight / columnValueDistance;
00220     const double ordinatePixelsPerUnit
00221         = (    ordinatePara
00222                && (0.0 != ordinatePara->trueAxisDeltaPixels())
00223                && (0.0 != ordinatePara->trueAxisDelta()))
00224         ? ordinatePara->trueAxisDeltaPixels() / ordinatePara->trueAxisDelta()
00225         : logHeight / columnValueDistance;;
00226     //qDebug("ordinatePixelsPerUnit: %f",ordinatePixelsPerUnit);
00227 
00228 
00229     const bool showThreeDLines = !mIsArea && params()->threeDLines();
00230 
00231     enum { Normal, Stacked, Percent } mode = Normal;
00232     if (    (    ( mChartType                   == KDChartParams::Line )
00233                  && ( params()->lineChartSubType() == KDChartParams::LineNormal ) )
00234             || (    ( mChartType                   == KDChartParams::Area )
00235                     && ( params()->areaChartSubType() == KDChartParams::AreaNormal ) ) )
00236         mode = Normal;
00237     else if (    (    ( mChartType                   == KDChartParams::Line )
00238                       && ( params()->lineChartSubType() == KDChartParams::LineStacked ) )
00239                  || (    ( mChartType                   == KDChartParams::Area )
00240                          && ( params()->areaChartSubType() == KDChartParams::AreaStacked ) ) )
00241         mode = Stacked;
00242     else if (    (    ( mChartType                   == KDChartParams::Line )
00243                       && ( params()->lineChartSubType() == KDChartParams::LinePercent ) )
00244                  || (    ( mChartType                   == KDChartParams::Area )
00245                          && ( params()->areaChartSubType() == KDChartParams::AreaPercent ) ) )
00246         mode = Percent;
00247     else
00248         qDebug( "Internal error in KDChartLinesPainter::paintDataInternal(): Unknown subtype" );
00249 
00250 
00251     QMap < int, double > currentValueSums;
00252     if ( mode == Stacked || mode == Percent ) {
00253         // this array is only used for stacked and percent lines, no need
00254         // to waste time initializing it for normal types
00255         for ( int value = 0; value < ai.numValues; ++value )
00256             currentValueSums[ value ] = 0.0;
00257     }
00258     QMap < int, double > totalValueSums;
00259 
00260     // compute the position of the 0 axis
00261     double zeroXAxisI;
00262     if ( mode == Percent ) {
00263         if ( minColumnValue == 0.0 )
00264             zeroXAxisI = logHeight + axisYOffset;
00265         else if( maxColumnValue == 0.0 )
00266             zeroXAxisI = _dataRect.y() + axisYOffset;
00267         else
00268             zeroXAxisI = logHeight / 2.0 + _dataRect.y();
00269     } else
00270         zeroXAxisI = ordinatePara->axisZeroLineStartY() - _dataRect.y();
00271 
00272 
00273     // compute how to shift of the points in case we want them in the
00274     // middle of their respective columns
00275     int xShift = mCenterThePoints ? static_cast < int > ( ai.pointDist * 0.5 ) : 0;
00276 
00277 
00278     // calculate all points' positions
00279     // ===============================
00280     int arrayNumDatasets = 0;
00281     int arrayNumValues   = ai.bAbscissaHasTrueAxisDtValues
00282         ? data->cols()
00283         : ai.numValues;
00284     int dataset;
00285     for( dataset = datasetEnd;
00286          ( dataset >= static_cast < int > ( datasetStart ) && dataset >= 0 );
00287          --dataset )
00288         ++arrayNumDatasets;
00289 #if COMPAT_QT_VERSION >= 0x030000
00290     QValueVector<MyPoint> allPoints(
00291 #else
00292     QArray<MyPoint> allPoints(
00293 #endif
00294                               arrayNumDatasets * arrayNumValues );
00295                                     
00296     KDChartPropertySet curPropSet;
00297     int curPropSetId = KDChartPropertySet::UndefinedID;
00298                                     
00299     for( dataset = datasetEnd; ( dataset >= (int)datasetStart && dataset >= 0 ); --dataset ) {
00300                                         
00301         int prevPointX = -1;
00302         int prevPointY = -1;
00303                                         
00304         const KDChartParams::LineMarkerStyle
00305             defaultMarkerStyle = params()->lineMarkerStyle( dataset );
00306         const QPen default2DPen(   params()->lineColor().isValid()
00307                                    ? params()->lineColor()
00308                                    : params()->dataColor( dataset ),
00309                                    params()->lineWidth(),
00310                                    params()->lineStyle( dataset ) );
00311 
00312         if( ai.bAbscissaHasTrueAxisDtValues )
00313             ai.numValues = data->cols();
00314 
00315         QVariant vValY;
00316         QVariant vValX;
00317         int cellPropID;
00318         for( int value = 0; value < ai.numValues; ++value ) {
00319             //if ( mode == Percent )
00320             //    valueTotal = data->colAbsSum( value );
00321             double valueTotal = 0.0; // Will only be used for Percent
00322             if( mode == Percent ) {
00323                 valueTotal = 0.0;
00324                 // iterate over datasets of this axis only:
00325                 for ( uint dataset2  = datasetStart;
00326                       dataset2 <= datasetEnd;
00327                       ++dataset2 ) {
00328                     if( data->cellCoord( dataset2, value, vValY, 1 ) &&
00329                         QVariant::Double == vValY.type() )
00330                         valueTotal += vValY.toDouble();
00331                 }
00332             }
00333 
00334             if( data->cellContent( dataset, value, vValY, vValX, cellPropID ) &&
00335                 QVariant::Double == vValY.type() &&
00336                 ( !ai.bCellsHaveSeveralCoordinates || QVariant::Invalid != vValX.type() ) ){
00337                 //qDebug("a. cellPropID: %i",cellPropID);
00338 
00339                 // calculate Ordinate axis value
00340                 // -----------------------------
00341                 double cellValue = vValY.toDouble();
00342                 double drawValue = 0.0;
00343                 // PENDING(kalle) This does not work for AreaPercent yet
00344                 if ( mode == Stacked )
00345                     drawValue = ( cellValue + currentValueSums[ value ] ) * ordinatePixelsPerUnit;
00346                 else if ( mode == Percent )
00347                     drawValue = ( ( cellValue + currentValueSums[ value ] ) / valueTotal ) * 100.0 * ordinatePixelsPerUnit;
00348                 else {
00349                     // LineNormal or AreaNormal
00350                     if( bOrdinateIsLogarithmic ){
00351                         if( 0.0 < cellValue )
00352                             drawValue = log10( cellValue ) * ordinatePixelsPerUnit;
00353                         else
00354                             drawValue = -10250.0;
00355                         //qDebug("\nlogarithmic calc  -  cellValue: %f   drawValue: %f",
00356                         //        cellValue, drawValue );
00357                     }else{
00358                         drawValue = cellValue * ordinatePixelsPerUnit * (bOrdinateDecreasing ? -1.0 : 1.0);
00359                         //qDebug("\nlinear calc  -  cellValue: %f\n             -  drawValue: %f",
00360                         //        cellValue, drawValue );
00361                     }
00362                 }
00363 
00364 
00365                 // calculate Abscissa axis value
00366                 // -----------------------------
00367                 double xValue;
00368                 bool skipMe = !calculateAbscissaAxisValue( vValX, ai, value,
00369                                                            xValue );
00370 
00371 
00372                 // calculate and store the point and region / draw the marker
00373                 // ----------------------------------------------------------
00374                 if( !skipMe ){
00375                     // prevent the point from being toooo far
00376                     // below the bottom (or above the top, resp.)
00377                     // of the cliprect
00378                     double pY = QMIN( zeroXAxisI - drawValue,
00379                                       (logHeight + axisYOffset) * 3 );
00380                     pY = QMAX( pY, -(logHeight + axisYOffset) * 3 );
00381                     // specify the Point
00382                     int myPointX = static_cast < int > ( xValue ) + xShift;
00383                     int myPointY = static_cast < int > ( pY );
00384 
00385                     if( cellPropID == curPropSetId &&
00386                         myPointX == prevPointX &&
00387                         myPointY == prevPointY ){
00388                         allPoints[   static_cast < int > ( datasetEnd-dataset )
00389                                      * arrayNumValues + value ].setSkipThis( true );
00390                         skipMe = true;
00391                         //qDebug("skipped");
00392                     }else{
00393                         // use typecast to make it compile on windows using qt232
00394                         allPoints[   static_cast < int > ( datasetEnd-dataset )
00395                                      * arrayNumValues + value ].set( myPointX, myPointY, cellValue );
00396                         //qDebug("ok");
00397                     }
00398                     if( !skipMe ){
00399                         // --------------------------------------------------------
00400                         // determine any 'extra' properties assigned to this cell
00401                         // by traversing the property set chain (if necessary)
00402                         // --------------------------------------------------------
00403                         if( cellPropID != curPropSetId ){
00404                             //qDebug("b. ( curPropSetId: %i )",curPropSetId);
00405                             //qDebug("b. cellPropID: %i",cellPropID);
00406                             //qDebug(curPropSet.name().latin1());
00407                             if( cellPropID != KDChartPropertySet::UndefinedID &&
00408                                 params()->calculateProperties( cellPropID,
00409                                                                curPropSet ) ){
00410                                 curPropSetId = cellPropID;
00411                                 //qDebug("c. curPropSetId: %i",curPropSetId);
00412                                 //qDebug(curPropSet.name().latin1());
00413                             }else{
00414                                 curPropSetId = KDChartPropertySet::UndefinedID;
00415                             }
00416                         }
00417                         // make sure any extra horiz. and/or vert. lines and/or markers
00418                         // are drawn *before* the data lines and/or markers are painted
00419                         if( mChartType == KDChartParams::Line ){
00420                             if( curPropSetId != KDChartPropertySet::UndefinedID ){
00421                                 drawExtraLinesAndMarkers(
00422                                                          curPropSet,
00423                                                          default2DPen,
00424                                                          defaultMarkerStyle,
00425                                                          myPointX, myPointY,
00426                                                          painter,
00427                                                          ai.abscissaPara,
00428                                                          ordinatePara,
00429                                                          logWidth/1000.0,
00430                                                          logHeight/1000.0,
00431                                                          false );
00432                             }
00433                         }
00434                         prevPointX = myPointX;
00435                         prevPointY = myPointY;
00436                     }
00437                 }
00438                 // calculate running sum for stacked and percent
00439                 if ( mode == Stacked || mode == Percent ) {
00440                     if( cellValue == KDCHART_POS_INFINITE )
00441                         currentValueSums[ value ] = KDCHART_POS_INFINITE;
00442                     else if( currentValueSums[ value ] != KDCHART_POS_INFINITE )
00443                         currentValueSums[ value ] += cellValue;
00444                 }
00445             }
00446         }
00447     }
00448 
00449 
00450 
00451     QPointArray previousPoints; // no vector since only areas need it,
00452     // and these do not support 3d yet
00453 
00454     // Store some (dataset-independend) default values
00455     // to be used unless other properties
00456     // have been specified for the respective data cell:
00457     //
00458     const bool defaultDrawMarkers = mDrawMarkers;
00459 
00460     for ( dataset = datasetEnd; ( dataset >= (int)datasetStart && dataset >= 0 ); --dataset ) {
00461 
00462         // Store some (dataset-dependend) default values
00463         // to be used unless other properties
00464         // have been specified for the respective data cell:
00465         //
00466         const QPen default2DPen(   params()->lineColor().isValid()
00467                                    ? params()->lineColor()
00468                                    : params()->dataColor( dataset ),
00469                                    params()->lineWidth(),
00470                                    params()->lineStyle( dataset ) );
00471         bool currentDrawMarkers = defaultDrawMarkers;
00472         const KDChartParams::LineMarkerStyle markerStyle = params()->lineMarkerStyle( dataset );
00473 
00474         // the +2 is for the areas (if any)
00475         QPtrVector< QPointArray > points( 2 );
00476         points.setAutoDelete( true );
00477         /* Pending Michel - we need to keep track of the 
00478          * non rotated points for 3D lines
00479          */
00480         QPtrVector< QPointArray > oripoints( 2 );
00481         oripoints.setAutoDelete( true );
00482         
00483         int i = 0;
00484         for( i = 0; i < 2; ++i ) {
00485             points.insert( i, new QPointArray( ai.numValues + 2 ) );
00486             oripoints.insert( i, new QPointArray( ai.numValues + 2 ) );
00487         }
00488 
00489         if( ai.bAbscissaHasTrueAxisDtValues )
00490             ai.numValues = data->cols();
00491 
00492         int point = 0;
00493 
00494         for ( int value = 0; value < ai.numValues; ++value ) {
00495 
00496             // determine and store marker properties assigned to this cell
00497             // -----------------------------------------------------------
00498             currentDrawMarkers = defaultDrawMarkers;
00499             int cellPropID;
00500             if( data->cellProp( dataset, value, cellPropID ) &&
00501                 cellPropID != curPropSetId ){
00502                 if( cellPropID != KDChartPropertySet::UndefinedID &&
00503                     params()->calculateProperties( cellPropID,
00504                                                    curPropSet ) )
00505                     curPropSetId = cellPropID;
00506                 else
00507                     curPropSetId = KDChartPropertySet::UndefinedID;
00508             }
00509             if( curPropSetId != KDChartPropertySet::UndefinedID ){
00510                 // we can safely call the following functions and ignore their
00511                 // return values since they will touch the parameters' values
00512                 // if the propSet *contains* corresponding own values only.
00513                 int iDummy;
00514                 curPropSet.hasOwnShowMarker( iDummy, currentDrawMarkers );
00515             }
00516 
00517 
00518             int iVec = static_cast < int > ( datasetEnd-dataset ) * arrayNumValues + value;
00519             if( allPoints[ iVec ].bValid && !allPoints[ iVec ].bSkipThis ){
00520                 const MyPoint& mp = allPoints[iVec];
00521 
00522                 
00523                 //qDebug("\np.x() %i        p.y() %i", p.x(), p.y() );
00524                 // For 3D lines, we need two points (that lie
00525                 // behind each other on the Z axis). For 2D lines and
00526                 // areas, we need only one point.
00527                 if( showThreeDLines ) {
00528                     points[0]->setPoint( point, project( mp.p.x(), mp.p.y(),
00529                                                          (datasetStart+dataset)*params()->threeDLineDepth() ) );
00530                     points[1]->setPoint( point, project( mp.p.x(), mp.p.y(),
00531                                                          (datasetStart+dataset + 1)*params()->threeDLineDepth() ) );
00532                     oripoints[0]->setPoint( point,  mp.p.x(), mp.p.y() );
00533                     oripoints[1]->setPoint( point,  mp.p.x() -  (datasetStart+dataset + 1)*params()->threeDLineDepth(), 
00534                                             mp.p.y() -  (datasetStart+dataset + 1)*params()->threeDLineDepth() );
00535          
00536                 } else
00537                     // 2D lines or areas
00538                     points[0]->setPoint( point, mp.p );
00539                 ++point;
00540 
00541                 int x = mp.p.x();
00542                 int y = QMAX(QMIN(mp.p.y(),
00543                                   static_cast < int > (logHeight +axisYOffset)),
00544                              0);
00545                 bool markerIsOutside = y != mp.p.y();
00546                 // draw the marker and store the region
00547                 if ( currentDrawMarkers ){
00548                     uint   theAlignment = Qt::AlignCenter;
00549                     bool   hasOwnSize = false;
00550                     int    theWidth  = 0;
00551                     int    theHeight = 0;
00552                     QColor theColor(params()->dataColor( dataset ));
00553                     int    theStyle = markerStyle;
00554                     if( curPropSetId != KDChartPropertySet::UndefinedID ){
00555                         // we can safely call the following functions and ignore their
00556                         // return values since they will touch the parameters' values
00557                         // if the propSet *contains* corresponding own values only.
00558                         int iDummy;
00559                         curPropSet.hasOwnMarkerAlign( iDummy, theAlignment );
00560                         curPropSet.hasOwnMarkerColor( iDummy, theColor );
00561                         curPropSet.hasOwnMarkerStyle( iDummy, theStyle );
00562                         QSize size(theWidth, theHeight);
00563                         hasOwnSize = curPropSet.hasOwnMarkerSize(iDummy, size);
00564                         if( hasOwnSize ){
00565                             theWidth  = size.width();
00566                             theHeight = size.height();
00567                         }
00568                     }
00569 
00570                     drawMarker( painter,
00571                                 params(),
00572                                 _areaWidthP1000, _areaHeightP1000,
00573                                 _dataRect.x(),
00574                                 _dataRect.y(),
00575                                 markerIsOutside
00576                                 ? KDChartParams::LineMarker1Pixel
00577                                 : theStyle,
00578                                 theColor,
00579                                 QPoint(x,y),
00580                                 dataset, value, chart, regions,
00581                                 hasOwnSize ? &theWidth  : 0,
00582                                 hasOwnSize ? &theHeight : 0,
00583                                 theAlignment );
00584 
00585                 }
00586                 // store the region
00587                 else if( regions ) {
00588                     QRect rect( QPoint( x-1, y-1 ), QPoint( x+1, y+1 ) );
00589                     rect.moveBy( _dataRect.x(), _dataRect.y() );
00590                     regions->append(
00591                                     new KDChartDataRegion(dataset, value, chart, rect) );
00592                 }
00593 
00594             }
00595         }
00596         if ( point ) {
00597             bool bDrawLines = (0 != params()->lineWidth());
00598           
00599             if ( mIsArea ) {
00600                 // first draw with the fill brush, no pen, with the
00601                 // zero axis points or upper border points added for the first
00602                 // dataset or with the previous points reversed for all other
00603                 // datasets.
00604                 painter->setPen( QPen( Qt::NoPen ) );
00605                 const QBrush datasetBrush( params()->dataColor( dataset ), Qt::SolidPattern );
00606                 painter->setBrush( datasetBrush );
00607                 QBrush currentBrush( datasetBrush );
00608 
00609                 if ( mode == Normal || dataset == (int)datasetEnd ) {
00612 
00613                     // no 3d handling for areas yet
00614                     QPoint lastPoint = points[0]->point( point - 1 );
00615 
00616                     // zeroXAxisI can be too far below the abscissa, but it's
00617                     // the only thing we have. Likewise can 0 be too far above
00618                     // the upper boundary, but again it's the only thing we
00619                     // have, at the rest is clipped anyway.
00620                     int yCoord;
00621                     if ( params()->areaLocation() == KDChartParams::AreaBelow ||
00622                          mode == Percent )
00623                         yCoord = static_cast<int>(zeroXAxisI);
00624                     else
00625                         yCoord = static_cast<int>(axisYOffset);
00626 
00627                     // old: draw the complete area in on go:
00628                     /*
00629                     // no 3d handling for areas yet
00630                     points[0]->setPoint( point, lastPoint.x(), yCoord );
00631                     point++;
00632 
00633                     QPoint firstPoint = points[0]->point( 0 );
00634                     points[0]->setPoint( point, firstPoint.x(), yCoord );
00635                     point++;
00636 
00637                     painter->drawPolygon( *points[0], false, 0, point );
00638                     */
00639 
00640                     // new: draw individual area segments:
00641                     curPropSetId = KDChartPropertySet::UndefinedID;
00642                     for( int value = 0; value < point-1; ++value ) {
00643 
00644                         int cellPropID;
00645                         if( data->cellProp( dataset, value, cellPropID ) &&
00646                             cellPropID != curPropSetId ){
00647 
00648                             if( cellPropID != KDChartPropertySet::UndefinedID &&
00649                                 params()->calculateProperties( cellPropID,
00650                                                                curPropSet ) ){
00651                                 curPropSetId = cellPropID;
00652                             }else{
00653                                 curPropSetId = KDChartPropertySet::UndefinedID;
00654                             }
00655                             // preset with default value
00656                             QBrush theAreaBrush = datasetBrush;
00657 
00658                             if( curPropSetId != KDChartPropertySet::UndefinedID ){
00659                                 // we can safely call the following functions and ignore their
00660                                 // return values since they will touch the parameters' values
00661                                 // if the propSet *contains* corresponding own values only.
00662                                 int iDummy;
00663                                 curPropSet.hasOwnAreaBrush( iDummy, theAreaBrush );
00664                             }
00665                             painter->setBrush( theAreaBrush );
00666 
00667                         }
00668                         QPointArray segment( 4 );
00669                         segment.setPoint( 0, points[0]->point( value                 ) );
00670                         segment.setPoint( 1, points[0]->point( value+1               ) );
00671                         segment.setPoint( 2, points[0]->point( value+1 ).x(), yCoord );
00672                         segment.setPoint( 3, points[0]->point( value   ).x(), yCoord );                        
00673                         painter->drawPolygon( segment );
00674                     }
00675 
00676                     // old: draw the complete area in on go:
00677                     /*
00678                     // remove the last two points added
00679                     point -= 2;
00680                     */
00681                     //qDebug("\n111");
00682                 } //  if ( mode == Normal || dataset == (int)datasetEnd )
00683                 else {
00684                     // don't mess around with the original array; we'll need
00685                     // that for the next time through.
00686 
00687                     //qDebug("222");
00688                     // no 3d handling for areas yet
00689                     QPointArray thisSection = points[0]->copy();
00690 
00691                     thisSection.resize( point + previousPoints.size() );
00692                     // append the previous array (there is guaranteed to be
00693                     // one because we are at least the second time through
00694                     // here) in reverse order
00695                     for ( unsigned int i = 0; i < previousPoints.size(); ++i ) {
00696                         thisSection.setPoint( point + i,
00697                                               previousPoints.point( previousPoints.size() - i - 1 ) );
00698                         //qDebug("\nx: %i",previousPoints.point( previousPoints.size() - i - 1 ).x());
00699                         //qDebug("y: %i",previousPoints.point( previousPoints.size() - i - 1 ).y());
00700                     }
00701                     painter->drawPolygon( thisSection );
00702                 }
00703                 // draw the line with no brush and outline color
00704                 painter->setBrush( Qt::NoBrush );
00705                 painter->setPen( QPen( params()->outlineDataColor(),
00706                                        params()->outlineDataLineWidth() ) );
00707             } else {
00708                 // line
00709                 if( showThreeDLines ) {
00710                     // This is a 3D line:
00711                     // We draw the line with the data color brush
00712                     //                   and the outline data pen.
00713                     painter->setBrush( params()->dataColor( dataset ) );
00714                     painter->setPen( QPen( params()->outlineDataColor(),
00715                                            params()->outlineDataLineWidth() ) );
00716                 } else {
00717                     // This is a 2D line:
00718                     // We draw the line with the no brush
00719                     // and the data color if no special line color was specified.
00720                     painter->setBrush( Qt::NoBrush );
00721                     painter->setPen( default2DPen );
00722                 }
00723             }
00724 
00725             // Neither draw the contour line if this is a pure Point chart
00726             // nor draw it for the last row of a percent area chart.
00727            
00728             if( bDrawLines &&
00729                 ( (mode != Percent) || !mIsArea || (dataset != (int)datasetEnd) ) ){
00730                 if( showThreeDLines ) {
00731          
00732                     // A 3D line needs to be drawn piece-wise
00733                     for ( int value = 0; value < point-1; ++value ) {
00734                         //          if( data->cell( dataset, value ).hasValue() &&
00735                         //              data->cell( dataset, value+1 ).hasValue() ) {
00736                         //      qDebug( "Draw a segment in dataset %d from %d to %d", dataset, value, value+1 );
00737                 
00738                         //store the rotated points ( see project() )
00739                         QPointArray rotatedSegment( 4 );                        
00740                         rotatedSegment.setPoint( 0, points[0]->point( value ));
00741                         rotatedSegment.setPoint( 1, points[0]->point( value+1 ) );
00742                         rotatedSegment.setPoint( 2, points[1]->point( value+1 ) );
00743                         rotatedSegment.setPoint( 3, points[1]->point( value ) );
00744 
00745                         //store the true points without rotation    
00746                         QPointArray trueSegment( 4 );            
00747                         trueSegment.setPoint( 0, oripoints[0]->point( value ));
00748                         trueSegment.setPoint( 1, oripoints[0]->point( value+1 ) );
00749                         trueSegment.setPoint( 2, oripoints[1]->point( value+1 ) );
00750                         trueSegment.setPoint( 3, oripoints[1]->point( value ) );
00751 
00752                         // calculate the rotated points position relative to each other
00753                         // we will then be able to keep the rotation ( see: project () )
00754                         // by reporting this position relative to the true segment line 
00755                         //left side pt3 and pt0 
00756                         int dx30 = rotatedSegment.point(3).x() - rotatedSegment.point(0).x();
00757                         int dy30 = rotatedSegment.point(3).y() - rotatedSegment.point(0).y(); 
00758                         //right side pt1 and pt2
00759                         int dx12 = rotatedSegment.point(2).x() - rotatedSegment.point(1).x();
00760                         int dy12 = rotatedSegment.point(2).y() - rotatedSegment.point(1).y();
00761 
00762                         // store and paint the "3D" segment
00763                         QPointArray segment( 4 );
00764                         segment.setPoint( 0, trueSegment.point(0) );
00765                         segment.setPoint( 1, trueSegment.point(1) );
00766                         segment.setPoint( 2, trueSegment.point(1).x() + dx12, trueSegment.point(1).y() + dy12 );
00767                         segment.setPoint( 3, trueSegment.point(0).x() + dx30, trueSegment.point(0).y() + dy30);
00768 
00769                
00770                         //PENDING Michel 3dlines drawing a segment with showThreeDLines                       
00771                         painter->drawPolygon( segment );
00772                
00773                                 
00774                         //          } else
00775                         //              qDebug( "Can't draw a segment in dataset %d from %d to %d", dataset, value, value+1 );
00776                     }
00777                 } else {
00778                     QPoint p1, p2;
00779                     // Note: If markers are drawn very near to each other
00780                     //       and tiny markers are used
00781                     //       we don't draw the connecting lines.
00782                     bool b4PMarkers = KDChartParams::LineMarker4Pixels == markerStyle;
00783                     bool bTinyMarkers =
00784                         KDChartParams::LineMarker1Pixel  == markerStyle || b4PMarkers;
00785                     curPropSetId = KDChartPropertySet::UndefinedID;
00786                     painter->setPen( default2DPen );
00787                     for ( int value = 0; value < point-1; ++value ) {
00788                         p1 = points[0]->point( value   );
00789                         p2 = points[0]->point( value+1 );
00790 
00791                         // Determine properties assigned to this cell
00792                         // and change the painter if necessarry:
00793                         currentDrawMarkers = defaultDrawMarkers;
00794                         int cellPropID;
00795                         if( data->cellProp( dataset, value, cellPropID ) &&
00796                             cellPropID != curPropSetId ){
00797                             if( cellPropID != KDChartPropertySet::UndefinedID &&
00798                                 params()->calculateProperties( cellPropID,
00799                                                                curPropSet ) ){
00800                                 curPropSetId = cellPropID;
00801                             }else{
00802                                 curPropSetId = KDChartPropertySet::UndefinedID;
00803                             }
00804                             // preset with default values
00805                             int          theLineWidth = default2DPen.width();
00806                             QColor       theLineColor = default2DPen.color();
00807                             Qt::PenStyle theLineStyle = default2DPen.style();
00808                             if( curPropSetId != KDChartPropertySet::UndefinedID ){
00809                                 // we can safely call the following functions and ignore their
00810                                 // return values since they will touch the parameters' values
00811                                 // if the propSet *contains* corresponding own values only.
00812                                 int iDummy;
00813                                 curPropSet.hasOwnLineWidth ( iDummy, theLineWidth );
00814                                 curPropSet.hasOwnLineColor ( iDummy, theLineColor );
00815                                 curPropSet.hasOwnLineStyle ( iDummy, theLineStyle );
00816                                 curPropSet.hasOwnShowMarker( iDummy, currentDrawMarkers );
00817                             }
00818                             painter->setPen( QPen( theLineColor,
00819                                                    theLineWidth,
00820                                                    theLineStyle ) );
00821                         }
00822 
00823                         if( !currentDrawMarkers ){
00824                             //PENDING Michel: drawing a line - not currentMarkers
00825                             painter->drawLine( p1, p2 );
00826                         }else{
00827                             int dx = p2.x() - p1.x();
00828                             int dy = p2.y() - p1.y();
00829                             if( !bTinyMarkers || (abs(dx) > 4) || (abs(dy) > 4) ){
00830                                 if( bTinyMarkers ) {
00831                                     double m  = !dx ? 100.0
00832                                         : !dy ? 0.01
00833                                         : ((double)dy / (double)dx);
00834                                     double am = fabs(m);
00835                                     int dxx;
00836                                     int dyy;
00837                                     if( 0.25 > am ){
00838                                         dxx = 3;
00839                                         dyy = 0;
00840                                     }else if( 0.67 > am ){
00841                                         dxx = 3;
00842                                         dyy = 1;
00843                                     }else if( 1.33 > am ){
00844                                         dxx = 2;
00845                                         dyy = 2;
00846                                     }else if( 4.0 > am ){
00847                                         dxx = 1;
00848                                         dyy = 3;
00849                                     }else{
00850                                         dxx = 0;
00851                                         dyy = 3;
00852                                     }
00853                                     if( 0 > dx )
00854                                         dxx *= -1;
00855                                     if( 0 > dy )
00856                                         dyy *= -1;
00857                                     if( b4PMarkers ){
00858                                         if( 0 < dx )
00859                                             ++p1.rx();
00860                                         else if( 0 > dx )
00861                                             ++p2.rx();
00862                                         if( 0 < dy )
00863                                             ++p1.ry();
00864                                         else if( 0 > dy )
00865                                             ++p2.ry();
00866                                     }
00867                                     p1.rx() += dxx; p1.ry() += dyy;
00868                                     p2.rx() -= dxx; p2.ry() -= dyy;
00869                                 }
00870                                 //PENDING Michel: drawing a line - currentMarkers
00871                                 painter->drawLine( p1, p2 );
00872                             }
00873                         }
00874                     }
00875                 }
00876             }
00877         }
00878 
00879         // Save point array for next way through (needed for e.g. stacked
00880         // areas), not for 3D currently
00881         points[0]->resize( point );
00882         previousPoints = points[0]->copy();
00883     }
00884 
00885 
00886     // Now draw any extra lines (and/or their markers, resp.) that
00887     // are to be printed IN FRONT of the normal lines:
00888     if( mChartType == KDChartParams::Line ){
00889         for( dataset = datasetEnd; ( dataset >= (int)datasetStart && dataset >= 0 ); --dataset ) {
00890 
00891             const KDChartParams::LineMarkerStyle
00892                 defaultMarkerStyle = params()->lineMarkerStyle( dataset );
00893             const QPen default2DPen(   params()->lineColor().isValid()
00894                                        ? params()->lineColor()
00895                                        : params()->dataColor( dataset ),
00896                                        params()->lineWidth(),
00897                                        params()->lineStyle( dataset ) );
00898 
00899             if( ai.bAbscissaHasTrueAxisDtValues )
00900                 ai.numValues = data->cols();
00901 
00902             for ( int value = 0; value < ai.numValues; ++value ) {
00903                 int iVec = static_cast < int > ( datasetEnd-dataset ) * arrayNumValues + value;
00904                 if( allPoints[ iVec ].bValid ){
00905                     const MyPoint& mp = allPoints[iVec];
00906                     //qDebug("\np.x() %i        p.y() %i", p.x(), p.y() );
00907 
00908                     // --------------------------------------------------------
00909                     // determine any 'extra' properties assigned to this cell
00910                     // by traversing the property set chain (if necessary)
00911                     // --------------------------------------------------------
00912                     int cellPropID;
00913                     if( data->cellProp( dataset, value, cellPropID ) &&
00914                         cellPropID != curPropSetId ){
00915                         if( cellPropID != KDChartPropertySet::UndefinedID &&
00916                             params()->calculateProperties( cellPropID,
00917                                                            curPropSet ) )
00918                             curPropSetId = cellPropID;
00919                         else
00920                             curPropSetId = KDChartPropertySet::UndefinedID;
00921                     }
00922                     if( curPropSetId != KDChartPropertySet::UndefinedID ){
00923                         drawExtraLinesAndMarkers(
00924                                                  curPropSet,
00925                                                  default2DPen,
00926                                                  defaultMarkerStyle,
00927                                                  mp.p.x(), mp.p.y(),
00928                                                  painter,
00929                                                  ai.abscissaPara,
00930                                                  ordinatePara,
00931                                                  logWidth/1000.0,
00932                                                  logHeight/1000.0,
00933                                                  true );
00934                     }
00935                 }
00936             }
00937         }
00938     }
00939     //qDebug(const_cast < KDChartParams* > ( params() )->properties( KDCHART_PROPSET_NORMAL_DATA )->name().latin1());
00940     //qDebug(const_cast < KDChartParams* > ( params() )->properties( KDCHART_PROPSET_TRANSPARENT_DATA )->name().latin1());
00941     //qDebug(const_cast < KDChartParams* > ( params() )->properties( KDCHART_PROPSET_HORI_LINE )->name().latin1());
00942     //qDebug(const_cast < KDChartParams* > ( params() )->properties( KDCHART_PROPSET_VERT_LINE )->name().latin1());
00943     //qDebug("--");
00944     }
KDE Home | KDE Accessibility Home | Description of Access Keys