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