~l3on/ubuntu/oneiric/qwt/fix-921430

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2007-10-05 15:20:41 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20071005152041-qmybqh4fj9jejyo2
Tags: 5.0.2-2
* Handle nostrip build option. (Closes: #437877)
* Build libqwt5-doc package in binary-indep target. (Closes: #443110)

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
 
#if 1
312
 
    const double delta = (v == 0.0) ? 0.5 : qwtAbs(0.5 * v);
313
 
    return QwtDoubleInterval(v - delta, v + delta);
314
 
#else
315
 
    if ( v == 0.0 )
316
 
        return QwtDoubleInterval(-0.5, 0.5);
317
 
 
318
 
    return QwtDoubleInterval(0.5 * v, 1.5 * v);
319
 
#endif
320
 
}
321
 
 
322
 
/*!
323
 
  Change a scale attribute
324
 
 
325
 
  \param attribute Attribute to change
326
 
  \param on On/Off
327
 
 
328
 
  The behaviour of the scale engine can be changed
329
 
  with the following attributes:
330
 
  <dl>
331
 
  <dt>QwtAutoscale::IncludeReference
332
 
  <dd>Build a scale which includes the reference value.
333
 
  <dt>QwtScaleEngine::Symmetric
334
 
  <dd>Build a scale which is symmetric to the reference value.
335
 
  <dt>QwtScaleEngine::Floating
336
 
  <dd>The endpoints of the scale are supposed to be equal the outmost included
337
 
  values plus the specified margins (see setMargins()). If this attribute is
338
 
  *not* set, the endpoints of the scale will be integer multiples of the step
339
 
  size.
340
 
  <dt>QwtScaleEngine::Inverted
341
 
  <dd>Turn the scale upside down.
342
 
  </dl>
343
 
 
344
 
  \sa QwtScaleEngine::testAttribute()
345
 
*/
346
 
void QwtScaleEngine::setAttribute(Attribute attribute, bool on)
347
 
{
348
 
    if (on)
349
 
       d_data->attributes |= attribute;
350
 
    else
351
 
       d_data->attributes &= (~attribute);
352
 
}
353
 
 
354
 
/*!
355
 
  Check if a attribute is set.
356
 
 
357
 
  \param attribute Attribute to be tested
358
 
  \sa QwtScaleEngine::setAttribute() for a description of the possible options.
359
 
*/
360
 
bool QwtScaleEngine::testAttribute(Attribute attribute) const
361
 
{
362
 
    return bool(d_data->attributes & attribute);
363
 
}
364
 
 
365
 
/*!
366
 
  Change the scale attribute
367
 
 
368
 
  \param attributes Set scale attributes
369
 
  \sa QwtScaleEngine::attributes()
370
 
*/
371
 
void QwtScaleEngine::setAttributes(int attributes)
372
 
{
373
 
    d_data->attributes = attributes;
374
 
}
375
 
 
376
 
/*!
377
 
  Return the scale attributes
378
 
*/
379
 
int QwtScaleEngine::attributes() const
380
 
{
381
 
    return d_data->attributes;
382
 
}
383
 
 
384
 
/*!
385
 
  \brief Specify a reference point
386
 
  \param r new reference value
387
 
 
388
 
  The reference point is needed if options IncludeRef or
389
 
  Symmetric are active. Its default value is 0.0.
390
 
*/
391
 
void QwtScaleEngine::setReference(double r)
392
 
{
393
 
    d_data->referenceValue = r;
394
 
}
395
 
 
396
 
/*!
397
 
 \return the reference value
398
 
 \sa QwtScaleEngine::setReference(), QwtScaleEngine::setOptions()
399
 
*/
400
 
double QwtScaleEngine::reference() const 
401
 
402
 
    return d_data->referenceValue; 
403
 
}
404
 
 
405
 
/*!
406
 
  Return a transformation, for linear scales
407
 
*/
408
 
QwtScaleTransformation *QwtLinearScaleEngine::transformation() const
409
 
{
410
 
    return new QwtScaleTransformation(QwtScaleTransformation::Linear);
411
 
}
412
 
 
413
 
