Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

# qwt_scldraw.cpp

    00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
    00002  * Qwt Widget Library
    00003  * Copyright (C) 1997   Josef Wilgen
    00004  * Copyright (C) 2002   Uwe Rathmann
    00005  *
    00006  * This library is free software; you can redistribute it and/or
    00007  * modify it under the terms of the Qwt License, Version 1.0
    00008  *****************************************************************************/
    00009
    00010 // vim: expandtab
    00011
    00012 #include <stdio.h>
    00013 #include <qpainter.h>
    00014 #include "qwt_math.h"
    00015 #include "qwt_painter.h"
    00016 #include "qwt_scldraw.h"
    00017 #include "qwt_layout_metrics.h"
    00018
    00019 static const double step_eps = 1.0e-6;
    00020
    00029 QwtScaleDraw::QwtScaleDraw():
    00030     d_options(Backbone),
    00031     d_hpad(4),
    00032     d_vpad(4),
    00033     d_medLen(6),
    00034     d_majLen(8),
    00035     d_minLen(4),
    00036     d_minAngle(-135 * 16),
    00037     d_maxAngle(135 * 16),
    00038     d_fmt('g'),
    00039     d_prec(4),
    00040     d_fieldwidth(0),
    00041     d_labelAlignment(0),
    00042     d_labelRotation(0.0)
    00043 {
    00044     // snprintf is C99 and therefore not portable :-(
    00045     // fieldwidth and precision must be in the range 0, 1, .., 99.
    00046     sprintf(d_formatBuffer, "%%%d.%d%c", d_fieldwidth, d_prec, d_fmt);
    00047     setGeometry(0,0,100,Bottom);
    00048     setScale(0,100,0,0,10);
    00049 }
    00050
    00052 QwtScaleDraw::~QwtScaleDraw()
    00053 {
    00054 }
    00055
    00057 void QwtScaleDraw::setOptions(int opt)
    00058 {
    00059     d_options = opt;
    00060 }
    00061
    00065 int QwtScaleDraw::options() const
    00066 {
    00067     return d_options;
    00068 }
    00069
    00082 void QwtScaleDraw::setScale(double x1, double x2, int maxMajIntv,
    00083                             int maxMinIntv, double step, int logscale)
    00084 {
    00085     d_scldiv.rebuild( x1, x2, maxMajIntv, maxMinIntv, logscale, step, FALSE );
    00086     setDblRange( d_scldiv.lBound(), d_scldiv.hBound(), d_scldiv.logScale());
    00087 }
    00088
    00089
    00094 void QwtScaleDraw::setScale(const QwtScaleDiv &sd)
    00095 {
    00096     d_scldiv = sd;
    00097     setDblRange(d_scldiv.lBound(),d_scldiv.hBound(),d_scldiv.logScale());
    00098 }
    00099
    00104 void QwtScaleDraw::draw(QPainter *p) const
    00105 {
    00106     uint i;
    00107
    00108     for (i=0; i< d_scldiv.majCnt(); i++)
    00109     {
    00110         const double val = d_scldiv.majMark(i);
    00111         drawTick(p, val, d_majLen);
    00112         drawLabel(p, val);
    00113     }
    00114
    00115     if (d_scldiv.logScale())
    00116     {
    00117         for (i=0; i< d_scldiv.minCnt(); i++)
    00118             drawTick(p, d_scldiv.minMark(i), d_minLen);
    00119     }
    00120     else
    00121     {
    00122         const int kmax = d_scldiv.majCnt() - 1;
    00123         if (kmax > 0)
    00124         {
    00125             double majTick = d_scldiv.majMark(0);
    00126             double hval = majTick - 0.5 * d_scldiv.majStep();
    00127
    00128             int k = 0;
    00129             for (i=0; i< d_scldiv.minCnt(); i++)
    00130             {
    00131                 const double val = d_scldiv.minMark(i);
    00132                 if  (val > majTick)
    00133                 {
    00134                     if (k < kmax)
    00135                     {
    00136                         k++;
    00137                         majTick = d_scldiv.majMark(k);
    00138                     }
    00139                     else
    00140                     {
    00141                         majTick += d_scldiv.majMark(kmax) + d_scldiv.majStep();
    00142                     }
    00143                     hval = majTick - 0.5 * d_scldiv.majStep();
    00144
    00145                 }
    00146                 if (qwtAbs(val-hval) < step_eps * d_scldiv.majStep())
    00147                     drawTick(p, val, d_medLen);
    00148                 else
    00149                     drawTick(p, val, d_minLen);
    00150             }
    00151         }
    00152     }
    00153
    00154     if ( options() & Backbone )
    00155         drawBackbone(p);
    00156 }
    00157
    00158
    00160 void QwtScaleDraw::drawTick(QPainter *p, double val, int len) const
    00161 {
    00162     if ( len <= 0 )
    00163         return;
    00164
    00165     const int tval = transform(val);
    00166
    00167     switch(d_orient)
    00168     {
    00169         case Left:
    00170             QwtPainter::drawLine(p, d_xorg, tval, d_xorg - len, tval);
    00171             break;
    00172
    00173         case Right:
    00174             QwtPainter::drawLine(p, d_xorg, tval, d_xorg + len, tval);
    00175             break;
    00176
    00177         case Bottom:
    00178             QwtPainter::drawLine(p, tval, d_yorg, tval, d_yorg + len);
    00179             break;
    00180
    00181         case Top:
    00182             QwtPainter::drawLine(p, tval, d_yorg, tval, d_yorg - len);
    00183             break;
    00184
    00185         case Round:
    00186             if ((tval <= d_minAngle + 359 * 16)
    00187                 || (tval >= d_minAngle - 359 * 16))
    00188             {
    00189                 const double arc = double(tval) / 16.0 * M_PI / 180.0;
    00190                 const int x1 = qwtInt(d_xCenter + sin(arc) * d_radius);
    00191                 const int x2 = qwtInt(d_xCenter + sin(arc)
    00192                     * (d_radius + double(len)));
    00193                 const int y1 = qwtInt(d_yCenter - cos(arc) * d_radius);
    00194                 const int y2 = qwtInt(d_yCenter - cos(arc)
    00195                     * (d_radius + double(len)));
    00196
    00197                 QwtPainter::drawLine(p, x1, y1, x2, y2);
    00198             }
    00199             break;
    00200     }
    00201 }
    00202
    00204 void QwtScaleDraw::drawLabel(QPainter *p, double val) const
    00205 {
    00206     QPoint pos;
    00207     int alignment;
    00208     double rotation;
    00209     labelPlacement(QFontMetrics(p->font()), val, pos, alignment, rotation);
    00210
    00211     if ( alignment )
    00212     {
    00213         const QString txt = label(val);
    00214         if ( !txt.isEmpty() )
    00215         {
    00216             QWMatrix m = labelWorldMatrix(QFontMetrics(p->font()),
    00217                 pos, alignment, rotation, txt);
    00218
    00219             p->save();
    00220 #ifndef QT_NO_TRANSFORMATIONS
    00221             p->setWorldMatrix(m, TRUE);
    00222 #else
    00223             p->translate(m.dx(), m.dy());
    00224 #endif
    00225             QwtPainter::drawText(p, 0, 0, txt);
    00226             p->restore();
    00227         }
    00228     }
    00229 }
    00230
    00232 void QwtScaleDraw::labelPlacement( const QFontMetrics &fm, double val,
    00233     QPoint &pos, int &alignment, double &rotation) const
    00234 {
    00235     // correct rounding errors if val = 0
    00236     if ((!d_scldiv.logScale())
    00237         && (qwtAbs(val) < qwtAbs(step_eps * d_scldiv.majStep())))
    00238     {
    00239        val = 0.0;
    00240     }
    00241
    00242     const int tval = transform(val);
    00243
    00244     int x = 0;
    00245     int y = 0;
    00246     int align = 0;
    00247
    00248     switch(d_orient)
    00249     {
    00250         case Right:
    00251         {
    00252             x = d_xorg + d_majLen + d_hpad + 1;
    00253             y = tval;
    00254             align = d_labelAlignment;
    00255             if ( align == 0 )
    00256                 align = Qt::AlignRight | Qt::AlignVCenter;
    00257             break;
    00258         }
    00259         case Left:
    00260         {
    00261             x = d_xorg - d_majLen - d_hpad - 1;
    00262             y = tval;
    00263             align = d_labelAlignment;
    00264             if ( align == 0 )
    00265                 align = Qt::AlignLeft | Qt::AlignVCenter;
    00266             break;
    00267         }
    00268         case Bottom:
    00269         {
    00270             x = tval;
    00271             y = d_yorg + d_majLen + d_vpad + 1;
    00272             align = d_labelAlignment;
    00273             if ( align == 0 )
    00274                 align = Qt::AlignHCenter | Qt::AlignBottom;
    00275             break;
    00276         }
    00277         case Top:
    00278         {
    00279             x = tval;
    00280             y = d_yorg - d_majLen - d_vpad - 1;
    00281             align = d_labelAlignment;
    00282             if ( align == 0 )
    00283                 align = Qt::AlignHCenter | Qt::AlignTop;
    00284             break;
    00285         }
    00286         case Round:
    00287         {
    00288             if ((tval > d_minAngle + 359 * 16)
    00289                 || (tval < d_minAngle - 359 * 16))
    00290             {
    00291                break;
    00292             }
    00293
    00294             const int fmh = fm.ascent() - 2;
    00295             const double arc = tval / 16.0 / 360.0 * 2 * M_PI;
    00296             const double radius = d_radius + d_majLen + d_vpad;
    00297
    00298             // First we find the point on a circle enlarged
    00299             // by half of the font height.
    00300
    00301             double xOffset = ( radius + fmh / 2 ) * sin(arc);
    00302             double yOffset = ( radius + fmh / 2 ) * cos(arc);
    00303
    00304             if ( qwtInt(xOffset) != 0 )
    00305             {
    00306                 // The centered label might cut the circle
    00307                 // with distance: d_radius + d_majLen + d_vpad
    00308                 // We align the label to the circle by moving
    00309                 // the x-coordinate, because we have only
    00310                 // horizontal labels here.
    00311
    00312                 const int fmw = fm.width(label(val));
    00313
    00314                 const double circleX = radius * sin(arc);
    00315                 if ( xOffset < 0 )
    00316                     xOffset = circleX - fmw / 2; // left
    00317                 else
    00318                     xOffset = circleX + fmw / 2; // right
    00319             }
    00320             x = qwtInt(d_xCenter + xOffset);
    00321             y = qwtInt(d_yCenter - yOffset);
    00322             align = Qt::AlignHCenter | Qt::AlignVCenter;
    00323
    00324             break;
    00325         }
    00326     }
    00327
    00328     pos = QPoint(x, y);
    00329     alignment = align;
    00330     rotation = d_labelRotation;
    00331 }
    00332
    00334
    00335 QWMatrix QwtScaleDraw::labelWorldMatrix(const QFontMetrics &fm,
    00336     const QPoint &pos, int alignment,
    00337 #ifdef QT_NO_TRANSFORMATIONS
    00338     double,
    00339 #else
    00340     double rotation,
    00341 #endif
    00342     const QString &txt) const
    00343 {
    00344     const int w = fm.boundingRect(0, 0,
    00345         QCOORD_MAX, QCOORD_MAX, 0, txt).width() - 2;
    00346     const int h = fm.ascent() - 2;
    00347
    00348     int x, y;
    00349     if ( alignment & Qt::AlignLeft )
    00350         x = -w;
    00351     else if ( alignment & Qt::AlignRight )
    00352         x = 0 - w % 2;
    00353     else // Qt::AlignHCenter
    00354         x = -(w / 2);
    00355
    00356     if ( alignment & Qt::AlignTop )
    00357         y = 0;
    00358     else if ( alignment & Qt::AlignBottom )
    00359         y = h - 1;
    00360     else // Qt::AlignVCenter
    00361         y = h / 2;
    00362
    00363     QWMatrix m;
    00364     m.translate(pos.x(), pos.y());
    00365 #ifndef QT_NO_TRANSFORMATIONS
    00366     m.rotate(rotation);
    00367 #endif
    00368     m.translate(x, y);
    00369
    00370     return m;
    00371 }
    00372
    00374 void QwtScaleDraw::drawBackbone(QPainter *p) const
    00375 {
    00376     const int bw2 = p->pen().width() / 2;
    00377
    00378     switch(d_orient)
    00379     {
    00380         case Left:
    00381             QwtPainter::drawLine(p, d_xorg - bw2,
    00382                 d_yorg, d_xorg - bw2, d_yorg + d_len - 1);
    00383             break;
    00384         case Right:
    00385             QwtPainter::drawLine(p, d_xorg + bw2,
    00386                 d_yorg, d_xorg + bw2, d_yorg + d_len - 1);
    00387             break;
    00388         case Top:
    00389             QwtPainter::drawLine(p, d_xorg, d_yorg - bw2,
    00390                 d_xorg + d_len - 1, d_yorg - bw2);
    00391             break;
    00392         case Bottom:
    00393             QwtPainter::drawLine(p, d_xorg, d_yorg + bw2,
    00394                 d_xorg + d_len - 1, d_yorg + bw2);
    00395             break;
    00396         case Round:
    00397         {
    00398             const int a1 = qwtMin(i1(), i2()) - 90 * 16;
    00399             const int a2 = qwtMax(i1(), i2()) - 90 * 16;
    00400
    00401             p->drawArc(d_xorg, d_yorg, d_len, d_len,
    00402                 -a2, a2 - a1 + 1);           // counterclockwise
    00403             break;
    00404         }
    00405     }
    00406 }
    00407
    00408
    00448 void QwtScaleDraw::setGeometry(int xorigin, int yorigin,
    00449     int length, Orientation o)
    00450 {
    00451     static int minLen = 10;
    00452
    00453     d_xorg = xorigin;
    00454     d_yorg = yorigin;
    00455     d_radius = double(length) * 0.5;
    00456     d_xCenter = double(xorigin) + double(length) * 0.5;
    00457     d_yCenter = double(yorigin) + double(length) * 0.5;
    00458
    00459     if (length > minLen)
    00460        d_len = length;
    00461     else
    00462        d_len = minLen;
    00463
    00464     d_orient = o;
    00465
    00466     switch(d_orient)
    00467     {
    00468         case Left:
    00469         case Right:
    00470             setIntRange(d_yorg + d_len - 1, d_yorg);
    00471             break;
    00472         case Round:
    00473             setIntRange(d_minAngle, d_maxAngle);
    00474             break;
    00475         case Top:
    00476         case Bottom:
    00477             setIntRange(d_xorg, d_xorg + d_len - 1);
    00478             break;
    00479     }
    00480 }
    00481
    00487 int QwtScaleDraw::maxWidth(const QPen &pen, const QFontMetrics &fm) const
    00488 {
    00489     int w = 0;
    00490
    00491     switch (d_orient)
    00492     {
    00493         case Left:
    00494         case Right:
    00495             w += pen.width() + d_majLen + d_hpad + maxLabelWidth(fm);
    00496             break;
    00497         case Round:
    00498             w += pen.width() + d_majLen + d_vpad + maxLabelWidth(fm);
    00499             break;
    00500         case Top:
    00501         case Bottom:
    00502             w = d_len + maxLabelWidth(fm);
    00503             break;
    00504     }
    00505     return w;
    00506 }
    00507
    00513 int QwtScaleDraw::maxHeight(const QPen &pen, const QFontMetrics &fm) const
    00514 {
    00515     int h = 0;
    00516
    00517     switch (d_orient)
    00518     {
    00519         case Top:
    00520         case Bottom:
    00521             h = pen.width() + d_vpad + d_majLen + maxLabelHeight(fm);
    00522             break;
    00523         case Left:
    00524         case Right:
    00525             h = d_len + maxLabelHeight(fm);
    00526             break;
    00527         case Round:
    00528             h = d_vpad + d_majLen;
    00529             if ( maxLabelHeight(fm) > 0 )
    00530                 h += fm.ascent() - 2;
    00531             break;
    00532     }
    00533
    00534     return h;
    00535 }
    00536
    00546 void QwtScaleDraw::setLabelRotation(double rotation)
    00547 {
    00548     d_labelRotation = rotation;
    00549 }
    00550
    00555 double QwtScaleDraw::labelRotation() const
    00556 {
    00557     return d_labelRotation;
    00558 }
    00559
    00579 void QwtScaleDraw::setLabelAlignment(int alignment)
    00580 {
    00581     d_labelAlignment = alignment;
    00582 }
    00583
    00588 int QwtScaleDraw::labelAlignment() const
    00589 {
    00590     return d_labelAlignment;
    00591 }
    00592
    00611 void QwtScaleDraw::setAngleRange(double angle1, double angle2)
    00612 {
    00613     angle1 = qwtLim(angle1, -360.0, 360.0);
    00614     angle2 = qwtLim(angle2, -360.0, 360.0);
    00615
    00616     int amin = int(floor (qwtMin(angle1, angle2) * 16.0 + 0.5));
    00617     int amax = int(floor (qwtMax(angle1, angle2) * 16.0 + 0.5));
    00618
    00619     if (amin == amax)
    00620     {
    00621         amin -= 1;
    00622         amax += 1;
    00623     }
    00624
    00625     d_minAngle = amin;
    00626     d_maxAngle = amax;
    00627     setIntRange(d_minAngle, d_maxAngle);
    00628 }
    00629
    00646 void QwtScaleDraw::setLabelFormat(char f, int prec, int fieldwidth)
    00647 {
    00648     switch(f)
    00649     {
    00650         case 'e':
    00651         case 'f':
    00652         case 'g':
    00653             d_fmt = f;
    00654             break;
    00655         default:
    00656             break;
    00657     }
    00658     if ((prec > -1) && (prec < 99))
    00659         d_prec = prec;
    00660     if ((fieldwidth > -1) && (fieldwidth < 99))
    00661         d_fieldwidth = fieldwidth;
    00662
    00663     sprintf(d_formatBuffer, "%%%d.%d%c", d_fieldwidth, d_prec, d_fmt);
    00664 }
    00665
    00679 void QwtScaleDraw::labelFormat(char &f, int &prec, int &fieldwidth) const
    00680 {
    00681     f = d_fmt;
    00682     prec = d_prec;
    00683     fieldwidth = d_fieldwidth;
    00684 }
    00685
    00692 void QwtScaleDraw::setMargin(uint hMargin, uint vMargin)
    00693 {
    00694     d_hpad = hMargin;
    00695     d_vpad = vMargin;
    00696 }
    00697
    00701 void QwtScaleDraw::setTickLength(unsigned int minLen,
    00702     unsigned int medLen, unsigned int majLen)
    00703 {
    00704     const unsigned int maxTickLen = 1000;
    00705
    00706     d_minLen = QMIN(minLen, maxTickLen);
    00707     d_medLen = QMIN(medLen, maxTickLen);
    00708     d_majLen = QMIN(majLen, maxTickLen);
    00709 }
    00710
    00715 void QwtScaleDraw::tickLength(unsigned int &minLen,
    00716         unsigned int &medLen, unsigned int &majLen) const
    00717 {
    00718     minLen = d_minLen;
    00719     medLen = d_medLen;
    00720     majLen = d_majLen;
    00721 }
    00722
    00727 unsigned int QwtScaleDraw::majTickLength() const
    00728 {
    00729     return d_majLen;
    00730 }
    00731
    00736 int QwtScaleDraw::maxLabelWidth(const QFontMetrics &fm) const
    00737 {
    00738     int maxWidth = 0;
    00739
    00740     for (uint i = 0; i < d_scldiv.majCnt(); i++)
    00741     {
    00742         double val = d_scldiv.majMark(i);
    00743
    00744         // correct rounding errors if val = 0
    00745
    00746         if ((!d_scldiv.logScale())
    00747             && (qwtAbs(val) < step_eps * qwtAbs(d_scldiv.majStep())))
    00748         {
    00749             val = 0.0;
    00750         }
    00751
    00752         const int w = labelBoundingRect(fm, val).width();
    00753         if ( w > maxWidth )
    00754             maxWidth = w;
    00755     }
    00756
    00757     return maxWidth;
    00758 }
    00759
    00764 int QwtScaleDraw::maxLabelHeight(const QFontMetrics &fm) const
    00765 {
    00766     int maxHeight = 0;
    00767
    00768     for (uint i = 0; i < d_scldiv.majCnt(); i++)
    00769     {
    00770         double val = d_scldiv.majMark(i);
    00771
    00772         // correct rounding errors if val = 0
    00773
    00774         if ((!d_scldiv.logScale())
    00775             && (qwtAbs(val) < step_eps * qwtAbs(d_scldiv.majStep())))
    00776         {
    00777             val = 0.0;
    00778         }
    00779
    00780         const int h = labelBoundingRect(fm, val).height();
    00781         if ( h > maxHeight )
    00782             maxHeight = h;
    00783     }
    00784
    00785     return maxHeight;
    00786 }
    00787
    00793 QRect QwtScaleDraw::labelBoundingRect(
    00794     const QFontMetrics &fm, double val) const
    00795 {
    00796     QString zeroString;
    00797     if ( d_fieldwidth > 0 )
    00798         zeroString.fill('0', d_fieldwidth);
    00799
    00800     const QString lbl = label(val);
    00801
    00802     const QString &txt = fm.width(zeroString) > fm.width(lbl)
    00803         ? zeroString : lbl;
    00804     if ( txt.isEmpty() )
    00805         return QRect(0, 0, 0, 0);
    00806
    00807     QRect br;
    00808
    00809     QPoint pos;
    00810     int alignment;
    00811     double rotation;
    00812
    00813     labelPlacement(fm, val, pos, alignment, rotation);
    00814     if ( alignment )
    00815     {
    00816         // Don't use fm.boundingRect(txt), it cuts off pixels.
    00817         const int w = fm.boundingRect(0, 0,
    00818             QCOORD_MAX, QCOORD_MAX, 0, txt).width();
    00819         const int h = -(fm.ascent() - 2);
    00820
    00821         QWMatrix m = labelWorldMatrix(fm, pos, alignment, rotation, txt);
    00822         br = QwtMetricsMap::translate(m, QRect(0, 0, w, h));
    00823         br.moveBy(-pos.x(), -pos.y());
    00824     }
    00825
    00826     return br;
    00827 }
    00828
    00839 void QwtScaleDraw::minBorderDist(const QFontMetrics &fm,
    00840     int &start, int &end ) const
    00841 {
    00842     start = 0;
    00843     end = 0;
    00844
    00845     if ( d_scldiv.majCnt() > 0 )
    00846     {
    00847         const QRect labelRectMin = labelBoundingRect(fm, d_scldiv.majMark(0));
    00848         const QRect labelRectMax = labelBoundingRect(fm,
    00849             d_scldiv.majMark(d_scldiv.majCnt() - 1));
    00850
    00851         switch (d_orient)
    00852         {
    00853             case Left:
    00854             case Right:
    00855                 end = -labelRectMin.y();
    00856                 start = labelRectMax.height() + labelRectMax.y();
    00857                 break;
    00858             case Top:
    00859             case Bottom:
    00860                 start = -labelRectMin.x();
    00861                 end = labelRectMax.width() + labelRectMax.x();
    00862                 break;
    00863             case Round:
    00864                 start = labelRectMin.width();
    00865                 end = labelRectMax.width();
    00866                 break;
    00867         }
    00868     }
    00869 }
    00870
    00880 int QwtScaleDraw::minLabelDist(const QFontMetrics &fm) const
    00881 {
    00882     if ( d_orient == Round ) // no implementation
    00883         return 0;
    00884
    00885     if (0 == d_scldiv.majCnt())
    00886     {
    00887         return 0;
    00888     }
    00889
    00890     const bool vertical = (d_orient == Left || d_orient == Right);
    00891
    00892     QRect bRect1;
    00893     QRect bRect2 = labelBoundingRect(fm, d_scldiv.majMark(0));
    00894     if ( vertical )
    00895     {
    00896         bRect2.setRect(-bRect2.bottom(), 0, bRect2.height(), bRect2.width());
    00897     }
    00898     int maxDist = 0;
    00899
    00900     for (uint i = 1; i < d_scldiv.majCnt(); i++ )
    00901     {
    00902         bRect1 = bRect2;
    00903         bRect2 = labelBoundingRect(fm, d_scldiv.majMark(i));
    00904         if ( vertical )
    00905         {
    00906             bRect2.setRect(-bRect2.bottom(), 0,
    00907                 bRect2.height(), bRect2.width());
    00908         }
    00909
    00910         int dist = fm.leading(); // space between the labels
    00911         if ( bRect1.right() > 0 )
    00912             dist += bRect1.right();
    00913         if ( bRect2.left() < 0 )
    00914             dist += -bRect2.left();
    00915
    00916         if ( dist > maxDist )
    00917             maxDist = dist;
    00918     }
    00919
    00920     double angle = d_labelRotation / 180.0 * M_PI;
    00921     if ( vertical )
    00922         angle += M_PI / 2;
    00923
    00924     if ( sin(angle) == 0.0 )
    00925         return maxDist;
    00926
    00927     const int fmHeight = fm.ascent() - 2;
    00928
    00929     // The distance we need until there is
    00930     // the height of the label font. This height is needed
    00931     // for the neighbour labal.
    00932
    00933     int labelDist = (int)(fmHeight / sin(angle) * cos(angle));
    00934     if ( labelDist < 0 )
    00935         labelDist = -labelDist;
    00936
    00937     // The cast above floored labelDist. We want to ceil.
    00938     labelDist++;
    00939
    00940     // For text orientations close to the scale orientation
    00941
    00942     if ( labelDist > maxDist )
    00943         labelDist = maxDist;
    00944
    00945     // For text orientations close to the opposite of the
    00946     // scale orientation
    00947
    00948     if ( labelDist < fmHeight )
    00949         labelDist = fmHeight;
    00950
    00951     return labelDist;
    00952 }
    00953
    00960 int QwtScaleDraw::minHeight( const QPen &pen, const QFontMetrics &fm ) const
    00961 {
    00962     const int pw = QMAX( 1, pen.width() );  // penwidth can be zero
    00963
    00964     int h = 0;
    00965     switch ( d_orient )
    00966     {
    00967         case Left:
    00968         case Right:
    00969         {
    00970             int bottomDist, topDist;
    00971             minBorderDist(fm, bottomDist, topDist);
    00972
    00973             h = bottomDist + topDist;
    00974             if ( d_scldiv.majCnt() >= 2 )
    00975                 h += minLabelDist(fm) * (d_scldiv.majCnt() - 1);
    00976
    00977             int th = 2 * (d_scldiv.majCnt() + d_scldiv.minCnt()) * pw;
    00978             if ( th > h )
    00979                 h = th;
    00980             break;
    00981         }
    00982         case Round:
    00983             // compute the radial thickness
    00984             h = pw + d_vpad + d_majLen + maxLabelWidth(fm);
    00985             break;
    00986         case Top:
    00987         case Bottom:
    00988             h = pw + d_vpad + d_majLen + maxLabelHeight(fm);
    00989             break;
    00990     }
    00991     return h;
    00992 }
    00993
    01000 int QwtScaleDraw::minWidth( const QPen &pen, const QFontMetrics &fm ) const
    01001 {
    01002     const int pw = QMAX( 1, pen.width() );  // penwidth can be zero
    01003
    01004     int w = 0;
    01005
    01006     switch(d_orient)
    01007     {
    01008         case Left:
    01009         case Right:
    01010         {
    01011             w = pw + d_hpad + d_majLen + maxLabelWidth(fm);
    01012             break;
    01013         }
    01014         case Round:
    01015         {
    01016             w = pw + d_vpad + d_majLen + maxLabelWidth(fm);
    01017             break;
    01018         }
    01019         case Top:
    01020         case Bottom:
    01021         {
    01022             int leftDist, rightDist;
    01023             minBorderDist(fm, leftDist, rightDist);
    01024
    01025             w = leftDist + rightDist +
    01026                 minLabelDist(fm) * (d_scldiv.majCnt() - 1);
    01027
    01028             int tw = 2 * (d_scldiv.majCnt() + d_scldiv.minCnt()) * pw;
    01029             if ( tw > w )
    01030                 w = tw;
    01031
    01032             break;
    01033         }
    01034     }
    01035     return w;
    01036 }
    01037
    01045 QString QwtScaleDraw::label(double value) const
    01046 {
    01047 #if 1
    01048     if ( value == -0 )
    01049         value = 0;
    01050 #endif
    01051
    01052     // snprintf is C99 and therefore not portable :-(
    01053     // sprintf is safe, when buffer is large enough for
    01054     // a minus sign, 99 digits, a radix symbol,
    01055     // an exponent character, a minus or plus sign, 3 digits,
    01056     // and a '\0'.
    01057     char buffer[128];
    01058     sprintf(buffer, d_formatBuffer, value);
    01059
    01060     return QString::fromLatin1(buffer);
    01061 }
    01062
    01064 int QwtScaleDraw::x() const
    01065 {
    01066     return d_xorg;
    01067 }
    01068
    01070 int QwtScaleDraw::y() const
    01071 {
    01072     return d_yorg;
    01073 }
    01074
    01076 int QwtScaleDraw::length() const
    01077 {
    01078     return d_len;
    01079 }
    01080
    01082 QwtScaleDraw::Orientation QwtScaleDraw::orientation() const
    01083 {
    01084     return d_orient;
    01085 }
    01086
    01087 // Local Variables:
    01088 // mode: C++
    01089 // c-file-style: "stroustrup"
    01090 // indent-tabs-mode: nil
    01091 // End: