source: ntrip/trunk/BNC/qwt/qwt_scale_engine.cpp@ 4720

Last change on this file since 4720 was 4271, checked in by mervart, 13 years ago
File size: 23.2 KB
Line 
1/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2 * Qwt Widget Library
3 * Copyright (C) 1997 Josef Wilgen
4 * Copyright (C) 2002 Uwe Rathmann
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the Qwt License, Version 1.0
8 *****************************************************************************/
9
10#include "qwt_scale_engine.h"
11#include "qwt_math.h"
12#include "qwt_scale_map.h"
13#include <qalgorithms.h>
14#include <qmath.h>
15
16#if QT_VERSION < 0x040601
17#define qFabs(x) ::fabs(x)
18#define qExp(x) ::exp(x)
19#endif
20
21static const double _eps = 1.0e-6;
22
23/*!
24 Ceil a value, relative to an interval
25
26 \param value Value to ceil
27 \param intervalSize Interval size
28
29 \sa floorEps()
30*/
31double QwtScaleArithmetic::ceilEps( double value,
32 double intervalSize )
33{
34 const double eps = _eps * intervalSize;
35
36 value = ( value - eps ) / intervalSize;
37 return qwtCeilF( value ) * intervalSize;
38}
39
40/*!
41 Floor a value, relative to an interval
42
43 \param value Value to floor
44 \param intervalSize Interval size
45
46 \sa floorEps()
47*/
48double QwtScaleArithmetic::floorEps( double value, double intervalSize )
49{
50 const double eps = _eps * intervalSize;
51
52 value = ( value + eps ) / intervalSize;
53 return qwtFloorF( value ) * intervalSize;
54}
55
56/*!
57 \brief Divide an interval into steps
58
59 \f$stepSize = (intervalSize - intervalSize * 10e^{-6}) / numSteps\f$
60
61 \param intervalSize Interval size
62 \param numSteps Number of steps
63 \return Step size
64*/
65double QwtScaleArithmetic::divideEps( double intervalSize, double numSteps )
66{
67 if ( numSteps == 0.0 || intervalSize == 0.0 )
68 return 0.0;
69
70 return ( intervalSize - ( _eps * intervalSize ) ) / numSteps;
71}
72
73/*!
74 Find the smallest value out of {1,2,5}*10^n with an integer number n
75 which is greater than or equal to x
76
77 \param x Input value
78*/
79double QwtScaleArithmetic::ceil125( double x )
80{
81 if ( x == 0.0 )
82 return 0.0;
83
84 const double sign = ( x > 0 ) ? 1.0 : -1.0;
85 const double lx = ::log10( qFabs( x ) );
86 const double p10 = qwtFloorF( lx );
87
88 double fr = qPow( 10.0, lx - p10 );
89 if ( fr <= 1.0 )
90 fr = 1.0;
91 else if ( fr <= 2.0 )
92 fr = 2.0;
93 else if ( fr <= 5.0 )
94 fr = 5.0;
95 else
96 fr = 10.0;
97
98 return sign * fr * qPow( 10.0, p10 );
99}
100
101/*!
102 \brief Find the largest value out of {1,2,5}*10^n with an integer number n
103 which is smaller than or equal to x
104
105 \param x Input value
106*/
107double QwtScaleArithmetic::floor125( double x )
108{
109 if ( x == 0.0 )
110 return 0.0;
111
112 double sign = ( x > 0 ) ? 1.0 : -1.0;
113 const double lx = ::log10( qFabs( x ) );
114 const double p10 = qwtFloorF( lx );
115
116 double fr = qPow( 10.0, lx - p10 );
117 if ( fr >= 10.0 )
118 fr = 10.0;
119 else if ( fr >= 5.0 )
120 fr = 5.0;
121 else if ( fr >= 2.0 )
122 fr = 2.0;
123 else
124 fr = 1.0;
125
126 return sign * fr * qPow( 10.0, p10 );
127}
128
129class QwtScaleEngine::PrivateData
130{
131public:
132 PrivateData():
133 attributes( QwtScaleEngine::NoAttribute ),
134 lowerMargin( 0.0 ),
135 upperMargin( 0.0 ),
136 referenceValue( 0.0 )
137 {
138 }
139
140 QwtScaleEngine::Attributes attributes; // scale attributes
141
142 double lowerMargin; // margins
143 double upperMargin;
144
145 double referenceValue; // reference value
146
147};
148
149//! Constructor
150QwtScaleEngine::QwtScaleEngine()
151{
152 d_data = new PrivateData;
153}
154
155
156//! Destructor
157QwtScaleEngine::~QwtScaleEngine ()
158{
159 delete d_data;
160}
161
162/*!
163 \return the margin at the lower end of the scale
164 The default margin is 0.
165
166 \sa setMargins()
167*/
168double QwtScaleEngine::lowerMargin() const
169{
170 return d_data->lowerMargin;
171}
172
173/*!
174 \return the margin at the upper end of the scale
175 The default margin is 0.
176
177 \sa setMargins()
178*/
179double QwtScaleEngine::upperMargin() const
180{
181 return d_data->upperMargin;
182}
183
184/*!
185 \brief Specify margins at the scale's endpoints
186 \param lower minimum distance between the scale's lower boundary and the
187 smallest enclosed value
188 \param upper minimum distance between the scale's upper boundary and the
189 greatest enclosed value
190
191 Margins can be used to leave a minimum amount of space between
192 the enclosed intervals and the boundaries of the scale.
193
194 \warning
195 \li QwtLog10ScaleEngine measures the margins in decades.
196
197 \sa upperMargin(), lowerMargin()
198*/
199
200void QwtScaleEngine::setMargins( double lower, double upper )
201{
202 d_data->lowerMargin = qMax( lower, 0.0 );
203 d_data->upperMargin = qMax( upper, 0.0 );
204}
205
206/*!
207 Calculate a step size for an interval size
208
209 \param intervalSize Interval size
210 \param numSteps Number of steps
211
212 \return Step size
213*/
214double QwtScaleEngine::divideInterval(
215 double intervalSize, int numSteps ) const
216{
217 if ( numSteps <= 0 )
218 return 0.0;
219
220 double v = QwtScaleArithmetic::divideEps( intervalSize, numSteps );
221 return QwtScaleArithmetic::ceil125( v );
222}
223
224/*!
225 Check if an interval "contains" a value
226
227 \param interval Interval
228 \param value Value
229
230 \sa QwtScaleArithmetic::compareEps()
231*/
232bool QwtScaleEngine::contains(
233 const QwtInterval &interval, double value ) const
234{
235 if ( !interval.isValid() )
236 return false;
237
238 if ( qwtFuzzyCompare( value, interval.minValue(), interval.width() ) < 0 )
239 return false;
240
241 if ( qwtFuzzyCompare( value, interval.maxValue(), interval.width() ) > 0 )
242 return false;
243
244 return true;
245}
246
247/*!
248 Remove ticks from a list, that are not inside an interval
249
250 \param ticks Tick list
251 \param interval Interval
252
253 \return Stripped tick list
254*/
255QList<double> QwtScaleEngine::strip( const QList<double>& ticks,
256 const QwtInterval &interval ) const
257{
258 if ( !interval.isValid() || ticks.count() == 0 )
259 return QList<double>();
260
261 if ( contains( interval, ticks.first() )
262 && contains( interval, ticks.last() ) )
263 {
264 return ticks;
265 }
266
267 QList<double> strippedTicks;
268 for ( int i = 0; i < ticks.count(); i++ )
269 {
270 if ( contains( interval, ticks[i] ) )
271 strippedTicks += ticks[i];
272 }
273 return strippedTicks;
274}
275
276/*!
277 \brief Build an interval for a value
278
279 In case of v == 0.0 the interval is [-0.5, 0.5],
280 otherwide it is [0.5 * v, 1.5 * v]
281*/
282
283QwtInterval QwtScaleEngine::buildInterval( double v ) const
284{
285 const double delta = ( v == 0.0 ) ? 0.5 : qAbs( 0.5 * v );
286 return QwtInterval( v - delta, v + delta );
287}
288
289/*!
290 Change a scale attribute
291
292 \param attribute Attribute to change
293 \param on On/Off
294
295 \sa Attribute, testAttribute()
296*/
297void QwtScaleEngine::setAttribute( Attribute attribute, bool on )
298{
299 if ( on )
300 d_data->attributes |= attribute;
301 else
302 d_data->attributes &= ~attribute;
303}
304
305/*!
306 Check if a attribute is set.
307
308 \param attribute Attribute to be tested
309 \sa Attribute, setAttribute()
310*/
311bool QwtScaleEngine::testAttribute( Attribute attribute ) const
312{
313 return ( d_data->attributes & attribute );
314}
315
316/*!
317 Change the scale attribute
318
319 \param attributes Set scale attributes
320 \sa Attribute, attributes()
321*/
322void QwtScaleEngine::setAttributes( Attributes attributes )
323{
324 d_data->attributes = attributes;
325}
326
327/*!
328 Return the scale attributes
329 \sa Attribute, setAttributes(), testAttribute()
330*/
331QwtScaleEngine::Attributes QwtScaleEngine::attributes() const
332{
333 return d_data->attributes;
334}
335
336/*!
337 \brief Specify a reference point
338 \param r new reference value
339
340 The reference point is needed if options IncludeReference or
341 Symmetric are active. Its default value is 0.0.
342
343 \sa Attribute
344*/
345void QwtScaleEngine::setReference( double r )
346{
347 d_data->referenceValue = r;
348}
349
350/*!
351 \return the reference value
352 \sa setReference(), setAttribute()
353*/
354double QwtScaleEngine::reference() const
355{
356 return d_data->referenceValue;
357}
358
359/*!
360 Return a transformation, for linear scales
361*/
362QwtScaleTransformation *QwtLinearScaleEngine::transformation() const
363{
364 return new QwtScaleTransformation( QwtScaleTransformation::Linear );
365}
366
367/*!
368 Align and divide an interval
369
370 \param maxNumSteps Max. number of steps
371 \param x1 First limit of the interval (In/Out)
372 \param x2 Second limit of the interval (In/Out)
373 \param stepSize Step size (Out)
374
375 \sa setAttribute()
376*/
377void QwtLinearScaleEngine::autoScale( int maxNumSteps,
378 double &x1, double &x2, double &stepSize ) const
379{
380 QwtInterval interval( x1, x2 );
381 interval = interval.normalized();
382
383 interval.setMinValue( interval.minValue() - lowerMargin() );
384 interval.setMaxValue( interval.maxValue() + upperMargin() );
385
386 if ( testAttribute( QwtScaleEngine::Symmetric ) )
387 interval = interval.symmetrize( reference() );
388
389 if ( testAttribute( QwtScaleEngine::IncludeReference ) )
390 interval = interval.extend( reference() );
391
392 if ( interval.width() == 0.0 )
393 interval = buildInterval( interval.minValue() );
394
395 stepSize = divideInterval( interval.width(), qMax( maxNumSteps, 1 ) );
396
397 if ( !testAttribute( QwtScaleEngine::Floating ) )
398 interval = align( interval, stepSize );
399
400 x1 = interval.minValue();
401 x2 = interval.maxValue();
402
403 if ( testAttribute( QwtScaleEngine::Inverted ) )
404 {
405 qSwap( x1, x2 );
406 stepSize = -stepSize;
407 }
408}
409
410/*!
411 \brief Calculate a scale division
412
413 \param x1 First interval limit
414 \param x2 Second interval limit
415 \param maxMajSteps Maximum for the number of major steps
416 \param maxMinSteps Maximum number of minor steps
417 \param stepSize Step size. If stepSize == 0, the scaleEngine
418 calculates one.
419
420 \sa QwtScaleEngine::stepSize(), QwtScaleEngine::subDivide()
421*/
422QwtScaleDiv QwtLinearScaleEngine::divideScale( double x1, double x2,
423 int maxMajSteps, int maxMinSteps, double stepSize ) const
424{
425 QwtInterval interval = QwtInterval( x1, x2 ).normalized();
426 if ( interval.width() <= 0 )
427 return QwtScaleDiv();
428
429 stepSize = qAbs( stepSize );
430 if ( stepSize == 0.0 )
431 {
432 if ( maxMajSteps < 1 )
433 maxMajSteps = 1;
434
435 stepSize = divideInterval( interval.width(), maxMajSteps );
436 }
437
438 QwtScaleDiv scaleDiv;
439
440 if ( stepSize != 0.0 )
441 {
442 QList<double> ticks[QwtScaleDiv::NTickTypes];
443 buildTicks( interval, stepSize, maxMinSteps, ticks );
444
445 scaleDiv = QwtScaleDiv( interval, ticks );
446 }
447
448 if ( x1 > x2 )
449 scaleDiv.invert();
450
451 return scaleDiv;
452}
453
454/*!
455 \brief Calculate ticks for an interval
456
457 \param interval Interval
458 \param stepSize Step size
459 \param maxMinSteps Maximum number of minor steps
460 \param ticks Arrays to be filled with the calculated ticks
461
462 \sa buildMajorTicks(), buildMinorTicks
463*/
464void QwtLinearScaleEngine::buildTicks(
465 const QwtInterval& interval, double stepSize, int maxMinSteps,
466 QList<double> ticks[QwtScaleDiv::NTickTypes] ) const
467{
468 const QwtInterval boundingInterval =
469 align( interval, stepSize );
470
471 ticks[QwtScaleDiv::MajorTick] =
472 buildMajorTicks( boundingInterval, stepSize );
473
474 if ( maxMinSteps > 0 )
475 {
476 buildMinorTicks( ticks[QwtScaleDiv::MajorTick], maxMinSteps, stepSize,
477 ticks[QwtScaleDiv::MinorTick], ticks[QwtScaleDiv::MediumTick] );
478 }
479
480 for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
481 {
482 ticks[i] = strip( ticks[i], interval );
483
484 // ticks very close to 0.0 are
485 // explicitely set to 0.0
486
487 for ( int j = 0; j < ticks[i].count(); j++ )
488 {
489 if ( qwtFuzzyCompare( ticks[i][j], 0.0, stepSize ) == 0 )
490 ticks[i][j] = 0.0;
491 }
492 }
493}
494
495/*!
496 \brief Calculate major ticks for an interval
497
498 \param interval Interval
499 \param stepSize Step size
500
501 \return Calculated ticks
502*/
503QList<double> QwtLinearScaleEngine::buildMajorTicks(
504 const QwtInterval &interval, double stepSize ) const
505{
506 int numTicks = qRound( interval.width() / stepSize ) + 1;
507 if ( numTicks > 10000 )
508 numTicks = 10000;
509
510 QList<double> ticks;
511
512 ticks += interval.minValue();
513 for ( int i = 1; i < numTicks - 1; i++ )
514 ticks += interval.minValue() + i * stepSize;
515 ticks += interval.maxValue();
516
517 return ticks;
518}
519
520/*!
521 \brief Calculate minor/medium ticks for major ticks
522
523 \param majorTicks Major ticks
524 \param maxMinSteps Maximum number of minor steps
525 \param stepSize Step size
526 \param minorTicks Array to be filled with the calculated minor ticks
527 \param mediumTicks Array to be filled with the calculated medium ticks
528
529*/
530void QwtLinearScaleEngine::buildMinorTicks(
531 const QList<double>& majorTicks,
532 int maxMinSteps, double stepSize,
533 QList<double> &minorTicks,
534 QList<double> &mediumTicks ) const
535{
536 double minStep = divideInterval( stepSize, maxMinSteps );
537 if ( minStep == 0.0 )
538 return;
539
540 // # ticks per interval
541 int numTicks = qCeil( qAbs( stepSize / minStep ) ) - 1;
542
543 // Do the minor steps fit into the interval?
544 if ( qwtFuzzyCompare( ( numTicks + 1 ) * qAbs( minStep ),
545 qAbs( stepSize ), stepSize ) > 0 )
546 {
547 numTicks = 1;
548 minStep = stepSize * 0.5;
549 }
550
551 int medIndex = -1;
552 if ( numTicks % 2 )
553 medIndex = numTicks / 2;
554
555 // calculate minor ticks
556
557 for ( int i = 0; i < majorTicks.count(); i++ )
558 {
559 double val = majorTicks[i];
560 for ( int k = 0; k < numTicks; k++ )
561 {
562 val += minStep;
563
564 double alignedValue = val;
565 if ( qwtFuzzyCompare( val, 0.0, stepSize ) == 0 )
566 alignedValue = 0.0;
567
568 if ( k == medIndex )
569 mediumTicks += alignedValue;
570 else
571 minorTicks += alignedValue;
572 }
573 }
574}
575
576/*!
577 \brief Align an interval to a step size
578
579 The limits of an interval are aligned that both are integer
580 multiples of the step size.
581
582 \param interval Interval
583 \param stepSize Step size
584
585 \return Aligned interval
586*/
587QwtInterval QwtLinearScaleEngine::align(
588 const QwtInterval &interval, double stepSize ) const
589{
590 double x1 = QwtScaleArithmetic::floorEps( interval.minValue(), stepSize );
591 if ( qwtFuzzyCompare( interval.minValue(), x1, stepSize ) == 0 )
592 x1 = interval.minValue();
593
594 double x2 = QwtScaleArithmetic::ceilEps( interval.maxValue(), stepSize );
595 if ( qwtFuzzyCompare( interval.maxValue(), x2, stepSize ) == 0 )
596 x2 = interval.maxValue();
597
598 return QwtInterval( x1, x2 );
599}
600
601/*!
602 Return a transformation, for logarithmic (base 10) scales
603*/
604QwtScaleTransformation *QwtLog10ScaleEngine::transformation() const
605{
606 return new QwtScaleTransformation( QwtScaleTransformation::Log10 );
607}
608
609/*!
610 Align and divide an interval
611
612 \param maxNumSteps Max. number of steps
613 \param x1 First limit of the interval (In/Out)
614 \param x2 Second limit of the interval (In/Out)
615 \param stepSize Step size (Out)
616
617 \sa QwtScaleEngine::setAttribute()
618*/
619void QwtLog10ScaleEngine::autoScale( int maxNumSteps,
620 double &x1, double &x2, double &stepSize ) const
621{
622 if ( x1 > x2 )
623 qSwap( x1, x2 );
624
625 QwtInterval interval( x1 / qPow( 10.0, lowerMargin() ),
626 x2 * qPow( 10.0, upperMargin() ) );
627
628 if ( interval.maxValue() / interval.minValue() < 10.0 )
629 {
630 // scale width is less than one decade -> build linear scale
631
632 QwtLinearScaleEngine linearScaler;
633 linearScaler.setAttributes( attributes() );
634 linearScaler.setReference( reference() );
635 linearScaler.setMargins( lowerMargin(), upperMargin() );
636
637 linearScaler.autoScale( maxNumSteps, x1, x2, stepSize );
638 stepSize = ::log10( stepSize );
639
640 return;
641 }
642
643 double logRef = 1.0;
644 if ( reference() > LOG_MIN / 2 )
645 logRef = qMin( reference(), LOG_MAX / 2 );
646
647 if ( testAttribute( QwtScaleEngine::Symmetric ) )
648 {
649 const double delta = qMax( interval.maxValue() / logRef,
650 logRef / interval.minValue() );
651 interval.setInterval( logRef / delta, logRef * delta );
652 }
653
654 if ( testAttribute( QwtScaleEngine::IncludeReference ) )
655 interval = interval.extend( logRef );
656
657 interval = interval.limited( LOG_MIN, LOG_MAX );
658
659 if ( interval.width() == 0.0 )
660 interval = buildInterval( interval.minValue() );
661
662 stepSize = divideInterval( log10( interval ).width(), qMax( maxNumSteps, 1 ) );
663 if ( stepSize < 1.0 )
664 stepSize = 1.0;
665
666 if ( !testAttribute( QwtScaleEngine::Floating ) )
667 interval = align( interval, stepSize );
668
669 x1 = interval.minValue();
670 x2 = interval.maxValue();
671
672 if ( testAttribute( QwtScaleEngine::Inverted ) )
673 {
674 qSwap( x1, x2 );
675 stepSize = -stepSize;
676 }
677}
678
679/*!
680 \brief Calculate a scale division
681
682 \param x1 First interval limit
683 \param x2 Second interval limit
684 \param maxMajSteps Maximum for the number of major steps
685 \param maxMinSteps Maximum number of minor steps
686 \param stepSize Step size. If stepSize == 0, the scaleEngine
687 calculates one.
688
689 \sa QwtScaleEngine::stepSize(), QwtLog10ScaleEngine::subDivide()
690*/
691QwtScaleDiv QwtLog10ScaleEngine::divideScale( double x1, double x2,
692 int maxMajSteps, int maxMinSteps, double stepSize ) const
693{
694 QwtInterval interval = QwtInterval( x1, x2 ).normalized();
695 interval = interval.limited( LOG_MIN, LOG_MAX );
696
697 if ( interval.width() <= 0 )
698 return QwtScaleDiv();
699
700 if ( interval.maxValue() / interval.minValue() < 10.0 )
701 {
702 // scale width is less than one decade -> build linear scale
703
704 QwtLinearScaleEngine linearScaler;
705 linearScaler.setAttributes( attributes() );
706 linearScaler.setReference( reference() );
707 linearScaler.setMargins( lowerMargin(), upperMargin() );
708
709 if ( stepSize != 0.0 )
710 stepSize = qPow( 10.0, stepSize );
711
712 return linearScaler.divideScale( x1, x2,
713 maxMajSteps, maxMinSteps, stepSize );
714 }
715
716 stepSize = qAbs( stepSize );
717 if ( stepSize == 0.0 )
718 {
719 if ( maxMajSteps < 1 )
720 maxMajSteps = 1;
721
722 stepSize = divideInterval( log10( interval ).width(), maxMajSteps );
723 if ( stepSize < 1.0 )
724 stepSize = 1.0; // major step must be >= 1 decade
725 }
726
727 QwtScaleDiv scaleDiv;
728 if ( stepSize != 0.0 )
729 {
730 QList<double> ticks[QwtScaleDiv::NTickTypes];
731 buildTicks( interval, stepSize, maxMinSteps, ticks );
732
733 scaleDiv = QwtScaleDiv( interval, ticks );
734 }
735
736 if ( x1 > x2 )
737 scaleDiv.invert();
738
739 return scaleDiv;
740}
741
742/*!
743 \brief Calculate ticks for an interval
744
745 \param interval Interval
746 \param maxMinSteps Maximum number of minor steps
747 \param stepSize Step size
748 \param ticks Arrays to be filled with the calculated ticks
749
750 \sa buildMajorTicks(), buildMinorTicks
751*/
752void QwtLog10ScaleEngine::buildTicks(
753 const QwtInterval& interval, double stepSize, int maxMinSteps,
754 QList<double> ticks[QwtScaleDiv::NTickTypes] ) const
755{
756 const QwtInterval boundingInterval = align( interval, stepSize );
757
758 ticks[QwtScaleDiv::MajorTick] =
759 buildMajorTicks( boundingInterval, stepSize );
760
761 if ( maxMinSteps > 0 )
762 {
763 ticks[QwtScaleDiv::MinorTick] = buildMinorTicks(
764 ticks[QwtScaleDiv::MajorTick], maxMinSteps, stepSize );
765 }
766
767 for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
768 ticks[i] = strip( ticks[i], interval );
769}
770
771/*!
772 \brief Calculate major ticks for an interval
773
774 \param interval Interval
775 \param stepSize Step size
776
777 \return Calculated ticks
778*/
779QList<double> QwtLog10ScaleEngine::buildMajorTicks(
780 const QwtInterval &interval, double stepSize ) const
781{
782 double width = log10( interval ).width();
783
784 int numTicks = qRound( width / stepSize ) + 1;
785 if ( numTicks > 10000 )
786 numTicks = 10000;
787
788 const double lxmin = ::log( interval.minValue() );
789 const double lxmax = ::log( interval.maxValue() );
790 const double lstep = ( lxmax - lxmin ) / double( numTicks - 1 );
791
792 QList<double> ticks;
793
794 ticks += interval.minValue();
795
796 for ( int i = 1; i < numTicks - 1; i++ )
797 ticks += qExp( lxmin + double( i ) * lstep );
798
799 ticks += interval.maxValue();
800
801 return ticks;
802}
803
804/*!
805 \brief Calculate minor/medium ticks for major ticks
806
807 \param majorTicks Major ticks
808 \param maxMinSteps Maximum number of minor steps
809 \param stepSize Step size
810*/
811QList<double> QwtLog10ScaleEngine::buildMinorTicks(
812 const QList<double> &majorTicks,
813 int maxMinSteps, double stepSize ) const
814{
815 if ( stepSize < 1.1 ) // major step width is one decade
816 {
817 if ( maxMinSteps < 1 )
818 return QList<double>();
819
820 int k0, kstep, kmax;
821
822 if ( maxMinSteps >= 8 )
823 {
824 k0 = 2;
825 kmax = 9;
826 kstep = 1;
827 }
828 else if ( maxMinSteps >= 4 )
829 {
830 k0 = 2;
831 kmax = 8;
832 kstep = 2;
833 }
834 else if ( maxMinSteps >= 2 )
835 {
836 k0 = 2;
837 kmax = 5;
838 kstep = 3;
839 }
840 else
841 {
842 k0 = 5;
843 kmax = 5;
844 kstep = 1;
845 }
846
847 QList<double> minorTicks;
848
849 for ( int i = 0; i < majorTicks.count(); i++ )
850 {
851 const double v = majorTicks[i];
852 for ( int k = k0; k <= kmax; k += kstep )
853 minorTicks += v * double( k );
854 }
855
856 return minorTicks;
857 }
858 else // major step > one decade
859 {
860 double minStep = divideInterval( stepSize, maxMinSteps );
861 if ( minStep == 0.0 )
862 return QList<double>();
863
864 if ( minStep < 1.0 )
865 minStep = 1.0;
866
867 // # subticks per interval
868 int nMin = qRound( stepSize / minStep ) - 1;
869
870 // Do the minor steps fit into the interval?
871
872 if ( qwtFuzzyCompare( ( nMin + 1 ) * minStep,
873 qAbs( stepSize ), stepSize ) > 0 )
874 {
875 nMin = 0;
876 }
877
878 if ( nMin < 1 )
879 return QList<double>(); // no subticks
880
881 // substep factor = 10^substeps
882 const qreal minFactor = qMax( qPow( 10.0, minStep ), qreal( 10.0 ) );
883
884 QList<double> minorTicks;
885 for ( int i = 0; i < majorTicks.count(); i++ )
886 {
887 double val = majorTicks[i];
888 for ( int k = 0; k < nMin; k++ )
889 {
890 val *= minFactor;
891 minorTicks += val;
892 }
893 }
894 return minorTicks;
895 }
896}
897
898/*!
899 \brief Align an interval to a step size
900
901 The limits of an interval are aligned that both are integer
902 multiples of the step size.
903
904 \param interval Interval
905 \param stepSize Step size
906
907 \return Aligned interval
908*/
909QwtInterval QwtLog10ScaleEngine::align(
910 const QwtInterval &interval, double stepSize ) const
911{
912 const QwtInterval intv = log10( interval );
913
914 double x1 = QwtScaleArithmetic::floorEps( intv.minValue(), stepSize );
915 if ( qwtFuzzyCompare( interval.minValue(), x1, stepSize ) == 0 )
916 x1 = interval.minValue();
917
918 double x2 = QwtScaleArithmetic::ceilEps( intv.maxValue(), stepSize );
919 if ( qwtFuzzyCompare( interval.maxValue(), x2, stepSize ) == 0 )
920 x2 = interval.maxValue();
921
922 return pow10( QwtInterval( x1, x2 ) );
923}
924
925/*!
926 Return the interval [log10(interval.minValue(), log10(interval.maxValue]
927*/
928
929QwtInterval QwtLog10ScaleEngine::log10( const QwtInterval &interval ) const
930{
931 return QwtInterval( ::log10( interval.minValue() ),
932 ::log10( interval.maxValue() ) );
933}
934
935/*!
936 Return the interval [pow10(interval.minValue(), pow10(interval.maxValue]
937*/
938QwtInterval QwtLog10ScaleEngine::pow10( const QwtInterval &interval ) const
939{
940 return QwtInterval( qPow( 10.0, interval.minValue() ),
941 qPow( 10.0, interval.maxValue() ) );
942}
Note: See TracBrowser for help on using the repository browser.