# 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         startAngle(-135 * 16),
    00028         endAngle(135 * 16)
    00029     {
    00030     }
    00031
    00032     QPoint center;
    00033     int radius;
    00034
    00035     int startAngle;
    00036     int endAngle;
    00037 };
    00038
    00046 QwtRoundScaleDraw::QwtRoundScaleDraw()
    00047 {
    00048     d_data = new QwtRoundScaleDraw::PrivateData;
    00049
    00050     setRadius(50);
    00051     scaleMap().setPaintInterval(d_data->startAngle, d_data->endAngle);
    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     d_data->startAngle = qRound(angle1 * 16.0);
    00141     d_data->endAngle = qRound(angle2 * 16.0);
    00142
    00143     if (d_data->startAngle == d_data->endAngle)
    00144     {
    00145         d_data->startAngle -= 1;
    00146         d_data->endAngle += 1;
    00147     }
    00148
    00149     scaleMap().setPaintInterval(d_data->startAngle, d_data->endAngle);
    00150 }
    00151
    00160 void QwtRoundScaleDraw::drawLabel(QPainter *painter, double value) const
    00161 {
    00162     const QwtText label = tickLabel(painter->font(), value);
    00163     if ( label.isEmpty() )
    00164         return;
    00165
    00166     const int tval = map().transform(value);
    00167     if ((tval > d_data->startAngle + 359 * 16)
    00168         || (tval < d_data->startAngle - 359 * 16))
    00169     {
    00170        return;
    00171     }
    00172
    00173     double radius = d_data->radius;
    00174     if ( hasComponent(QwtAbstractScaleDraw::Ticks) ||
    00175         hasComponent(QwtAbstractScaleDraw::Backbone) )
    00176     {
    00177         radius += spacing();
    00178     }
    00179
    00180     if ( hasComponent(QwtAbstractScaleDraw::Ticks) )
    00181         radius += majTickLength();
    00182
    00183     const QSize sz = label.textSize(painter->font());
    00184     const double arc = tval / 16.0 / 360.0 * 2 * M_PI;
    00185
    00186     const int x = d_data->center.x() +
    00187         qRound((radius + sz.width() / 2.0) * sin(arc));
    00188     const int y = d_data->center.y() -
    00189         qRound( (radius + sz.height() / 2.0) * cos(arc));
    00190
    00191     const QRect r(x - sz.width() / 2, y - sz.height() / 2,
    00192         sz.width(), sz.height() );
    00193     label.draw(painter, r);
    00194 }
    00195
    00205 void QwtRoundScaleDraw::drawTick(QPainter *painter, double value, int len) const
    00206 {
    00207     if ( len <= 0 )
    00208         return;
    00209
    00210     const int tval = map().transform(value);
    00211
    00212     const int cx = d_data->center.x();
    00213     const int cy = d_data->center.y();
    00214     const int radius = d_data->radius;
    00215
    00216     if ((tval <= d_data->startAngle + 359 * 16)
    00217         || (tval >= d_data->startAngle - 359 * 16))
    00218     {
    00219         const double arc = double(tval) / 16.0 * M_PI / 180.0;
    00220
    00221         const double sinArc = sin(arc);
    00222         const double cosArc = cos(arc);
    00223
    00224         const int x1 = qRound( cx + radius * sinArc );
    00225         const int x2 = qRound( cx + (radius + len) * sinArc );
    00226         const int y1 = qRound( cy - radius * cosArc );
    00227         const int y2 = qRound( cy - (radius + len) * cosArc );
    00228
    00229         QwtPainter::drawLine(painter, x1, y1, x2, y2);
    00230     }
    00231 }
    00232
    00239 void QwtRoundScaleDraw::drawBackbone(QPainter *painter) const
    00240 {
    00241     const int a1 = qRound(qwtMin(map().p1(), map().p2()) - 90 * 16);
    00242     const int a2 = qRound(qwtMax(map().p1(), map().p2()) - 90 * 16);
    00243
    00244     const int radius = d_data->radius;
    00245     const int x = d_data->center.x() - radius;
    00246     const int y = d_data->center.y() - radius;
    00247
    00248     painter->drawArc(x, y, 2 * radius, 2 * radius,
    00249         -a2, a2 - a1 + 1);           // counterclockwise
    00250 }
    00251
    00267 int QwtRoundScaleDraw::extent(const QPen &pen, const QFont &font) const
    00268 {
    00269     int d = 0;
    00270
    00271     if ( hasComponent(QwtAbstractScaleDraw::Labels) )
    00272     {
    00273         const QwtScaleDiv &sd = scaleDiv();
    00274         const QwtValueList &ticks = sd.ticks(QwtScaleDiv::MajorTick);
    00275         for (uint i = 0; i < (uint)ticks.count(); i++)
    00276         {
    00277             const double value = ticks[i];
    00278             if ( !sd.contains(value) )
    00279                 continue;
    00280
    00281             const QwtText label = tickLabel(font, value);
    00282             if ( label.isEmpty() )
    00283                 continue;
    00284
    00285             const int tval = map().transform(value);
    00286             if ((tval < d_data->startAngle + 360 * 16)
    00287                 && (tval > d_data->startAngle - 360 * 16))
    00288             {
    00289                 const double arc = tval / 16.0 / 360.0 * 2 * M_PI;
    00290
    00291                 const QSize sz = label.textSize(font);
    00292                 const double off = qwtMax(sz.width(), sz.height());
    00293
    00294                 double x = off * sin(arc);
    00295                 double y = off * cos(arc);
    00296
    00297                 const int dist = (int)ceil(sqrt(x * x + y * y) + 1 );
    00298                 if ( dist > d )
    00299                     d = dist;
    00300             }
    00301         }
    00302     }
    00303
    00304     if ( hasComponent(QwtAbstractScaleDraw::Ticks) )
    00305     {
    00306         d += majTickLength();
    00307     }
    00308
    00309     if ( hasComponent(QwtAbstractScaleDraw::Backbone) )
    00310     {
    00311         const int pw = qwtMax( 1, pen.width() );  // penwidth can be zero
    00312         d += pw;
    00313     }
    00314
    00315     if ( hasComponent(QwtAbstractScaleDraw::Labels) &&
    00316         ( hasComponent(QwtAbstractScaleDraw::Ticks) ||
    00317             hasComponent(QwtAbstractScaleDraw::Backbone) ) )
    00318     {
    00319         d += spacing();
    00320     }
    00321
    00322     d = qwtMax(d, minimumExtent());
    00323
    00324     return d;
    00325 }