~ubuntu-branches/ubuntu/oneiric/qwt/oneiric-proposed

« back to all changes in this revision

Viewing changes to qwt-5.1.2/src/qwt_scale_engine.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2009-07-01 16:08:21 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20090701160821-gog44m4w7x2f4u6o
Tags: 5.2.0-1
* New upstream release.
* Add branch pull patch from svn r544.
* Bump Standards-Version to 3.8.2. No changes needed.
* Update installed manpages.
* Use qwt as base name for directory (drop version).
* Add missing warnings patch.
* Rewrite debian/rules: use dh.

Show diffs side-by-side

added added

removed removed

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