kchart

KDChartPolarPainter.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 "KDChartPolarPainter.h"
30#include <KDChartParams.h>
31#include <KDChartAxisParams.h>
32#include "KDChartAxesPainter.h"
33#include "KDDrawText.h"
34
35#include <tqpainter.h>
36
50 KDChartPainter( params )
51{
52 // This constructor intentionally left blank so far; we cannot setup the
53 // geometry yet since we do not know the size of the painter.
54}
55
56
61{
62 // intentionally left blank
63}
64
65
77void KDChartPolarPainter::paintData( TQPainter* painter,
79 bool paint2nd,
80 KDChartDataRegionList* regions )
81{
82 uint chart = paint2nd ? 1 : 0;
83
84 TQRect ourClipRect( _dataRect );
85 ourClipRect.setBottom( ourClipRect.bottom() - 1 ); // protect axes
86 ourClipRect.setLeft( ourClipRect.left() + 1 );
87 ourClipRect.setRight( ourClipRect.right() - 1 );
88 //
89 // PENDING(khz) adjust the clip rect if neccessary...
90 //
91
92 const TQWMatrix & world = painter->worldMatrix();
93 ourClipRect = world.mapRect( ourClipRect );
94 painter->setClipRect( ourClipRect );
95
96
97 uint datasetStart, datasetEnd;
98 findChartDatasets( data, paint2nd, chart, datasetStart, datasetEnd );
99
100
101 painter->translate( _dataRect.x(), _dataRect.y() );
102
103
104 // Number of values: If -1, use all values, otherwise use the
105 // specified number of values.
106 int numValues = 0;
107 if ( params()->numValues() != -1 )
108 numValues = params()->numValues();
109 else
110 numValues = data->usedCols();
111
112 // compute position
113 int size = TQMIN( _dataRect.width(), _dataRect.height() ); // initial size
114
115 const double minSizeP1000 = size / 1000.0;
116
117 int x = ( _dataRect.width() == size ) ? 0 : ( ( _dataRect.width() - size ) / 2 );
118 int y = ( _dataRect.height() == size ) ? 0 : ( ( _dataRect.height() - size ) / 2 );
119 TQRect position( x, y, size, size );
120
121 TQPoint center( position.width() / 2 + position.x(),
122 position.height() / 2 + position.y() );
123
124
125 double maxValue;
126 switch ( params()->polarChartSubType() ) {
127 case KDChartParams::PolarNormal:
128 maxValue = data->maxValue();
129 break;
130 case KDChartParams::PolarPercent:
131 maxValue = 100.0;
132 break;
133 default:
134 maxValue = TQMAX( data->maxColSum(), 0.0 );
135 }
136
137 double pixelsPerUnit = 0.0;
138 // the / 2 in the next line is there because we need the space in
139 // both directions
140 pixelsPerUnit = (position.height() / maxValue / 2) * 1000 / 1250;
141
142 TQMap < int, double > currentValueSums;
143 if ( params()->polarChartSubType() == KDChartParams::PolarStacked
144 || params()->polarChartSubType() == KDChartParams::PolarPercent )
145 // this array is only used for stacked and percent polar
146 // charts, no need to waste time initializing it for normal
147 // ones
148 for ( int value = 0; value < numValues; value++ )
149 currentValueSums[ value ] = 0.0;
150 TQMap < int, double > totalValueSums;
151
152
153 /*
154 axes schema: use AxisPosSagittal for sagittal 'axis' lines
155 use AxisPosCircular for circular 'axis'
156 */
157 const KDChartAxisParams & paraSagittal = params()->axisParams( KDChartAxisParams::AxisPosSagittal );
158 const KDChartAxisParams & paraCircular = params()->axisParams( KDChartAxisParams::AxisPosCircular );
159
160 int sagittalLineWidth = 0 <= paraSagittal.axisLineWidth()
161 ? paraSagittal.axisLineWidth()
162 : -1 * static_cast < int > ( paraSagittal.axisLineWidth()
163 * minSizeP1000 );
164 ( ( KDChartAxisParams& ) paraSagittal ).setAxisTrueLineWidth( sagittalLineWidth );
165 int sagittalGridLineWidth
167 == paraSagittal.axisGridLineWidth() )
168 ? sagittalLineWidth
169 : ( ( 0 <= paraSagittal.axisGridLineWidth() )
170 ? paraSagittal.axisGridLineWidth()
171 : -1 * static_cast < int > ( paraSagittal.axisGridLineWidth()
172 * minSizeP1000 ) );
173
174 int circularLineWidth = 0 <= paraCircular.axisLineWidth()
175 ? paraCircular.axisLineWidth()
176 : -1 * static_cast < int > ( paraCircular.axisLineWidth()
177 * minSizeP1000 );
178 ( ( KDChartAxisParams& ) paraCircular ).setAxisTrueLineWidth( circularLineWidth );
179 int circularGridLineWidth
181 == paraCircular.axisGridLineWidth() )
182 ? circularLineWidth
183 : ( ( 0 <= paraCircular.axisGridLineWidth() )
184 ? paraCircular.axisGridLineWidth()
185 : -1 * static_cast < int > ( paraCircular.axisGridLineWidth()
186 * minSizeP1000 ) );
187
188 TQFont actFont;
189 int labels = 0;
190 double currentRadiusPPU = position.height() / 2.0;
191
192 // draw the "axis" circles
193 if( paraCircular.axisShowGrid()
194 || paraCircular.axisVisible()
195 || paraCircular.axisLabelsVisible() ) {
196
197 double radiusPPU = maxValue * pixelsPerUnit;
198 double pDelimDelta = 0.0;
199
200 // calculate label texts
201 TQStringList* labelTexts = 0;
202 ((KDChartParams*)params())->setAxisArea( KDChartAxisParams::AxisPosCircular,
203 TQRect( 0,
204 0,
205 static_cast<int>( radiusPPU ),
206 static_cast<int>( radiusPPU ) ) );
207
208 double delimLen = 20.0 * minSizeP1000; // per mille of area
209 KDChartAxisParams::AxisPos basicPos;
210 TQPoint orig, dest;
211 double dDummy;
212 double nSubDelimFactor = 0.0;
213 double nTxtHeight = 0.0;
214 double pTextsX = 0.0;
215 double pTextsY = 0.0;
216 double pTextsW = 0.0;
217 double pTextsH = 0.0;
218 int textAlign = TQt::AlignHCenter | TQt::AlignVCenter;
219 bool isLogarithmic = false;
220 bool isDateTime = false;
221 bool autoDtLabels = false;
222 TQDateTime dtLow;
223 TQDateTime dtHigh;
224 KDChartAxisParams::ValueScale dtDeltaScale;
226 painter,
227 *data,
228 *params(),
229 KDChartAxisParams::AxisPosCircular,
230 minSizeP1000,
231 delimLen,
232 // start of reference parameters
233 basicPos,
234 orig,
235 dest,
236 dDummy,dDummy,dDummy,dDummy,
237 nSubDelimFactor,
238 pDelimDelta,
239 nTxtHeight,
240 pTextsX,
241 pTextsY,
242 pTextsW,
243 pTextsH,
244 textAlign,
245 isLogarithmic,
246 isDateTime,
247 autoDtLabels,
248 dtLow,
249 dtHigh,
250 dtDeltaScale );
251 labelTexts = ( TQStringList* ) paraCircular.axisLabelTexts();
252 if( paraCircular.axisLabelsVisible() ) {
253//tqDebug("\nnTxtHeight: "+TQString::number(nTxtHeight));
254 // calculate font size
255 actFont = paraCircular.axisLabelsFont();
256 if ( paraCircular.axisLabelsFontUseRelSize() ) {
257//tqDebug("paraCircular.axisLabelsFontUseRelSize() is true");
258 actFont.setPointSizeFloat( nTxtHeight );
259 }
260 TQFontMetrics fm( actFont );
261 TQString strMax;
262 int maxLabelsWidth = 0;
263 for ( TQStringList::Iterator it = labelTexts->begin();
264 it != labelTexts->end();
265 ++it ) {
266 if ( fm.width( *it ) > maxLabelsWidth ) {
267 maxLabelsWidth = fm.width( *it );
268 strMax = *it;
269 }
270 }
271 while ( fm.width( strMax ) > pTextsW
272 && 6.0 < nTxtHeight ) {
273 nTxtHeight -= 0.5;
274 actFont.setPointSizeFloat( nTxtHeight );
275 fm = TQFontMetrics( actFont );
276 }
277 painter->setFont( actFont );
278 }
279
280 double radiusDelta = pDelimDelta;
281
282 labels = labelTexts
283 ? labelTexts->count()
284 : 0;
285 if( labels )
286 currentRadiusPPU = -radiusDelta;
287 for( int iLabel = 0; iLabel < labels; ++iLabel ) {
288 //while( currentRadius < maxValue ) {
289 //double currentRadiusPPU = currentRadius;
290 currentRadiusPPU += radiusDelta;
291 double currentRadiusPPU2 = currentRadiusPPU * 2;
292 int circularAxisAngle = ( currentRadiusPPU != 0.0 ) ? ( static_cast < int > (4.0 * radiusPPU / currentRadiusPPU) ) : 0;
293 if( paraCircular.axisShowGrid() ) {
294 painter->setPen( TQPen( paraCircular.axisGridColor(),
295 circularGridLineWidth ) );
296 painter->drawEllipse( static_cast<int>( center.x() - currentRadiusPPU ),
297 static_cast<int>( center.y() - currentRadiusPPU ),
298 static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ) );
299 }
300 if( paraCircular.axisVisible() ) {
301 painter->setPen( TQPen( paraCircular.axisLineColor(),
302 circularLineWidth ) );
303 if( params()->polarDelimAtPos( KDChartEnums::PosTopCenter ) )
304 painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
305 static_cast<int>( center.y() - currentRadiusPPU ),
306 static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
307 (90 - circularAxisAngle/2) * 16,
308 circularAxisAngle * 16 );
309 if( params()->polarDelimAtPos( KDChartEnums::PosBottomCenter ) )
310 painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
311 static_cast<int>( center.y() - currentRadiusPPU ),
312 static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
313 (270 - circularAxisAngle/2) * 16,
314 circularAxisAngle * 16 );
315
316 if( params()->polarDelimAtPos( KDChartEnums::PosCenterRight ) )
317 painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
318 static_cast<int>( center.y() - currentRadiusPPU ),
319 static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
320 (0 - circularAxisAngle/2) * 16,
321 circularAxisAngle * 16 );
322 if( params()->polarDelimAtPos( KDChartEnums::PosCenterLeft ) )
323 painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
324 static_cast<int>( center.y() - currentRadiusPPU ),
325 static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
326 (180 - circularAxisAngle/2) * 16,
327 circularAxisAngle * 16 );
328
329 if( params()->polarDelimAtPos( KDChartEnums::PosTopRight ) )
330 painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
331 static_cast<int>( center.y() - currentRadiusPPU ),
332 static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
333 (45 - circularAxisAngle/2) * 16,
334 circularAxisAngle * 16 );
335 if( params()->polarDelimAtPos( KDChartEnums::PosBottomLeft ) )
336 painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
337 static_cast<int>( center.y() - currentRadiusPPU ),
338 static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
339 (225 - circularAxisAngle/2) * 16,
340 circularAxisAngle * 16 );
341
342 if( params()->polarDelimAtPos( KDChartEnums::PosBottomRight ) )
343 painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
344 static_cast<int>( center.y() - currentRadiusPPU ),
345 static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
346 (315 - circularAxisAngle/2) * 16,
347 circularAxisAngle * 16 );
348 if( params()->polarDelimAtPos( KDChartEnums::PosTopLeft ) )
349 painter->drawArc( static_cast<int>( center.x() - currentRadiusPPU ),
350 static_cast<int>( center.y() - currentRadiusPPU ),
351 static_cast<int>( currentRadiusPPU2 ), static_cast<int>( currentRadiusPPU2 ),
352 (135 - circularAxisAngle/2) * 16,
353 circularAxisAngle * 16 );
354 }
355 if( paraCircular.axisLabelsVisible() ) {
356 const bool rotate = params()->polarRotateCircularLabels();
357 painter->setPen( TQPen( paraCircular.axisLabelsColor(),
358 circularLineWidth ) );
359 const TQString& txt = (*labelTexts)[ iLabel ];
360 if( params()->polarLabelsAtPos( KDChartEnums::PosTopCenter ) )
361 paintCircularAxisLabel( painter, rotate, 90, center, currentRadiusPPU, txt,
362 TQt::AlignBottom | TQt::AlignHCenter, iLabel );
363
364 if( params()->polarLabelsAtPos( KDChartEnums::PosBottomCenter ) )
365 paintCircularAxisLabel( painter, rotate, 270, center, currentRadiusPPU, txt,
366 TQt::AlignTop | TQt::AlignHCenter, iLabel );
367
368 if( params()->polarLabelsAtPos( KDChartEnums::PosCenterRight ) )
369 paintCircularAxisLabel( painter, rotate, 0, center, currentRadiusPPU, txt,
370 TQt::AlignVCenter | TQt::AlignRight, iLabel );
371
372 if( params()->polarLabelsAtPos( KDChartEnums::PosCenterLeft ) )
373 paintCircularAxisLabel( painter, rotate, 180, center, currentRadiusPPU, txt,
374 TQt::AlignVCenter | TQt::AlignLeft, iLabel );
375
376 if( params()->polarLabelsAtPos( KDChartEnums::PosTopRight ) )
377 paintCircularAxisLabel( painter, rotate, 45, center, currentRadiusPPU, txt,
378 TQt::AlignBottom | TQt::AlignRight, iLabel );
379
380 if( params()->polarLabelsAtPos( KDChartEnums::PosBottomLeft ) )
381 paintCircularAxisLabel( painter, rotate, 225, center, currentRadiusPPU, txt,
382 TQt::AlignTop | TQt::AlignLeft, iLabel );
383
384 if( params()->polarLabelsAtPos( KDChartEnums::PosBottomRight ) )
385 paintCircularAxisLabel( painter, rotate, 315, center, currentRadiusPPU, txt,
386 TQt::AlignTop | TQt::AlignRight, iLabel );
387
388 if( params()->polarLabelsAtPos( KDChartEnums::PosTopLeft ) )
389 paintCircularAxisLabel( painter, rotate, 135, center, currentRadiusPPU, txt,
390 TQt::AlignBottom | TQt::AlignLeft, iLabel );
391 }
392 }
393 }
394
395
396 double circularSpan = params()->polarChartSubType() == KDChartParams::PolarPercent
397 ? 100.0
398 : paraCircular.trueAxisHigh() - paraCircular.trueAxisLow();
399 double radius = currentRadiusPPU;
400 if( !labels
401 || params()->polarChartSubType() == KDChartParams::PolarPercent )
402 radius = (position.width() / 2.0) * 1000.0 / 1250.0;
403
404 if( params()->polarChartSubType() != KDChartParams::PolarPercent )
405 pixelsPerUnit = labels ? currentRadiusPPU / circularSpan
406 : (position.height() / maxValue / 2.0) * 1000.0 / 1250.0;
407 else
408 pixelsPerUnit = (position.height() / 100.0 / 2.0) * 1000.0 / 1250.0;
409
410 // draw the sagittal grid and axis lines
411 if( paraSagittal.axisShowGrid()
412 || paraSagittal.axisVisible()
413 || paraSagittal.axisLabelsVisible() ) {
414
415 // calculate label texts
416 TQStringList* labelTexts = 0;
417 bool onlyDefaultLabels = true;
418 if( paraSagittal.axisLabelsVisible() ) {
419 ((KDChartParams*)params())->setAxisArea( KDChartAxisParams::AxisPosSagittal,
420 TQRect( 0,
421 0,
422 static_cast < int > ( 2.0 * M_PI * radius ),
423 static_cast < int > ( 0.5 * radius ) ) );
424 double delimLen = 20.0 * minSizeP1000; // per mille of area
425 KDChartAxisParams::AxisPos basicPos;
426 TQPoint orig, dest;
427 double dDummy;
428 double nSubDelimFactor = 0.0;
429 double pDelimDelta = 0.0;
430 double nTxtHeight = 0.0;
431 double pTextsX = 0.0;
432 double pTextsY = 0.0;
433 double pTextsW = 0.0;
434 double pTextsH = 0.0;
435 int textAlign = TQt::AlignCenter;
436 bool isLogarithmic = false;
437 bool isDateTime = false;
438 bool autoDtLabels = false;
439 TQDateTime dtLow;
440 TQDateTime dtHigh;
441 KDChartAxisParams::ValueScale dtDeltaScale;
443 painter,
444 *data,
445 *params(),
446 KDChartAxisParams::AxisPosSagittal,
447 minSizeP1000,
448 delimLen,
449 // start of reference parameters
450 basicPos,
451 orig,
452 dest,
453 dDummy,dDummy,dDummy,dDummy,
454 nSubDelimFactor,
455 pDelimDelta,
456 nTxtHeight,
457 pTextsX,
458 pTextsY,
459 pTextsW,
460 pTextsH,
461 textAlign,
462 isLogarithmic,
463 isDateTime,
464 autoDtLabels,
465 dtLow,
466 dtHigh,
467 dtDeltaScale );
468 labelTexts = ( TQStringList* ) paraSagittal.axisLabelTexts();
469 // calculate font size
470 actFont = paraSagittal.axisLabelsFont();
471 if ( paraSagittal.axisLabelsFontUseRelSize() ) {
472 actFont.setPointSizeFloat( nTxtHeight );
473 }
474 TQFontMetrics fm( actFont );
475 TQString strMax;
476 int maxLabelsWidth = 0;
477 for ( TQStringList::Iterator it = labelTexts->begin();
478 it != labelTexts->end();
479 ++it ) {
480 if ( fm.width( *it ) > maxLabelsWidth ) {
481 maxLabelsWidth = fm.width( *it );
482 strMax = *it;
483 }
484 if ( !(*it).startsWith( "Item ") )
485 onlyDefaultLabels = false;
486 }
487 while ( fm.width( strMax ) > pTextsW && 6.0 < nTxtHeight ) {
488 nTxtHeight -= 0.5;
489 actFont.setPointSizeFloat( nTxtHeight );
490 fm = TQFontMetrics( actFont );
491 }
492 painter->setFont( actFont );
493 }
494
495 int currentAngle = params()->polarZeroDegreePos();
496 if( -360 > currentAngle
497 || 360 < currentAngle )
498 currentAngle = 0;
499 if( 0 > currentAngle )
500 currentAngle += 360;
501 int r1 = static_cast < int > ( radius * 1050 / 1000 );
502 int r2 = static_cast < int > ( radius * 1100 / 1000 );
503 int r3 = static_cast < int > ( radius * 1175 / 1000 );
504 TQPoint pt1, pt2, pt3;
505 uint nLabels = labelTexts->count();
506 int angleBetweenRays = 360 / nLabels;
507 for( uint value = 0; value < nLabels; ++value ) {
508 pt1 = center + polarToXY( r1, currentAngle );
509 pt2 = center + polarToXY( r2, currentAngle );
510 pt3 = center + polarToXY( r3, currentAngle );
511
512 //pt3 = painter->worldMatrix().map( pt3 );
513
514 if( paraSagittal.axisShowGrid() ) {
515 painter->setPen( TQPen( paraSagittal.axisGridColor(),
516 sagittalGridLineWidth ) );
517 painter->drawLine( center, pt1 );
518 }
519 if( paraSagittal.axisVisible() ) {
520 painter->setPen( TQPen( paraSagittal.axisLineColor(),
521 sagittalLineWidth ) );
522 painter->drawLine( pt1, pt2 );
523 }
524 if( paraSagittal.axisLabelsVisible()
525 && labelTexts
526 && labelTexts->count() > value ) {
527 painter->setPen( TQPen( paraSagittal.axisLabelsColor(),
528 sagittalLineWidth ) );
529 TQString label( onlyDefaultLabels
530 ? TQString::number( currentAngle )
531 : (*labelTexts)[ value ] );
532
533 KDDrawText::drawRotatedText( painter,
534 currentAngle+90,
535 painter->worldMatrix().map(pt3),
536 label,
537 0,
538 TQt::AlignCenter );
539 }
540 currentAngle += angleBetweenRays;
541 }
542 }
543
544
545 // Now draw the data
546 int dataLinesWidth = 0 <= params()->polarLineWidth()
547 ? params()->polarLineWidth()
548 : -1 * static_cast < int > ( params()->polarLineWidth()
549 * minSizeP1000 );
550 painter->setBrush( TQt::NoBrush );
551 for ( unsigned int dataset = datasetStart; dataset <= datasetEnd; dataset++ ) {
552 painter->setPen( TQPen( params()->dataColor( dataset ),
553 dataLinesWidth ) );
554 TQPointArray points( numValues );
555 int totalPoints = 0;
556 double valueTotal = 0.0; // Will only be used for Percent
557 int angleBetweenRays = 360 / numValues;
558 TQVariant vValY;
559 for ( int value = 0; value < numValues; value++ ) {
560 if( params()->polarChartSubType() == KDChartParams::PolarPercent )
561 valueTotal = data->colAbsSum( value );
562 // the value determines the angle, the dataset only the color
563 if( data->cellCoord( dataset, value, vValY, 1 ) &&
564 TQVariant::Double == vValY.type() ){
565 const double cellValue = vValY.toDouble();
566 double drawValue;
567 if ( params()->polarChartSubType() == KDChartParams::PolarStacked )
568 drawValue = ( cellValue + currentValueSums[ value ] ) * pixelsPerUnit;
569 else if( params()->polarChartSubType() == KDChartParams::PolarPercent ) {
570 drawValue = ( ( cellValue + currentValueSums[ value ] )
571 / valueTotal * static_cast<double>( radius ) );
572 } else
573 drawValue = cellValue * pixelsPerUnit;
574
575 // record the point for drawing the polygon later
576 int drawAngle = value * angleBetweenRays;
577 TQPoint drawPoint( center + polarToXY( static_cast<int>( drawValue ),
578 drawAngle ) );
579 points.setPoint( totalPoints, drawPoint );
580 totalPoints++;
581 KDChartDataRegion* datReg = 0;
582 // the marker can be drawn now
583 if( params()->polarMarker() ) {
584 int xsize = params()->polarMarkerSize().width();
585 int ysize = params()->polarMarkerSize().height();
586 datReg = drawMarker( painter,
587 params(),
588 _areaWidthP1000, _areaHeightP1000,
589 _dataRect.x(), _dataRect.y(),
590 params()->polarMarkerStyle( dataset ),
591 params()->dataColor( dataset ),
592 drawPoint,
593 dataset, value, chart,
594 regions,
595 xsize ? &xsize : 0,
596 ysize ? &ysize : 0 );
597 painter->setPen( TQPen( params()->dataColor( dataset ),
598 dataLinesWidth ) );
599 }
600 if ( regions ) {
601 bool bMustAppendDatReg = 0 == datReg;
602 if( bMustAppendDatReg ){
603 TQRect rect( TQPoint( drawPoint.x() - 1,
604 drawPoint.y() - 1 ),
605 TQSize( 3, 3 ) );
606 datReg = new KDChartDataRegion( dataset,
607 value,
608 chart,
609 rect );
610 }
611 datReg->points[ KDChartEnums::PosTopLeft ] =
612 drawPoint + _dataRect.topLeft();
613
614 datReg->points[ KDChartEnums::PosTopCenter ] =
615 datReg->points[ KDChartEnums::PosTopLeft ];
616 datReg->points[ KDChartEnums::PosTopRight ] =
617 datReg->points[ KDChartEnums::PosTopLeft ];
618 datReg->points[ KDChartEnums::PosBottomLeft ] =
619 datReg->points[ KDChartEnums::PosTopLeft ];
620 datReg->points[ KDChartEnums::PosBottomCenter ] =
621 datReg->points[ KDChartEnums::PosTopLeft ];
622 datReg->points[ KDChartEnums::PosBottomRight ] =
623 datReg->points[ KDChartEnums::PosTopLeft ];
624 datReg->points[ KDChartEnums::PosCenterLeft ] =
625 datReg->points[ KDChartEnums::PosTopLeft ];
626 datReg->points[ KDChartEnums::PosCenter ] =
627 datReg->points[ KDChartEnums::PosTopLeft ];
628 datReg->points[ KDChartEnums::PosCenterRight ] =
629 datReg->points[ KDChartEnums::PosTopLeft ];
630 /*
631 // test the center positions:
632 painter->drawEllipse( datReg->points[ KDChartEnums::PosCenterLeft ].x() - 2,
633 datReg->points[ KDChartEnums::PosCenterLeft ].y() - 2, 5, 5);
634 */
635 datReg->startAngle = drawAngle;
636 datReg->angleLen = drawAngle;
637 if( bMustAppendDatReg )
638 regions->append( datReg );
639 }
640 // calculate running sum for stacked and percent
641 if ( params()->polarChartSubType() == KDChartParams::PolarStacked ||
642 params()->polarChartSubType() == KDChartParams::PolarPercent )
643 currentValueSums[ value ] += cellValue;
644 }
645 }
646 painter->drawPolygon( points );
647 }
648
649 painter->translate( -_dataRect.x(), -_dataRect.y() );
650}
651
652
653/*
654 Helper methode being called by KDChartPolarPainter::paintData()
655*/
656void KDChartPolarPainter::paintCircularAxisLabel( TQPainter* painter,
657 bool rotate,
658 int txtAngle,
659 TQPoint center,
660 double currentRadiusPPU,
661 const TQString& txt,
662 int align,
663 int step )
664{
665 if( !rotate && (0 != (align & (TQt::AlignLeft | TQt::AlignRight) ) ) )
666 currentRadiusPPU += center.x()*0.01;
667 KDDrawText::drawRotatedText(
668 painter,
669 rotate ? txtAngle - 90 : 0,
670 painter->worldMatrix().map(center - polarToXY( static_cast<int>( currentRadiusPPU ), txtAngle )),
671 txt,
672 0,
673 step
674 ? (rotate ? TQt::AlignBottom | TQt::AlignHCenter : align)
675 : TQt::AlignCenter,
676 false,0,false,
677 false );
678}
679
680
/*
693void KDChartPolarPainter::drawMarker( TQPainter* painter,
694 KDChartParams::PolarMarkerStyle style,
695 const TQColor& color,
696 const TQPoint& p,
697 uint, //dataset,
698 uint, //value,
699 uint, //chart,
700 double minSizeP1000,
701 TQRegion& region )
702{
703 int xsize = params()->polarMarkerSize().width();
704 if ( 0 > xsize )
705 xsize = -1 * static_cast < int > ( xsize * minSizeP1000 );
706 int ysize = params()->polarMarkerSize().height();
707 if ( 0 > ysize )
708 ysize = -1 * static_cast < int > ( ysize * minSizeP1000 );
709 int xsize2 = xsize / 2;
710 int ysize2 = ysize / 2;
711 painter->setPen( color );
712 switch ( style ) {
713 case KDChartParams::PolarMarkerSquare: {
714 painter->save();
715 painter->setBrush( color );
716 TQRect rect( TQPoint( p.x() - xsize2, p.y() - ysize2 ), TQPoint( p.x() + xsize2, p.y() + ysize2 ) );
717 painter->drawRect( rect );
718 // Don't use rect for drawing after this!
719 rect.moveBy( _dataRect.x(), _dataRect.y() );
720 region = TQRegion( rect );
721 painter->restore();
722 break;
723 }
724 case KDChartParams::PolarMarkerDiamond: {
725 painter->save();
726 painter->setBrush( color );
727 TQPointArray points( 4 );
728 points.setPoint( 0, p.x() - xsize2, p.y() );
729 points.setPoint( 1, p.x(), p.y() - ysize2 );
730 points.setPoint( 2, p.x() + xsize2, p.y() );
731 points.setPoint( 3, p.x(), p.y() + ysize2 );
732 painter->drawPolygon( points );
733 // Don't use points for drawing after this!
734 points.translate( _dataRect.x(), _dataRect.y() );
735 region = TQRegion( points );
736 painter->restore();
737 break;
738 }
739 case KDChartParams::PolarMarkerCircle:
740 default: {
741 painter->save();
742 painter->setBrush( color );
743 painter->drawEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
744 TQPointArray points;
745 points.makeEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
746 // Don't use points for drawing after this!
747 points.translate( _dataRect.x(), _dataRect.y() );
748 if( points.size() > 0 )
749 region = TQRegion( points );
750 else
751 region = TQRegion();
752 painter->restore();
753 }
754 };
755}*/
756
757#define DEGTORAD(d) (d)*M_PI/180
758
759TQPoint KDChartPolarPainter::polarToXY( int radius, int angle )
760{
761 double anglerad = DEGTORAD( static_cast<double>( angle ) );
762 TQPoint ret( static_cast<int>( cos( anglerad ) * radius ),
763 static_cast<int>( sin( anglerad ) * radius ) );
764 return ret;
765}
766
767
781TQString KDChartPolarPainter::fallbackLegendText( uint dataset ) const
782{
783 return TQObject::tr( "Series " ) + TQString::number( dataset + 1 );
784}
785
786
797{
798 return data->usedRows();
799}
Provide access to the chart axis parameters.
#define KDCHART_AXIS_GRID_AUTO_LINEWIDTH
Use this to specify that the width of the axis grid lines shall be equal to the width of the axis lin...
Header for all common chart parameters.
static void calculateLabelTexts(TQPainter *painter, const KDChartTableDataBase &data, const KDChartParams &params, uint axisNumber, double averageValueP1000, double delimLen, KDChartAxisParams::AxisPos &basicPos, TQPoint &orig, TQPoint &dest, double &pXDeltaFactor, double &pYDeltaFactor, double &pXDelimDeltaFaktor, double &pYDelimDeltaFaktor, double &nSubDelimFactor, double &pDelimDelta, double &nTxtHeight, double &pTextsX, double &pTextsY, double &pTextsW, double &pTextsH, int &textAlign, bool &isLogarithmic, bool &isDateTime, bool &autoDtLabels, TQDateTime &dtLow, TQDateTime &dtHigh, KDChartAxisParams::ValueScale &dtDeltaScale, bool adjustTheValues=false, double trueDelta=0.0, double trueDeltaPix=0.0)
Calculates the actual label texts for one axis.
access the chart axis parameters.
TQColor axisLabelsColor() const
Returns the axis labels colour.
TQColor axisGridColor() const
Returns the axis grid color.
double trueAxisHigh() const
Returns the true end value of the ordinate axis labels as is was calculated and set by setTrueAxisLow...
double trueAxisLow() const
Returns the true start value of the ordinate axis labels as is was calculated and set by setTrueAxisL...
int axisGridLineWidth() const
Returns the width of the axis grid lines.
TQFont axisLabelsFont() const
Returns the axis labels font.
bool axisLabelsFontUseRelSize() const
Returns whether the fix axis font size is used.
bool axisShowGrid() const
Returns whether a grid should be drawn at the chart data area.
int axisLineWidth() const
Returns the axis line width.
bool axisVisible() const
Returns weither the axis will be drawn or not.
TQColor axisLineColor() const
Returns the axis line colour.
bool axisLabelsVisible() const
Returns whether the axis labels should be drawn.
The collection class used by KD Chart to store data region information.
An abstract base class that defines an interface for classes that implement chart drawing.
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.
TQSize polarMarkerSize() const
Returns the sizes of polar markers.
int polarLineWidth() const
Returns the line width of the lines in polar charts.
int polarZeroDegreePos() const
Returns the zero degree position in polar charts.
int numValues() const
Returns how many of the values should be shown.
PolarChartSubType polarChartSubType() const
Returns the polar chart subtype.
const KDChartAxisParams & axisParams(uint n) const
Returns the parameters that are currently defined for axis n.
bool polarRotateCircularLabels() const
Returns whether circular labels will be rotated in polar charts.
virtual void paintData(TQPainter *painter, KDChartTableDataBase *data, bool paint2nd, KDChartDataRegionList *regions=0)
Paints the actual data area.
virtual ~KDChartPolarPainter()
Destructor.
virtual uint numLegendFallbackTexts(KDChartTableDataBase *data) const
This methods returns the number of elements to be shown in the legend in case fallback texts are used...
KDChartPolarPainter(KDChartParams *params)
Constructor.
virtual TQString fallbackLegendText(uint dataset) const
This method is a specialization that returns a fallback legend text appropriate for polar charts wher...
KD Chart's build-in table data for an easy way of storing data values.
virtual uint usedCols() const
Returns the number of cols in the table that actually contain data.
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 usedRows() const
Returns the number of rows in the table that actually contain data.