/*!
414
 
    Align and divide an interval 
415
 
 
416
 
   \param maxNumSteps Max. number of steps
417
 
   \param x1 First limit of the interval (In/Out)
418
 
   \param x2 Second limit of the interval (In/Out)
419
 
   \param stepSize Step size (Out)
420
 
 
421
 
   \sa QwtLinearScaleEngine::setAttribute
422
 
*/
423
 
void QwtLinearScaleEngine::autoScale(int maxNumSteps, 
424
 
    double &x1, double &x2, double &stepSize) const
425
 
{
426
 
    QwtDoubleInterval interval(x1, x2);
427
 
    interval = interval.normalized();
428
 
 
429
 
    interval.setMinValue(interval.minValue() - loMargin());
430
 
    interval.setMaxValue(interval.maxValue() + hiMargin());
431
 
 
432
 
    if (testAttribute(QwtScaleEngine::Symmetric))
433
 
        interval = interval.symmetrize(reference());
434
 
 
435
 
    if (testAttribute(QwtScaleEngine::IncludeReference))
436
 
        interval = interval.extend(reference());
437
 
 
438
 
    if (interval.width() == 0.0)
439
 
        interval = buildInterval(interval.minValue());
440
 
 
441
 
    stepSize = divideInterval(interval.width(), qwtMax(maxNumSteps, 1));
442
 
 
443
 
    if ( !testAttribute(QwtScaleEngine::Floating) )
444
 
        interval = align(interval, stepSize);
445
 
 
446
 
    x1 = interval.minValue();
447
 
    x2 = interval.maxValue();
448
 
 
449
 
    if (testAttribute(QwtScaleEngine::Inverted))
450
 
    {
451
 
        qSwap(x1, x2);
452
 
        stepSize = -stepSize;
453
 
    }
454
 
}
455
 
 
456
 
/*!
457
 
   \brief Calculate a scale division
458
 
 
459
 
   \param x1 First interval limit 
460
 
   \param x2 Second interval limit 
461
 
   \param maxMajSteps Maximum for the number of major steps
462
 
   \param maxMinSteps Maximum number of minor steps
463
 
   \param stepSize Step size. If stepSize == 0, the scaleEngine
464
 
                   calculates one.
465
 
 
466
 
   \sa QwtScaleEngine::stepSize, QwtScaleEngine::subDivide
467
 
*/
468
 
QwtScaleDiv QwtLinearScaleEngine::divideScale(double x1, double x2,
469
 
    int maxMajSteps, int maxMinSteps, double stepSize) const
470
 
{
471
 
    QwtDoubleInterval interval = QwtDoubleInterval(x1, x2).normalized();
472
 
    if (interval.width() <= 0 )
473
 
        return QwtScaleDiv();
474
 
 
475
 
    stepSize = qwtAbs(stepSize);
476
 
    if ( stepSize == 0.0 )
477
 
    {
478
 
        if ( maxMajSteps < 1 )
479
 
            maxMajSteps = 1;
480
 
 
481
 
        stepSize = divideInterval(interval.width(), maxMajSteps);
482
 
    }
483
 
 
484
 
    QwtScaleDiv scaleDiv;
485
 
 
486
 
    if ( stepSize != 0.0 )
487
 
    {
488
 
        QwtValueList ticks[QwtScaleDiv::NTickTypes];
489
 
        buildTicks(interval, stepSize, maxMinSteps, ticks);
490
 
 
491
 
        scaleDiv = QwtScaleDiv(interval, ticks);
492
 
    }
493
 
 
494
 
    if ( x1 > x2 )
495
 
        scaleDiv.invert();
496
 
 
497
 
    return scaleDiv;
498
 
}
499
 
 
500
 
void QwtLinearScaleEngine::buildTicks(
501
 
    const QwtDoubleInterval& interval, double stepSize, int maxMinSteps,
502
 
    QwtValueList ticks[QwtScaleDiv::NTickTypes]) const
503
 
