kchart

KDChartLinesPainter.cpp
1/*
2 KDChart - a multi-platform charting engine
3*/
4
5/****************************************************************************
6 ** Copyright (C) 2001-2003 Klarälvdalens Datakonsult AB. All rights reserved.
7 **
8 ** This file is part of the KDChart library.
9 **
10 ** This file may be distributed and/or modified under the terms of the
11 ** GNU General Public License version 2 as published by the Free Software
12 ** Foundation and appearing in the file LICENSE.GPL included in the
13 ** packaging of this file.
14 **
15 ** Licensees holding valid commercial KDChart licenses may use this file in
16 ** accordance with the KDChart Commercial License Agreement provided with
17 ** the Software.
18 **
19 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 **
22 ** See http://www.klaralvdalens-datakonsult.se/?page=products for
23 ** information about KDChart Commercial License Agreements.
24 **
25 ** Contact info@klaralvdalens-datakonsult.se if any conditions of this
26 ** licensing are not clear to you.
27 **
28 **********************************************************************/
29#include "KDChartLinesPainter.h"
30#include <KDChartParams.h>
31#include <KDChartPropertySet.h>
32
33#include <tqpainter.h>
34#include <tqvaluevector.h>
35
36#include <stdlib.h>
37
51 KDChartAxesPainter( params )
52{
53 // This constructor intentionally left blank so far; we cannot setup the
54 // geometry yet since we do not know the size of the painter.
55}
56
57
62{
63 // intentionally left blank
64}
65
66
77void KDChartLinesPainter::paintData( TQPainter* painter,
79 bool paint2nd,
80 KDChartDataRegionList* regions )
81{
82 paintDataInternal( painter, data,
83 true, // center points
84 params()->lineMarker() && !params()->threeDLines(), // line markers yes/no, 3D lines have no markers
85 false, // not an area
86 paint2nd,
87 regions );
88}
89
110void KDChartLinesPainter::paintDataInternal( TQPainter* painter,
112 bool centerThePoints,
113 bool drawMarkers,
114 bool isArea,
115 bool paint2nd,
116 KDChartDataRegionList* regions )
117{
118 mCenterThePoints = centerThePoints;
119 mDrawMarkers = drawMarkers;
120 mIsArea = isArea;
121 mChartType = paint2nd ? params()->additionalChartType()
122 : params()->chartType();
123
124 KDChartAxesPainter::paintData( painter, data, paint2nd, regions );
125}
126
127
128#define DEGTORAD(d) (d)*M_PI/180
129
135TQPoint KDChartLinesPainter::project( int x, int y, int z )
136{
137
138 double xrad = DEGTORAD( params()->threeDLineXRotation() );
139 double yrad = DEGTORAD( params()->threeDLineYRotation() );
140 TQPoint ret( static_cast<int>( x*cos( yrad ) + z * sin( yrad ) ),
141 static_cast<int>( y*cos( xrad ) - z * sin( xrad ) ) );
142 return ret;
143}
144
145bool KDChartLinesPainter::isNormalMode() const
146{
147 return KDChartParams::LineNormal == params()->lineChartSubType();
148}
149
150int KDChartLinesPainter::clipShiftUp( bool, double ) const
151{
152 return 0;
153}
154
155
156class MyPoint
157{
158public:
159 MyPoint() : bValid( false ), bSkipThis( false ), cellValue( 0.0 ) {}
160 void set( int x, int y, double value ) {
161 bValid = true;
162 p.setX( x );
163 p.setY( y );
164 cellValue = value;
165 }
166 void setSkipThis( bool skipThis ) {
167 bSkipThis = skipThis;
168 }
169 TQPoint p;
170 bool bValid;
171 bool bSkipThis;
172 double cellValue;
173};
174
175
177 const TQRect& /*ourClipRect*/,
179 KDChartDataRegionList* regions,
180 const KDChartAxisParams* ordinatePara,
181 bool /*bNormalMode*/,
182 uint chart,
183 double logWidth,
184 double /*areaWidthP1000*/,
185 double logHeight,
186 double axisYOffset,
187 double minColumnValue,
188 double maxColumnValue,
189 double columnValueDistance,
190 uint /*chartDatasetStart*/,
191 uint /*chartDatasetEnd*/,
192 uint datasetStart,
193 uint datasetEnd )
194{
195 if( !data ) return;
196
197
198 abscissaInfos ai;
199 ai.bCenterThePoints = mCenterThePoints;
200 calculateAbscissaInfos( *params(), *data,
201 datasetStart, datasetEnd,
202 logWidth, _dataRect,
203 ai );
204 mCenterThePoints = ai.bCenterThePoints;
205
206 bool bOrdinateDecreasing = ordinatePara
207 ? ordinatePara->axisValuesDecreasing()
208 : false;
209 bool bOrdinateIsLogarithmic
210 = ordinatePara
211 ? (KDChartAxisParams::AxisCalcLogarithmic == ordinatePara->axisCalcMode())
212 : false;
213
214 //const double ordinatePixelsPerUnit = logHeight / columnValueDistance;
215 const double ordinatePixelsPerUnit
216 = ( ordinatePara
217 && (0.0 != ordinatePara->trueAxisDeltaPixels())
218 && (0.0 != ordinatePara->trueAxisDelta()))
219 ? ordinatePara->trueAxisDeltaPixels() / ordinatePara->trueAxisDelta()
220 : logHeight / columnValueDistance;;
221 //tqDebug("ordinatePixelsPerUnit: %f",ordinatePixelsPerUnit);
222
223
224 const bool showThreeDLines = !mIsArea && params()->threeDLines();
225
226 enum { Normal, Stacked, Percent } mode = Normal;
227 if ( ( ( mChartType == KDChartParams::Line )
228 && ( params()->lineChartSubType() == KDChartParams::LineNormal ) )
229 || ( ( mChartType == KDChartParams::Area )
230 && ( params()->areaChartSubType() == KDChartParams::AreaNormal ) ) )
231 mode = Normal;
232 else if ( ( ( mChartType == KDChartParams::Line )
233 && ( params()->lineChartSubType() == KDChartParams::LineStacked ) )
234 || ( ( mChartType == KDChartParams::Area )
235 && ( params()->areaChartSubType() == KDChartParams::AreaStacked ) ) )
236 mode = Stacked;
237 else if ( ( ( mChartType == KDChartParams::Line )
238 && ( params()->lineChartSubType() == KDChartParams::LinePercent ) )
239 || ( ( mChartType == KDChartParams::Area )
240 && ( params()->areaChartSubType() == KDChartParams::AreaPercent ) ) )
241 mode = Percent;
242 else
243 tqDebug( "Internal error in KDChartLinesPainter::paintDataInternal(): Unknown subtype" );
244
245
246 TQMap < int, double > currentValueSums;
247 if ( mode == Stacked || mode == Percent ) {
248 // this array is only used for stacked and percent lines, no need
249 // to waste time initializing it for normal types
250 for ( int value = 0; value < ai.numValues; ++value )
251 currentValueSums[ value ] = 0.0;
252 }
253 TQMap < int, double > totalValueSums;
254
255 // compute the position of the 0 axis
256 double zeroXAxisI;
257 if ( mode == Percent ) {
258 if ( minColumnValue == 0.0 )
259 zeroXAxisI = logHeight + axisYOffset;
260 else if( maxColumnValue == 0.0 )
261 zeroXAxisI = _dataRect.y() + axisYOffset;
262 else
263 zeroXAxisI = logHeight / 2.0 + _dataRect.y();
264 } else
265 zeroXAxisI = ordinatePara->axisZeroLineStartY() - _dataRect.y();
266
267
268 // compute how to shift of the points in case we want them in the
269 // middle of their respective columns
270 int xShift = mCenterThePoints ? static_cast < int > ( ai.pointDist * 0.5 ) : 0;
271
272
273 // calculate all points' positions
274 // ===============================
275 int arrayNumDatasets = 0;
276 int arrayNumValues = ai.bAbscissaHasTrueAxisDtValues
277 ? data->cols()
278 : ai.numValues;
279 int dataset;
280 for( dataset = datasetEnd;
281 ( dataset >= static_cast < int > ( datasetStart ) && dataset >= 0 );
282 --dataset )
283 ++arrayNumDatasets;
284 TQValueVector<MyPoint> allPoints(
285 arrayNumDatasets * arrayNumValues );
286
287 KDChartPropertySet curPropSet;
288 int curPropSetId = KDChartPropertySet::UndefinedID;
289
290 for( dataset = datasetEnd; ( dataset >= (int)datasetStart && dataset >= 0 ); --dataset ) {
291
292 int prevPointX = -1;
293 int prevPointY = -1;
294
296 defaultMarkerStyle = params()->lineMarkerStyle( dataset );
297 const TQPen default2DPen( params()->lineColor().isValid()
298 ? params()->lineColor()
299 : params()->dataColor( dataset ),
300 params()->lineWidth(),
301 params()->lineStyle( dataset ) );
302
303 if( ai.bAbscissaHasTrueAxisDtValues )
304 ai.numValues = data->cols();
305
306 TQVariant vValY;
307 TQVariant vValX;
308 int cellPropID;
309 for( int value = 0; value < ai.numValues; ++value ) {
310 //if ( mode == Percent )
311 // valueTotal = data->colAbsSum( value );
312 double valueTotal = 0.0; // Will only be used for Percent
313 if( mode == Percent ) {
314 valueTotal = 0.0;
315 // iterate over datasets of this axis only:
316 for ( uint dataset2 = datasetStart;
317 dataset2 <= datasetEnd;
318 ++dataset2 ) {
319 if( data->cellCoord( dataset2, value, vValY, 1 ) &&
320 TQVariant::Double == vValY.type() )
321 valueTotal += vValY.toDouble();
322 }
323 }
324
325 if( data->cellContent( dataset, value, vValY, vValX, cellPropID ) &&
326 TQVariant::Double == vValY.type() &&
327 ( !ai.bCellsHaveSeveralCoordinates || TQVariant::Invalid != vValX.type() ) ){
328 //tqDebug("a. cellPropID: %i",cellPropID);
329
330 // calculate Ordinate axis value
331 // -----------------------------
332 double cellValue = vValY.toDouble();
333 double drawValue = 0.0;
334 // PENDING(kalle) This does not work for AreaPercent yet
335 if ( mode == Stacked )
336 drawValue = ( cellValue + currentValueSums[ value ] ) * ordinatePixelsPerUnit;
337 else if ( mode == Percent )
338 drawValue = ( ( cellValue + currentValueSums[ value ] ) / valueTotal ) * 100.0 * ordinatePixelsPerUnit;
339 else {
340 // LineNormal or AreaNormal
341 if( bOrdinateIsLogarithmic ){
342 if( 0.0 < cellValue )
343 drawValue = log10( cellValue ) * ordinatePixelsPerUnit;
344 else
345 drawValue = -10250.0;
346 //tqDebug("\nlogarithmic calc - cellValue: %f drawValue: %f",
347 // cellValue, drawValue );
348 }else{
349 drawValue = cellValue * ordinatePixelsPerUnit * (bOrdinateDecreasing ? -1.0 : 1.0);
350 //tqDebug("\nlinear calc - cellValue: %f\n - drawValue: %f",
351 // cellValue, drawValue );
352 }
353 }
354
355
356 // calculate Abscissa axis value
357 // -----------------------------
358 double xValue;
359 bool skipMe = !calculateAbscissaAxisValue( vValX, ai, value,
360 xValue );
361
362
363 // calculate and store the point and region / draw the marker
364 // ----------------------------------------------------------
365 if( !skipMe ){
366 // prevent the point from being toooo far
367 // below the bottom (or above the top, resp.)
368 // of the cliprect
369 double pY = TQMIN( zeroXAxisI - drawValue,
370 (logHeight + axisYOffset) * 3 );
371 pY = TQMAX( pY, -(logHeight + axisYOffset) * 3 );
372 // specify the Point
373 int myPointX = static_cast < int > ( xValue ) + xShift;
374 int myPointY = static_cast < int > ( pY );
375
376 if( cellPropID == curPropSetId &&
377 myPointX == prevPointX &&
378 myPointY == prevPointY ){
379 allPoints[ static_cast < int > ( datasetEnd-dataset )
380 * arrayNumValues + value ].setSkipThis( true );
381 skipMe = true;
382 //tqDebug("skipped");
383 }else{
384 // use typecast to make it compile on windows using qt232
385 allPoints[ static_cast < int > ( datasetEnd-dataset )
386 * arrayNumValues + value ].set( myPointX, myPointY, cellValue );
387 //tqDebug("ok");
388 }
389 if( !skipMe ){
390 // --------------------------------------------------------
391 // determine any 'extra' properties assigned to this cell
392 // by traversing the property set chain (if necessary)
393 // --------------------------------------------------------
394 if( cellPropID != curPropSetId ){
395 //tqDebug("b. ( curPropSetId: %i )",curPropSetId);
396 //tqDebug("b. cellPropID: %i",cellPropID);
397 //tqDebug(curPropSet.name().latin1());
398 if( cellPropID != KDChartPropertySet::UndefinedID &&
399 params()->calculateProperties( cellPropID,
400 curPropSet ) ){
401 curPropSetId = cellPropID;
402 //tqDebug("c. curPropSetId: %i",curPropSetId);
403 //tqDebug(curPropSet.name().latin1());
404 }else{
405 curPropSetId = KDChartPropertySet::UndefinedID;
406 }
407 }
408 // make sure any extra horiz. and/or vert. lines and/or markers
409 // are drawn *before* the data lines and/or markers are painted
410 if( mChartType == KDChartParams::Line ){
411 if( curPropSetId != KDChartPropertySet::UndefinedID ){
412 drawExtraLinesAndMarkers(
413 curPropSet,
414 default2DPen,
415 defaultMarkerStyle,
416 myPointX, myPointY,
417 painter,
418 ai.abscissaPara,
419 ordinatePara,
420 logWidth/1000.0,
421 logHeight/1000.0,
422 false );
423 }
424 }
425 prevPointX = myPointX;
426 prevPointY = myPointY;
427 }
428 }
429 // calculate running sum for stacked and percent
430 if ( mode == Stacked || mode == Percent ) {
431 if( cellValue == KDCHART_POS_INFINITE )
432 currentValueSums[ value ] = KDCHART_POS_INFINITE;
433 else if( currentValueSums[ value ] != KDCHART_POS_INFINITE )
434 currentValueSums[ value ] += cellValue;
435 }
436 }
437 }
438 }
439
440
441
442 TQPointArray previousPoints; // no vector since only areas need it,
443 // and these do not support 3d yet
444
445 // Store some (dataset-independend) default values
446 // to be used unless other properties
447 // have been specified for the respective data cell:
448 //
449 const bool defaultDrawMarkers = mDrawMarkers;
450
451 for ( dataset = datasetEnd; ( dataset >= (int)datasetStart && dataset >= 0 ); --dataset ) {
452
453 // Store some (dataset-dependend) default values
454 // to be used unless other properties
455 // have been specified for the respective data cell:
456 //
457 const TQPen default2DPen( params()->lineColor().isValid()
458 ? params()->lineColor()
459 : params()->dataColor( dataset ),
460 params()->lineWidth(),
461 params()->lineStyle( dataset ) );
462 bool currentDrawMarkers = defaultDrawMarkers;
463 const KDChartParams::LineMarkerStyle markerStyle = params()->lineMarkerStyle( dataset );
464
465 // the +2 is for the areas (if any)
466 TQPtrVector< TQPointArray > points( 2 );
467 points.setAutoDelete( true );
468 /* Pending Michel - we need to keep track of the
469 * non rotated points for 3D lines
470 */
471 TQPtrVector< TQPointArray > oripoints( 2 );
472 oripoints.setAutoDelete( true );
473
474 int i = 0;
475 for( i = 0; i < 2; ++i ) {
476 points.insert( i, new TQPointArray( ai.numValues + 2 ) );
477 oripoints.insert( i, new TQPointArray( ai.numValues + 2 ) );
478 }
479
480 if( ai.bAbscissaHasTrueAxisDtValues )
481 ai.numValues = data->cols();
482
483 int point = 0;
484
485 for ( int value = 0; value < ai.numValues; ++value ) {
486
487 // determine and store marker properties assigned to this cell
488 // -----------------------------------------------------------
489 currentDrawMarkers = defaultDrawMarkers;
490 int cellPropID;
491 if( data->cellProp( dataset, value, cellPropID ) &&
492 cellPropID != curPropSetId ){
493 if( cellPropID != KDChartPropertySet::UndefinedID &&
494 params()->calculateProperties( cellPropID,
495 curPropSet ) )
496 curPropSetId = cellPropID;
497 else
498 curPropSetId = KDChartPropertySet::UndefinedID;
499 }
500 if( curPropSetId != KDChartPropertySet::UndefinedID ){
501 // we can safely call the following functions and ignore their
502 // return values since they will touch the parameters' values
503 // if the propSet *contains* corresponding own values only.
504 int iDummy;
505 curPropSet.hasOwnShowMarker( iDummy, currentDrawMarkers );
506 }
507
508
509 int iVec = static_cast < int > ( datasetEnd-dataset ) * arrayNumValues + value;
510 if( allPoints[ iVec ].bValid && !allPoints[ iVec ].bSkipThis ){
511 const MyPoint& mp = allPoints[iVec];
512
513
514 //tqDebug("\np.x() %i p.y() %i", p.x(), p.y() );
515 // For 3D lines, we need two points (that lie
516 // behind each other on the Z axis). For 2D lines and
517 // areas, we need only one point.
518 if( showThreeDLines ) {
519 points[0]->setPoint( point, project( mp.p.x(), mp.p.y(),
520 (datasetStart+dataset)*params()->threeDLineDepth() ) );
521 points[1]->setPoint( point, project( mp.p.x(), mp.p.y(),
522 (datasetStart+dataset + 1)*params()->threeDLineDepth() ) );
523 oripoints[0]->setPoint( point, mp.p.x(), mp.p.y() );
524 oripoints[1]->setPoint( point, mp.p.x() - (datasetStart+dataset + 1)*params()->threeDLineDepth(),
525 mp.p.y() - (datasetStart+dataset + 1)*params()->threeDLineDepth() );
526
527 } else
528 // 2D lines or areas
529 points[0]->setPoint( point, mp.p );
530 ++point;
531
532 int x = mp.p.x();
533 int y = TQMAX(TQMIN(mp.p.y(),
534 static_cast < int > (logHeight +axisYOffset)),
535 0);
536 bool markerIsOutside = y != mp.p.y();
537 // draw the marker and store the region
538 if ( currentDrawMarkers ){
539 uint theAlignment = TQt::AlignCenter;
540 bool hasOwnSize = false;
541 int theWidth = 0;
542 int theHeight = 0;
543 TQColor theColor(params()->dataColor( dataset ));
544 int theStyle = markerStyle;
545 if( curPropSetId != KDChartPropertySet::UndefinedID ){
546 // we can safely call the following functions and ignore their
547 // return values since they will touch the parameters' values
548 // if the propSet *contains* corresponding own values only.
549 int iDummy;
550 curPropSet.hasOwnMarkerAlign( iDummy, theAlignment );
551 curPropSet.hasOwnMarkerColor( iDummy, theColor );
552 curPropSet.hasOwnMarkerStyle( iDummy, theStyle );
553 TQSize size(theWidth, theHeight);
554 hasOwnSize = curPropSet.hasOwnMarkerSize(iDummy, size);
555 if( hasOwnSize ){
556 theWidth = size.width();
557 theHeight = size.height();
558 }
559 }
560
561 drawMarker( painter,
562 params(),
563 _areaWidthP1000, _areaHeightP1000,
564 _dataRect.x(),
565 _dataRect.y(),
566 markerIsOutside
567 ? KDChartParams::LineMarker1Pixel
568 : theStyle,
569 theColor,
570 TQPoint(x,y),
571 dataset, value, chart, regions,
572 hasOwnSize ? &theWidth : 0,
573 hasOwnSize ? &theHeight : 0,
574 theAlignment );
575
576 }
577 // store the region
578 else if( regions ) {
579 TQRect rect( TQPoint( x-1, y-1 ), TQPoint( x+1, y+1 ) );
580 rect.moveBy( _dataRect.x(), _dataRect.y() );
581 regions->append(
582 new KDChartDataRegion(dataset, value, chart, rect) );
583 }
584
585 }
586 }
587 if ( point ) {
588 bool bDrawLines = (0 != params()->lineWidth());
589
590 if ( mIsArea ) {
591 // first draw with the fill brush, no pen, with the
592 // zero axis points or upper border points added for the first
593 // dataset or with the previous points reversed for all other
594 // datasets.
595 painter->setPen( TQPen( TQt::NoPen ) );
596 const TQBrush datasetBrush( params()->dataColor( dataset ), TQt::SolidPattern );
597 painter->setBrush( datasetBrush );
598 TQBrush currentBrush( datasetBrush );
599
600 if ( mode == Normal || dataset == (int)datasetEnd ) {
603
604 // no 3d handling for areas yet
605 TQPoint lastPoint = points[0]->point( point - 1 );
606
607 // zeroXAxisI can be too far below the abscissa, but it's
608 // the only thing we have. Likewise can 0 be too far above
609 // the upper boundary, but again it's the only thing we
610 // have, at the rest is clipped anyway.
611 int yCoord;
612 if ( params()->areaLocation() == KDChartParams::AreaBelow ||
613 mode == Percent )
614 yCoord = static_cast<int>(zeroXAxisI);
615 else
616 yCoord = static_cast<int>(axisYOffset);
617
618 // old: draw the complete area in on go:
619 /*
620 // no 3d handling for areas yet
621 points[0]->setPoint( point, lastPoint.x(), yCoord );
622 point++;
623
624 TQPoint firstPoint = points[0]->point( 0 );
625 points[0]->setPoint( point, firstPoint.x(), yCoord );
626 point++;
627
628 painter->drawPolygon( *points[0], false, 0, point );
629 */
630
631 // new: draw individual area segments:
632 curPropSetId = KDChartPropertySet::UndefinedID;
633 for( int value = 0; value < point-1; ++value ) {
634
635 int cellPropID;
636 if( data->cellProp( dataset, value, cellPropID ) &&
637 cellPropID != curPropSetId ){
638
639 if( cellPropID != KDChartPropertySet::UndefinedID &&
640 params()->calculateProperties( cellPropID,
641 curPropSet ) ){
642 curPropSetId = cellPropID;
643 }else{
644 curPropSetId = KDChartPropertySet::UndefinedID;
645 }
646 // preset with default value
647 TQBrush theAreaBrush = datasetBrush;
648
649 if( curPropSetId != KDChartPropertySet::UndefinedID ){
650 // we can safely call the following functions and ignore their
651 // return values since they will touch the parameters' values
652 // if the propSet *contains* corresponding own values only.
653 int iDummy;
654 curPropSet.hasOwnAreaBrush( iDummy, theAreaBrush );
655 }
656 painter->setBrush( theAreaBrush );
657
658 }
659 TQPointArray segment( 4 );
660 segment.setPoint( 0, points[0]->point( value ) );
661 segment.setPoint( 1, points[0]->point( value+1 ) );
662 segment.setPoint( 2, points[0]->point( value+1 ).x(), yCoord );
663 segment.setPoint( 3, points[0]->point( value ).x(), yCoord );
664 painter->drawPolygon( segment );
665 }
666
667 // old: draw the complete area in on go:
668 /*
669 // remove the last two points added
670 point -= 2;
671 */
672 //tqDebug("\n111");
673 } // if ( mode == Normal || dataset == (int)datasetEnd )
674 else {
675 // don't mess around with the original array; we'll need
676 // that for the next time through.
677
678 //tqDebug("222");
679 // no 3d handling for areas yet
680 TQPointArray thisSection = points[0]->copy();
681
682 thisSection.resize( point + previousPoints.size() );
683 // append the previous array (there is guaranteed to be
684 // one because we are at least the second time through
685 // here) in reverse order
686 for ( unsigned int i = 0; i < previousPoints.size(); ++i ) {
687 thisSection.setPoint( point + i,
688 previousPoints.point( previousPoints.size() - i - 1 ) );
689 //tqDebug("\nx: %i",previousPoints.point( previousPoints.size() - i - 1 ).x());
690 //tqDebug("y: %i",previousPoints.point( previousPoints.size() - i - 1 ).y());
691 }
692 painter->drawPolygon( thisSection );
693 }
694 // draw the line with no brush and outline color
695 painter->setBrush( TQt::NoBrush );
696 painter->setPen( TQPen( params()->outlineDataColor(),
697 params()->outlineDataLineWidth() ) );
698 } else {
699 // line
700 if( showThreeDLines ) {
701 // This is a 3D line:
702 // We draw the line with the data color brush
703 // and the outline data pen.
704 painter->setBrush( params()->dataColor( dataset ) );
705 painter->setPen( TQPen( params()->outlineDataColor(),
706 params()->outlineDataLineWidth() ) );
707 } else {
708 // This is a 2D line:
709 // We draw the line with the no brush
710 // and the data color if no special line color was specified.
711 painter->setBrush( TQt::NoBrush );
712 painter->setPen( default2DPen );
713 }
714 }
715
716 // Neither draw the contour line if this is a pure Point chart
717 // nor draw it for the last row of a percent area chart.
718
719 if( bDrawLines &&
720 ( (mode != Percent) || !mIsArea || (dataset != (int)datasetEnd) ) ){
721 if( showThreeDLines ) {
722
723 // A 3D line needs to be drawn piece-wise
724 for ( int value = 0; value < point-1; ++value ) {
725 // if( data->cell( dataset, value ).hasValue() &&
726 // data->cell( dataset, value+1 ).hasValue() ) {
727 // tqDebug( "Draw a segment in dataset %d from %d to %d", dataset, value, value+1 );
728
729 //store the rotated points ( see project() )
730 TQPointArray rotatedSegment( 4 );
731 rotatedSegment.setPoint( 0, points[0]->point( value ));
732 rotatedSegment.setPoint( 1, points[0]->point( value+1 ) );
733 rotatedSegment.setPoint( 2, points[1]->point( value+1 ) );
734 rotatedSegment.setPoint( 3, points[1]->point( value ) );
735
736 //store the true points without rotation
737 TQPointArray trueSegment( 4 );
738 trueSegment.setPoint( 0, oripoints[0]->point( value ));
739 trueSegment.setPoint( 1, oripoints[0]->point( value+1 ) );
740 trueSegment.setPoint( 2, oripoints[1]->point( value+1 ) );
741 trueSegment.setPoint( 3, oripoints[1]->point( value ) );
742
743 // calculate the rotated points position relative to each other
744 // we will then be able to keep the rotation ( see: project () )
745 // by reporting this position relative to the true segment line
746 //left side pt3 and pt0
747 int dx30 = rotatedSegment.point(3).x() - rotatedSegment.point(0).x();
748 int dy30 = rotatedSegment.point(3).y() - rotatedSegment.point(0).y();
749 //right side pt1 and pt2
750 int dx12 = rotatedSegment.point(2).x() - rotatedSegment.point(1).x();
751 int dy12 = rotatedSegment.point(2).y() - rotatedSegment.point(1).y();
752
753 // store and paint the "3D" segment
754 TQPointArray segment( 4 );
755 segment.setPoint( 0, trueSegment.point(0) );
756 segment.setPoint( 1, trueSegment.point(1) );
757 segment.setPoint( 2, trueSegment.point(1).x() + dx12, trueSegment.point(1).y() + dy12 );
758 segment.setPoint( 3, trueSegment.point(0).x() + dx30, trueSegment.point(0).y() + dy30);
759
760
761 //PENDING Michel 3dlines drawing a segment with showThreeDLines
762 painter->drawPolygon( segment );
763
764
765 // } else
766 // tqDebug( "Can't draw a segment in dataset %d from %d to %d", dataset, value, value+1 );
767 }
768 } else {
769 TQPoint p1, p2;
770 // Note: If markers are drawn very near to each other
771 // and tiny markers are used
772 // we don't draw the connecting lines.
773 bool b4PMarkers = KDChartParams::LineMarker4Pixels == markerStyle;
774 bool bTinyMarkers =
775 KDChartParams::LineMarker1Pixel == markerStyle || b4PMarkers;
776 curPropSetId = KDChartPropertySet::UndefinedID;
777 painter->setPen( default2DPen );
778 for ( int value = 0; value < point-1; ++value ) {
779 p1 = points[0]->point( value );
780 p2 = points[0]->point( value+1 );
781
782 // Determine properties assigned to this cell
783 // and change the painter if necessarry:
784 currentDrawMarkers = defaultDrawMarkers;
785 int cellPropID;
786 if( data->cellProp( dataset, value, cellPropID ) &&
787 cellPropID != curPropSetId ){
788 if( cellPropID != KDChartPropertySet::UndefinedID &&
789 params()->calculateProperties( cellPropID,
790 curPropSet ) ){
791 curPropSetId = cellPropID;
792 }else{
793 curPropSetId = KDChartPropertySet::UndefinedID;
794 }
795 // preset with default values
796 int theLineWidth = default2DPen.width();
797 TQColor theLineColor = default2DPen.color();
798 TQt::PenStyle theLineStyle = default2DPen.style();
799 if( curPropSetId != KDChartPropertySet::UndefinedID ){
800 // we can safely call the following functions and ignore their
801 // return values since they will touch the parameters' values
802 // if the propSet *contains* corresponding own values only.
803 int iDummy;
804 curPropSet.hasOwnLineWidth ( iDummy, theLineWidth );
805 curPropSet.hasOwnLineColor ( iDummy, theLineColor );
806 curPropSet.hasOwnLineStyle ( iDummy, theLineStyle );
807 curPropSet.hasOwnShowMarker( iDummy, currentDrawMarkers );
808 }
809 painter->setPen( TQPen( theLineColor,
810 theLineWidth,
811 theLineStyle ) );
812 }
813
814 if( !currentDrawMarkers ){
815 //PENDING Michel: drawing a line - not currentMarkers
816 painter->drawLine( p1, p2 );
817 }else{
818 int dx = p2.x() - p1.x();
819 int dy = p2.y() - p1.y();
820 if( !bTinyMarkers || (abs(dx) > 4) || (abs(dy) > 4) ){
821 if( bTinyMarkers ) {
822 double m = !dx ? 100.0
823 : !dy ? 0.01
824 : ((double)dy / (double)dx);
825 double am = fabs(m);
826 int dxx;
827 int dyy;
828 if( 0.25 > am ){
829 dxx = 3;
830 dyy = 0;
831 }else if( 0.67 > am ){
832 dxx = 3;
833 dyy = 1;
834 }else if( 1.33 > am ){
835 dxx = 2;
836 dyy = 2;
837 }else if( 4.0 > am ){
838 dxx = 1;
839 dyy = 3;
840 }else{
841 dxx = 0;
842 dyy = 3;
843 }
844 if( 0 > dx )
845 dxx *= -1;
846 if( 0 > dy )
847 dyy *= -1;
848 if( b4PMarkers ){
849 if( 0 < dx )
850 ++p1.rx();
851 else if( 0 > dx )
852 ++p2.rx();
853 if( 0 < dy )
854 ++p1.ry();
855 else if( 0 > dy )
856 ++p2.ry();
857 }
858 p1.rx() += dxx; p1.ry() += dyy;
859 p2.rx() -= dxx; p2.ry() -= dyy;
860 }
861 //PENDING Michel: drawing a line - currentMarkers
862 painter->drawLine( p1, p2 );
863 }
864 }
865 }
866 }
867 }
868 }
869
870 // Save point array for next way through (needed for e.g. stacked
871 // areas), not for 3D currently
872 points[0]->resize( point );
873 previousPoints = points[0]->copy();
874 }
875
876
877 // Now draw any extra lines (and/or their markers, resp.) that
878 // are to be printed IN FRONT of the normal lines:
879 if( mChartType == KDChartParams::Line ){
880 for( dataset = datasetEnd; ( dataset >= (int)datasetStart && dataset >= 0 ); --dataset ) {
881
883 defaultMarkerStyle = params()->lineMarkerStyle( dataset );
884 const TQPen default2DPen( params()->lineColor().isValid()
885 ? params()->lineColor()
886 : params()->dataColor( dataset ),
887 params()->lineWidth(),
888 params()->lineStyle( dataset ) );
889
890 if( ai.bAbscissaHasTrueAxisDtValues )
891 ai.numValues = data->cols();
892
893 for ( int value = 0; value < ai.numValues; ++value ) {
894 int iVec = static_cast < int > ( datasetEnd-dataset ) * arrayNumValues + value;
895 if( allPoints[ iVec ].bValid ){
896 const MyPoint& mp = allPoints[iVec];
897 //tqDebug("\np.x() %i p.y() %i", p.x(), p.y() );
898
899 // --------------------------------------------------------
900 // determine any 'extra' properties assigned to this cell
901 // by traversing the property set chain (if necessary)
902 // --------------------------------------------------------
903 int cellPropID;
904 if( data->cellProp( dataset, value, cellPropID ) &&
905 cellPropID != curPropSetId ){
906 if( cellPropID != KDChartPropertySet::UndefinedID &&
907 params()->calculateProperties( cellPropID,
908 curPropSet ) )
909 curPropSetId = cellPropID;
910 else
911 curPropSetId = KDChartPropertySet::UndefinedID;
912 }
913 if( curPropSetId != KDChartPropertySet::UndefinedID ){
914 drawExtraLinesAndMarkers(
915 curPropSet,
916 default2DPen,
917 defaultMarkerStyle,
918 mp.p.x(), mp.p.y(),
919 painter,
920 ai.abscissaPara,
921 ordinatePara,
922 logWidth/1000.0,
923 logHeight/1000.0,
924 true );
925 }
926 }
927 }
928 }
929 }
930 //tqDebug(const_cast < KDChartParams* > ( params() )->properties( KDCHART_PROPSET_NORMAL_DATA )->name().latin1());
931 //tqDebug(const_cast < KDChartParams* > ( params() )->properties( KDCHART_PROPSET_TRANSPARENT_DATA )->name().latin1());
932 //tqDebug(const_cast < KDChartParams* > ( params() )->properties( KDCHART_PROPSET_HORI_LINE )->name().latin1());
933 //tqDebug(const_cast < KDChartParams* > ( params() )->properties( KDCHART_PROPSET_VERT_LINE )->name().latin1());
934 //tqDebug("--");
935 }
Header for all common chart parameters.
Property settings of a single KDChart data cell.
#define KDCHART_POS_INFINITE
Use special value KDCHART_POS_INFINITE to indicate positive infinite values.
A common base class for classes that implement chart painters for chart types ith axes.
virtual void paintData(TQPainter *painter, KDChartTableDataBase *data, bool paint2nd, KDChartDataRegionList *regions)
Paints the actual data area and registers the region for the data points if regions is not 0.
access the chart axis parameters.
bool axisValuesDecreasing() const
Returns whether axis values should be printed in reverted order: starting with the highest label and ...
double trueAxisDeltaPixels() const
Returns the true delimiter delta pixel value of the axis labels as is was calculated and set by setTr...
double axisZeroLineStartY() const
Returns the not-rounded y-position where drawing of this axis zero line started.
AxisCalcMode axisCalcMode() const
Returns the axis calculation mode configured in this params object.
double trueAxisDelta() const
Returns the true delta value of the ordinate axis labels as is was calculated and set by setTrueAxisL...
The collection class used by KD Chart to store data region information.
virtual ~KDChartLinesPainter()
Destructor.
KDChartLinesPainter(KDChartParams *params)
Constructor.
TQPoint project(int x, int y, int z)
virtual void paintData(TQPainter *painter, KDChartTableDataBase *data, bool paint2nd, KDChartDataRegionList *regions=0)
Paints the actual data area.
virtual void specificPaintData(TQPainter *painter, const TQRect &ourClipRect, KDChartTableDataBase *data, KDChartDataRegionList *regions, const KDChartAxisParams *axisPara, bool bNormalMode, uint chart, double logWidth, double areaWidthP1000, double logHeight, double axisYOffset, double minColumnValue, double maxColumnValue, double columnValueDistance, uint chartDatasetStart, uint chartDatasetEnd, uint datasetStart, uint datasetEnd)
static void drawMarker(TQPainter *painter, int style, const TQColor &color, const TQPoint &p, const TQSize &size, uint align=TQt::AlignCenter)
Draws the marker for one data point according to the specified style, color, size.
Bundles the display parameters of a chart.
TQColor dataColor(uint dataset) const
Returns the color for a dataset.
ChartType chartType() const
Returns the chart type configured in this params object.
TQt::PenStyle lineStyle(uint dataset=KDCHART_GLOBAL_LINE_STYLE) const
Returns the line style of one of the lines in a line chart or the global line style if no style was s...
int threeDLineDepth() const
Returns the depth of 3D lines (the "width" in Z direction).
LineMarkerStyle lineMarkerStyle(uint dataset) const
Returns the marker to be used for a dataset.
LineMarkerStyle
The available line marker styles.
bool calculateProperties(int startId, KDChartPropertySet &rSet) const
Retrieves the values that correspond to a property set by reading this set's properties and obtaining...
LineChartSubType lineChartSubType() const
Returns the line chart subtype.
int lineWidth() const
Returns the line width of the lines in line charts.
ChartType additionalChartType() const
Returns the additional chart type configured in this params object.
bool threeDLines() const
Returns whether lines are drawn three-dimensionally or not.
Property settings of a single KDChart data cell.
bool hasOwnLineWidth(int &idLineWidth, int &lineWidth)
Returns whether this property set is specifying it's own line width settings.
bool hasOwnLineStyle(int &idLineStyle, TQt::PenStyle &lineStyle)
Returns whether this property set is specifying it's own line style settings.
bool hasOwnShowMarker(int &idShowMarker, bool &showMarker)
Returns whether this property set is specifying it's own flag indicating whether a Marker is to be di...
bool hasOwnAreaBrush(int &idAreaBrush, TQBrush &areaBrush)
Returns whether this property set is specifying it's own area brush settings.
bool hasOwnLineColor(int &idLineColor, TQColor &lineColor)
Returns whether this property set is specifying it's own line color settings.
KD Chart's build-in table data for an easy way of storing data values.
virtual bool cellContent(uint _row, uint _col, TQVariant &_value1, TQVariant &_value2, int &_prop) const
virtual bool cellCoord(uint _row, uint _col, TQVariant &_value, int coordinate=1) const =0
Returns one of the coordinate data value(s) stored in a cell.
virtual uint cols() const =0
Returns the number of cols in the table.
virtual bool cellProp(uint _row, uint _col, int &_prop) const =0
Returns the property set ID stored in a cell.