# qwt_round_scale_draw.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 <math.h>
    00013 #include <qpen.h>
    00014 #include <qpainter.h>
    00015 #include <qfontmetrics.h>
    00016 #include "qwt_painter.h"
    00017 #include "qwt_scale_div.h"
    00018 #include "qwt_scale_map.h"
    00019 #include "qwt_round_scale_draw.h"
    00020
    00021 class QwtRoundScaleDraw::PrivateData
    00022 {
    00023 public:
    00024     PrivateData():
    00025         center(50, 50),
    00026         radius(50),
    00027         minAngle(-135 * 16),
    00028         maxAngle(135 * 16)
    00029     {
    00030     }
    00031
    00032     QPoint center;
    00033     int radius;
    00034
    00035     int minAngle;
    00036     int maxAngle;
    00037 };
    00038
    00046 QwtRoundScaleDraw::QwtRoundScaleDraw()
    00047 {
    00048     d_data = new QwtRoundScaleDraw::PrivateData;
    00049
    00050     setRadius(50);
    00051     scaleMap().setPaintInterval(d_data->minAngle, d_data->maxAngle);
    00052 }
    00053
    00055 QwtRoundScaleDraw::QwtRoundScaleDraw(const QwtRoundScaleDraw &other):
    00056     QwtAbstractScaleDraw(other)
    00057 {
    00058     d_data = new QwtRoundScaleDraw::PrivateData(*other.d_data);
    00059 }
    00060
    00061
    00063 QwtRoundScaleDraw::~QwtRoundScaleDraw()
    00064 {
    00065     delete d_data;
    00066 }
    00067
    00069 QwtRoundScaleDraw &QwtRoundScaleDraw::operator=(const QwtRoundScaleDraw &other)
    00070 {
    00071     *(QwtAbstractScaleDraw*)this = (const QwtAbstractScaleDraw &)other;
    00072     *d_data = *other.d_data;
    00073     return *this;
    00074 }
    00075
    00084 void QwtRoundScaleDraw::setRadius(int radius)
    00085 {
    00086     d_data->radius = radius;
    00087 }
    00088
    00096 int QwtRoundScaleDraw::radius() const
    00097 {
    00098     return d_data->radius;
    00099 }
    00100
    00107 void QwtRoundScaleDraw::moveCenter(const QPoint &center)
    00108 {
    00109     d_data->center = center;
    00110 }
    00111
    00113 QPoint QwtRoundScaleDraw::center() const
    00114 {
    00115     return d_data->center;
    00116 }
    00117
    00135 void QwtRoundScaleDraw::setAngleRange(double angle1, double angle2)
    00136 {
    00137     angle1 = qwtLim(angle1, -360.0, 360.0);
    00138     angle2 = qwtLim(angle2, -360.0, 360.0);
    00139
    00140     int amin = qRound(qwtMin(angle1, angle2) * 16.0);
    00141     int amax = qRound(qwtMax(angle1, angle2) * 16.0);
    00142
    00143     if (amin == amax)
    00144     {
    00145         amin -= 1;
    00146         amax += 1;
    00147     }
    00148
    00149     d_data->minAngle = amin;
    00150     d_data->maxAngle = amax;
    00151     scaleMap().setPaintInterval(d_data->minAngle, d_data->maxAngle);
    00152 }
    00153
    00162 void QwtRoundScaleDraw::drawLabel(QPainter *painter, double value) const
    00163 {
    00164     const QwtText label = tickLabel(painter->font(), value);
    00165     if ( label.isEmpty() )
    00166         return;
    00167
    00168     const int tval = map().transform(value);
    00169     if ((tval > d_data->minAngle + 359 * 16)
    00170         || (tval < d_data->minAngle - 359 * 16))
    00171     {
    00172        return;
    00173     }
    00174
    00175     double radius = d_data->radius;
    00176     if ( hasComponent(QwtAbstractScaleDraw::Ticks) ||
    00177         hasComponent(QwtAbstractScaleDraw::Backbone) )
    00178     {
    00179         radius += spacing();
    00180     }
    00181
    00182     if ( hasComponent(QwtAbstractScaleDraw::Ticks) )
    00183         radius += majTickLength();
    00184
    00185     const QSize sz = label.textSize(painter->font());
    00186     const double arc = tval / 16.0 / 360.0 * 2 * M_PI;
    00187
    00188     const int x = d_data->center.x() +
    00189         qRound((radius + sz.width() / 2.0) * sin(arc));
    00190     const int y = d_data->center.y() -
    00191         qRound( (radius + sz.height() / 2.0) * cos(arc));
    00192
    00193     const QRect r(x - sz.width() / 2, y - sz.height() / 2,
    00194         sz.width(), sz.height() );
    00195     label.draw(painter, r);
    00196 }
    00197
    00207 void QwtRoundScaleDraw::drawTick(QPainter *painter, double value, int len) const
    00208 {
    00209     if ( len <= 0 )
    00210         return;
    00211
    00212     const int tval = map().transform(value);
    00213
    00214     const int cx = d_data->center.x();
    00215     const int cy = d_data->center.y();
    00216     const int radius = d_data->radius;
    00217
    00218     if ((tval <= d_data->minAngle + 359 * 16)
    00219         || (tval >= d_data->minAngle - 359 * 16))
    00220     {
    00221         const double arc = double(tval) / 16.0 * M_PI / 180.0;
    00222
    00223         const double sinArc = sin(arc);
    00224         const double cosArc = cos(arc);
    00225
    00226         const int x1 = qRound( cx + radius * sinArc );
    00227         const int x2 = qRound( cx + (radius + len) * sinArc );
    00228         const int y1 = qRound( cy - radius * cosArc );
    00229         const int y2 = qRound( cy - (radius + len) * cosArc );
    00230
    00231         QwtPainter::drawLine(painter, x1, y1, x2, y2);
    00232     }
    00233 }
    00234
    00241 void QwtRoundScaleDraw::drawBackbone(QPainter *painter) const
    00242 {
    00243     const int a1 = qRound(qwtMin(map().p1(), map().p2()) - 90 * 16);
    00244     const int a2 = qRound(qwtMax(map().p1(), map().p2()) - 90 * 16);
    00245
    00246     const int radius = d_data->radius;
    00247     const int x = d_data->center.x() - radius;
    00248     const int y = d_data->center.y() - radius;
    00249
    00250     painter->drawArc(x, y, 2 * radius, 2 * radius,
    00251         -a2, a2 - a1 + 1);           // counterclockwise
    00252 }
    00253
    00269 int QwtRoundScaleDraw::extent(const QPen &pen, const QFont &font) const
    00270 {
    00271     int d = 0;
    00272
    00273     if ( hasComponent(QwtAbstractScaleDraw::Labels) )
    00274     {
    00275         const QwtScaleDiv &sd = scaleDiv();
    00276         const QwtValueList &ticks = sd.ticks(QwtScaleDiv::MajorTick);
    00277         for (uint i = 0; i < (uint)ticks.count(); i++)
    00278         {
    00279             const double value = ticks[i];
    00280             if ( !sd.contains(value) )
    00281                 continue;
    00282
    00283             const QwtText label = tickLabel(font, value);
    00284             if ( label.isEmpty() )
    00285                 continue;
    00286
    00287             const int tval = map().transform(value);
    00288             if ((tval < d_data->minAngle + 360 * 16)
    00289                 && (tval > d_data->minAngle - 360 * 16))
    00290             {
    00291                 const double arc = tval / 16.0 / 360.0 * 2 * M_PI;
    00292
    00293                 const QSize sz = label.textSize(font);
    00294                 const double off = qwtMax(sz.width(), sz.height());
    00295
    00296                 double x = off * sin(arc);
    00297                 double y = off * cos(arc);
    00298
    00299                 const int dist = (int)ceil(sqrt(x * x + y * y) + 1 );
    00300                 if ( dist > d )
    00301                     d = dist;
    00302             }
    00303         }
    00304     }
    00305
    00306     if ( hasComponent(QwtAbstractScaleDraw::Ticks) )
    00307     {
    00308         d += majTickLength();
    00309     }
    00310
    00311     if ( hasComponent(QwtAbstractScaleDraw::Backbone) )
    00312     {
    00313         const int pw = qwtMax( 1, pen.width() );  // penwidth can be zero
    00314         d += pw;
    00315     }
    00316
    00317     if ( hasComponent(QwtAbstractScaleDraw::Labels) &&
    00318         ( hasComponent(QwtAbstractScaleDraw::Ticks) ||
    00319             hasComponent(QwtAbstractScaleDraw::Backbone) ) )
    00320     {
    00321         d += spacing();
    00322     }
    00323
    00324     d = qwtMax(d, minimumExtent());
    00325
    00326     return d;
    00327 }