{
504
 
    const QwtDoubleInterval boundingInterval =
505
 
        align(interval, stepSize);
506
 
    
507
 
    ticks[QwtScaleDiv::MajorTick] = 
508
 
        buildMajorTicks(boundingInterval, stepSize);
509
 
 
510
 
    if ( maxMinSteps > 0 )
511
 
    {
512
 
        buildMinorTicks(ticks[QwtScaleDiv::MajorTick], maxMinSteps, stepSize,
513
 
            ticks[QwtScaleDiv::MinorTick], ticks[QwtScaleDiv::MediumTick]);
514
 
    }
515
 
    
516
 
    for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
517
 
    {
518
 
        ticks[i] = strip(ticks[i], interval);
519
 
 
520
 
        // ticks very close to 0.0 are 
521
 
        // explicitely set to 0.0
522
 
 
523
 
        for ( int j = 0; j < (int)ticks[i].count(); j++ )
524
 
        {
525
 
            if ( QwtScaleArithmetic::compareEps(ticks[i][j], 0.0, stepSize) == 0 )
526
 
                ticks[i][j] = 0.0;
527
 
        }
528
 
    }
529
 
}
530
 
 
531
 
QwtValueList QwtLinearScaleEngine::buildMajorTicks(
532
 
    const QwtDoubleInterval &interval, double stepSize) const
533
 
{
534
 
    int numTicks = qRound(interval.width() / stepSize) + 1;
535
 
#if 1
536
 
    if ( numTicks > 10000 )
537
 
        numTicks = 10000;
538
 
#endif
539
 
 
540
 
    QwtValueList ticks;
541
 
 
542
 
    ticks += interval.minValue();
543
 
    for (int i = 1; i < numTicks - 1; i++)
544
 
        ticks += interval.minValue() + i * stepSize;
545
 
    ticks += interval.maxValue();
546
 
 
547
 
    return ticks;
548
 
}
549
 
 
550
 
void QwtLinearScaleEngine::buildMinorTicks(
551
 
    const QwtValueList& majorTicks,
552
 
    int maxMinSteps, double stepSize,
553
 
    QwtValueList &minorTicks, 
554
 
    QwtValueList &mediumTicks) const
555
 
{   
556
 
    double minStep = divideInterval(stepSize, maxMinSteps);
557
 
    if (minStep == 0.0)  
558
 
        return; 
559
 
        
560
 
    // # minor steps per interval
561
 
    int nMin = qwtAbs(qRound(stepSize / minStep)) - 1;
562
 
    
563
 
    // Do the minor steps fit into the interval?
564
 
    if ( QwtScaleArithmetic::compareEps((nMin +  1) * qwtAbs(minStep), 
565
 
        qwtAbs(stepSize), stepSize) > 0)
566
 
    {   
567
 
        nMin = 1;
568
 
        minStep = stepSize * 0.5;
569
 
    }
570
 
 
571
 
    int medIndex = -1;
572
 
    if ( nMin % 2 )
573
 
        medIndex = nMin / 2;
574
 
 
575
 
    // calculate minor ticks
576
 
 
577
 
    for (int i = 0; i < (int)majorTicks.count(); i++)
578
 
    {
579
 
        double val = majorTicks[i];
580
 
        for (int k=0; k< nMin; k++)
581
 
        {
582
 
            val += minStep;
583
 
 
584
 
            double alignedValue = val;
585
 
            if (QwtScaleArithmetic::compareEps(val, 0.0, stepSize) == 0) 
586
 
                alignedValue = 0.0;
587
 
 
588
 
            if ( k == medIndex )
589
 
                mediumTicks += alignedValue;
590
 
            else
591
 
                minorTicks += alignedValue;
592
 
        }
593
 
    }
594
 
}
595
 
 
596
 
/*!
597
 
  \brief Align an interval to a step size
598
 
 
599
 
  The limits of an interval are aligned that both are integer
600
 
  multiples of the step size.
601
 
 
602
 
  \param interval Interval
603
 
  \param stepSize Step size
604
 
 
605
 
  \return Aligned interval
606
 
*/
607
 
QwtDoubleInterval QwtLinearScaleEngine::align(
608
 
    const QwtDoubleInterval &interval, double stepSize) const
609
 
{
610
 
    const double x1 = 
611
 
        QwtScaleArithmetic::floorEps(interval.minValue(), stepSize);
612
 
    const double x2 = 
613
 
        QwtScaleArithmetic::ceilEps(interval.maxValue(), stepSize);
614
 
 
615
 
    return QwtDoubleInterval(x1, x2);
616
 
}
617
 
 
618
 
/*!
619
 
  Return a transformation, for logarithmic (base 10) scales
620
 
*/
621
 
QwtScaleTransformation *QwtLog10ScaleEngine::transformation() const
622
 
{
623
 
    return new QwtScaleTransformation(QwtScaleTransformation::Log10);
624
 
}
625
 
 
626
 
/*!
627
 
    Align and divide an interval
628
 
 
629
 
   \param maxNumSteps Max. number of steps
630
 
   \param x1 First limit of the interval (In/Out)
631
 
   \param x2 Second limit of the interval (In/Out)
632
 
   \param stepSize Step size (Out)
633
 
 
634
 
   \sa QwtScaleEngine::setAttribute
635
 
*/
636
 
void QwtLog10ScaleEngine::autoScale(int maxNumSteps, 
637
 
    double &x1, double &x2, double &stepSize) const
638
 
{
639
 
    if ( x1 > x2 )
640
 
        qSwap(x1, x2);
641
 
 
642
 
    QwtDoubleInterval interval(x1 / pow(10.0, loMargin()), 
643
 
        x2 * pow(10.0, hiMargin()) );
644
 
 
645
 
    double logRef = 1.0;
646
 
    if (reference() > LOG_MIN / 2)
647
 
        logRef = qwtMin(reference(), LOG_MAX / 2);
648
 
 
649
 
    if (testAttribute(QwtScaleEngine::Symmetric))
650
 
    {
651
 
        const double delta = qwtMax(interval.maxValue() / logRef,  
652
 
            logRef / interval.minValue());
653
 
        interval.setInterval(logRef / delta, logRef * delta);
654
 
    }
655
 
 
656
 
    if (testAttribute(QwtScaleEngine::IncludeReference))
657
 
        interval = interval.extend(logRef);
658
 
 
659
 
    interval = interval.limited(LOG_MIN, LOG_MAX);
660
 
 
661
 
    if (interval.width() == 0.0)
662
 
        interval = buildInterval(interval.minValue());
663
 
 
664
 
    stepSize = divideInterval(log10(interval).width(), qwtMax(maxNumSteps, 1));
665
 
    if ( stepSize < 1.0 )
666
 
        stepSize = 1.0;
667
 
 
668
 
    if (!testAttribute(QwtScaleEngine::Floating))
669
 
        interval = align(interval, stepSize);
670
 
 
671
 
    x1 = interval.minValue();
672
 
    x2 = interval.maxValue();
673
 
 
674
 
    if (testAttribute(QwtScaleEngine::Inverted))
675
 
    {
676
 
        qSwap(x1, x2);
677
 
        stepSize = -stepSize;
678
 
    }
679
 
}
680
 
 
681
 
/*!
682
 
   \brief Calculate a scale division
683
 
 
684
 
   \param x1 First interval limit 
685
 
   \param x2 Second interval limit 
686
 
   \param maxMajSteps Maximum for the number of major steps
687
 
   \param maxMinSteps Maximum number of minor steps
688
 
   \param stepSize Step size. If stepSize == 0, the scaleEngine
689
 
                   calculates one.
690
 
 
691
 
   \sa QwtScaleEngine::stepSize, QwtLog10ScaleEngine::subDivide
692
 
*/
693
 
QwtScaleDiv QwtLog10ScaleEngine::divideScale(double x1, double x2,
694
 
    int maxMajSteps, int maxMinSteps, double stepSize) const
695
 
{
696
 
    QwtDoubleInterval interval = QwtDoubleInterval(x1, x2).normalized();
697
 
    interval = interval.limited(LOG_MIN, LOG_MAX);
698
 
 
699
 
    if (interval.width() <= 0 )
700
 
        return QwtScaleDiv();
701
 
 
702
 
    if (interval.maxValue() / interval.minValue() < 10.0)
703
 
    {
704
 
        // scale width is less than one decade -> build linear scale
705
 
    
706
 
        QwtLinearScaleEngine linearScaler;
707
 
        linearScaler.setAttributes(attributes());
708
 
        linearScaler.setReference(reference());
709
 
        linearScaler.setMargins(loMargin(), hiMargin());
710
 
 
711
 
        return linearScaler.divideScale(x1, x2, 
712
 
            maxMajSteps, maxMinSteps, stepSize);
713
 
    }
714
 
 
715
 
    stepSize = qwtAbs(stepSize);
716
 
    if ( stepSize == 0.0 )
717
 
    {
718
 
        if ( maxMajSteps < 1 )
719
 
            maxMajSteps = 1;
720
 
 
721
 
        stepSize = divideInterval(log10(interval).width(), maxMajSteps);
722
 
        if ( stepSize < 1.0 )
723
 
            stepSize = 1.0; // major step must be >= 1 decade
724
 
    }
725
 
 
726
 
    QwtScaleDiv scaleDiv;
727
 
    if ( stepSize != 0.0 )
728
 
    {
729
 
        QwtValueList ticks[QwtScaleDiv::NTickTypes];
730
 
        buildTicks(interval, stepSize, maxMinSteps, ticks);
731
 
 
732
 
        scaleDiv = QwtScaleDiv(interval, ticks);
733
 
    }
734
 
 
735
 
    if ( x1 > x2 )
736
 
        scaleDiv.invert();
737
 
 
738
 
    return scaleDiv;
739
 
}
740
 
 
741
 
void QwtLog10ScaleEngine::buildTicks(
742
 
    const QwtDoubleInterval& interval, double stepSize, int maxMinSteps,
743
 
    QwtValueList ticks[QwtScaleDiv::NTickTypes]) const
744
 
{
745
 
    const QwtDoubleInterval boundingInterval =
746
 
        align(interval, stepSize);
747
 
    
748
 
    ticks[QwtScaleDiv::MajorTick] = 
749
 
        buildMajorTicks(boundingInterval, stepSize);
750
 
 
751
 
    if ( maxMinSteps > 0 )
752
 
    {
753
 
        ticks[QwtScaleDiv::MinorTick] = buildMinorTicks(
754
 
            ticks[QwtScaleDiv::MajorTick], maxMinSteps, stepSize);
755
 
    }
756
 
    
757
 
    for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
758
 
        ticks[i] = strip(ticks[i], interval);
759
 
}
760
 
 
761
 
QwtValueList QwtLog10ScaleEngine::buildMajorTicks(
762
 
    const QwtDoubleInterval &interval, double stepSize) const
763
 
{
764
 
    double width = log10(interval).width();
765
 
 
766
 
    int numTicks = qRound(width / stepSize) + 1;
767
 
    if ( numTicks > 10000 )
768
 
        numTicks = 10000;
769
 
 
770
 
    const double lxmin = log(interval.minValue());
771
 
    const double lxmax = log(interval.maxValue());
772
 
    const double lstep = (lxmax - lxmin) / double(numTicks - 1);
773
 
 
774
 
    QwtValueList ticks;
775
 
 
776
 
    ticks += interval.minValue();
777
 
 
778
 
    for (int i = 1; i < numTicks; i++)
779
 
       ticks += exp(lxmin + double(i) * lstep);
780
 
 
781
 
    ticks += interval.maxValue();
782
 
 
783
 
    return ticks;
784
 
}
785
 
 
786
 
QwtValueList QwtLog10ScaleEngine::buildMinorTicks(
787
 
    const QwtValueList &majorTicks, 
788
 
    int maxMinSteps, double stepSize) const
789
 
{   
790
 
    if (stepSize < 1.1)            // major step width is one decade
791
 
    {
792
 
        if ( maxMinSteps < 1 )
793
 
            return QwtValueList();
794
 
            
795
 
        int k0, kstep, kmax;
796
 
        
797
 
        if (maxMinSteps >= 8)
798
 
        {
799
 
            k0 = 2;
800
 
            kmax = 9;
801
 
            kstep = 1;
802
 
        }   
803
 
        else if (maxMinSteps >= 4)
804
 
        {
805
 
            k0 = 2;
806
 
            kmax = 8;
807
 
            kstep = 2;
808
 
        }   
809
 
        else if (maxMinSteps >= 2)
810
 
        {
811
 
            k0 = 2;
812
 
            kmax = 5;
813
 
            kstep = 3;
814
 
        }
815
 
        else
816
 
        {
817
 
            k0 = 5;
818
 
            kmax = 5;
819
 
            kstep = 1;
820
 
        }
821
 
 
822
 
        QwtValueList minorTicks;
823
 
 
824
 
        for (int i = 0; i < (int)majorTicks.count(); i++)
825
 
        {
826
 
            const double v = majorTicks[i];
827
 
            for (int k = k0; k<= kmax; k+=kstep)
828
 
                minorTicks += v * double(k);
829
 
        }
830
 
 
831
 
        return minorTicks;
832
 
    }
833
 
    else  // major step > one decade
834
 
    {
835
 
        double minStep = divideInterval(stepSize, maxMinSteps);
836
 
        if ( minStep == 0.0 )
837
 
            return QwtValueList();
838
 
 
839
 
        if ( minStep < 1.0 )
840
 
            minStep = 1.0;
841
 
 
842
 
        // # subticks per interval
843
 
        int nMin = qRound(stepSize / minStep) - 1;
844
 
 
845
 
        // Do the minor steps fit into the interval?
846
 
 
847
 
        if ( QwtScaleArithmetic::compareEps((nMin +  1) * minStep, 
848
 
            qwtAbs(stepSize), stepSize) > 0)
849
 
        {
850
 
            nMin = 0;
851
 
        }
852
 
 
853
 
        if (nMin < 1)
854
 
            return QwtValueList();      // no subticks
855
 
 
856
 
        // substep factor = 10^substeps
857
 
        const double minFactor = qwtMax(pow(10.0, minStep), 10.0);
858
 
 
859
 
        QwtValueList minorTicks;
860
 
        for (int i = 0; i < (int)majorTicks.count(); i++)
861
 
        {
862
 
            double val = majorTicks[i];
863
 
            for (int k=0; k< nMin; k++)
864
 
            {
865
 
                val *= minFactor;
866
 
                minorTicks += val;
867
 
            }
868
 
        }
869
 
        return minorTicks;
870
 
    }
871
 
}
872
 
 
873
 
/*!
874
 
  \brief Align an interval to a step size
875
 
 
876
 
  The limits of an interval are aligned that both are integer
877
 
  multiples of the step size.
878
 
 
879
 
  \param interval Interval
880
 
  \param stepSize Step size
881
 
 
882
 
  \return Aligned interval
883
 
*/
884
 
QwtDoubleInterval QwtLog10ScaleEngine::align(
885
 
    const QwtDoubleInterval &interval, double stepSize) const
886
 
{
887
 
    const QwtDoubleInterval intv = log10(interval);
888
 
 
889
 
    const double x1 = QwtScaleArithmetic::floorEps(intv.minValue(), stepSize);
890
 
    const double x2 = QwtScaleArithmetic::ceilEps(intv.maxValue(), stepSize);
891
 
 
892
 
    return pow10(QwtDoubleInterval(x1, x2));
893
 
}
894
 
 
895
 
/*!
896
 
  Return the interval [log10(interval.minValue(), log10(interval.maxValue]
897
 
*/
898
 
 
899
 
QwtDoubleInterval QwtLog10ScaleEngine::log10(
900
 
    const QwtDoubleInterval &interval) const
901
 
{
902
 
    return QwtDoubleInterval(::log10(interval.minValue()),
903
 
            ::log10(interval.maxValue()));
904
 
}
905
 
 
906
 
/*!
907
 
  Return the interval [pow10(interval.minValue(), pow10(interval.maxValue]
908
 
*/
909
 
QwtDoubleInterval QwtLog10ScaleEngine::pow10(
910
 
    const QwtDoubleInterval &interval) const
911
 
{
912
 
    return QwtDoubleInterval(pow(10.0, interval.minValue()),
913
 
            pow(10.0, interval.maxValue()));
914
 
}