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

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     const double arc = tval / 16.0 / 360.0 * 2 * M_PI;
00176 
00177     QRect r( QPoint(0, 0), label.textSize(painter->font()) );
00178     r.moveCenter(labelCenter(painter->font(), arc, label));
00179 
00180     label.draw(painter, r);
00181 }
00182 
00192 void QwtRoundScaleDraw::drawTick(QPainter *painter, double value, int len) const
00193 {
00194     if ( len <= 0 )
00195         return;
00196 
00197     const int tval = map().transform(value);
00198 
00199     const int cx = d_data->center.x();
00200     const int cy = d_data->center.y();
00201     const int radius = d_data->radius;
00202 
00203     if ((tval <= d_data->minAngle + 359 * 16)
00204         || (tval >= d_data->minAngle - 359 * 16))
00205     {
00206         const double arc = double(tval) / 16.0 * M_PI / 180.0;
00207 
00208         const double sinArc = sin(arc);
00209         const double cosArc = cos(arc);
00210 
00211         const int x1 = qRound( cx + radius * sinArc );
00212         const int x2 = qRound( cx + (radius + len) * sinArc );
00213         const int y1 = qRound( cy - radius * cosArc );
00214         const int y2 = qRound( cy - (radius + len) * cosArc );
00215 
00216         QwtPainter::drawLine(painter, x1, y1, x2, y2);
00217     }
00218 }
00219 
00226 void QwtRoundScaleDraw::drawBackbone(QPainter *painter) const
00227 {
00228     const int a1 = qRound(qwtMin(map().p1(), map().p2()) - 90 * 16);
00229     const int a2 = qRound(qwtMax(map().p1(), map().p2()) - 90 * 16);
00230 
00231     const int radius = d_data->radius;
00232     const int x = d_data->center.x() - radius;
00233     const int y = d_data->center.y() - radius;
00234 
00235     painter->drawArc(x, y, 2 * radius, 2 * radius,
00236         -a2, a2 - a1 + 1);           // counterclockwise
00237 }
00238 
00254 int QwtRoundScaleDraw::extent(const QPen &pen, const QFont &font) const
00255 {
00256     int d = 0;
00257 
00258     if ( hasComponent(QwtAbstractScaleDraw::Labels) )
00259     {
00260         const QwtScaleDiv &sd = scaleDiv();
00261         const QwtTickList &ticks = sd.ticks(QwtScaleDiv::MajorTick);
00262         for (uint i = 0; i < (uint)ticks.count(); i++)
00263         {
00264             const double v = ticks[i];
00265             if ( sd.contains(v) )
00266             {
00267                 const QRect r = labelRect(font, v);
00268                 if ( !r.isEmpty() )
00269                 {
00270                     int dx = r.center().x() - d_data->center.x();
00271                     int dy = r.center().y() - d_data->center.y();
00272 
00273                     const int dist1 = 
00274                         qRound(sqrt((double)(dx * dx + dy * dy)));
00275 
00276                     dx = r.width() / 2 + r.width() % 2;
00277                     dy = r.height() / 2 + r.height() % 2;
00278 
00279                     const int dist2 = 
00280                         qRound(sqrt((double)(dx * dx + dy * dy)));
00281 
00282                     int dist = dist1 + dist2;
00283                     if ( dist > d )
00284                         d = dist;
00285                 }
00286             }
00287         }
00288         d -= d_data->radius;
00289     }
00290 
00291     if ( d == 0 )
00292     {
00293         if ( hasComponent(QwtAbstractScaleDraw::Ticks) )
00294         {
00295             d += majTickLength();
00296         }
00297 
00298         if ( hasComponent(QwtAbstractScaleDraw::Backbone) )
00299         {
00300             const int pw = qwtMax( 1, pen.width() );  // penwidth can be zero
00301             d += pw;
00302         }
00303 
00304     }
00305     d = qwtMax(d, minimumExtent());
00306 
00307     return d;
00308 }
00309 
00316 QSize QwtRoundScaleDraw::labelSize(
00317     const QFont &font, double value) const
00318 {   
00319     return tickLabel(font, value).textSize(font);
00320 }
00321 
00330 QRect QwtRoundScaleDraw::labelRect(const QFont &font, double value) const
00331 {
00332     const QwtText label = tickLabel(font, value);
00333     if ( label.isEmpty() )
00334         return QRect(); 
00335 
00336     const int tval = map().transform(value);
00337     if ((tval > d_data->minAngle + 359 * 16)
00338         || (tval < d_data->minAngle - 359 * 16))
00339     {
00340        return QRect();
00341     }
00342 
00343     const double arc = tval / 16.0 / 360.0 * 2 * M_PI;
00344 
00345     QRect r( QPoint(0, 0), label.textSize(font) );
00346     r.moveCenter(labelCenter(font, arc, label));
00347 
00348     return r;
00349 }
00350 
00354 QPoint QwtRoundScaleDraw::labelCenter( 
00355     const QFont &font, double arc, const QwtText& label) const
00356 {   
00357     const QFont fnt = label.usedFont(font);
00358 
00359     QFontMetrics fm(fnt);
00360     const int fmh = fm.ascent() - 2;
00361 
00362     double radius = d_data->radius + spacing();
00363     if ( hasComponent(QwtAbstractScaleDraw::Ticks) )
00364         radius += majTickLength();
00365 
00366     // First we find the point on a circle enlarged
00367     // by half of the font height.
00368 
00369     double xOffset = ( radius + fmh / 2 ) * sin(arc);
00370     double yOffset = ( radius + fmh / 2 ) * cos(arc);
00371 
00372     if ( qRound(xOffset) != 0 )
00373     {
00374         // The centered label might cut the circle
00375         // with distance: d_data->radius + d_data->majLen + d_data->vpad
00376         // We align the label to the circle by moving
00377         // the x-coordinate, because we have only
00378         // horizontal labels here.
00379 
00380         const int brw = label.textSize(font).width();
00381 
00382         const double circleX = radius * sin(arc);
00383         if ( xOffset < 0 )
00384             xOffset = circleX - brw / 2; // left
00385         else
00386             xOffset = circleX + brw / 2; // right
00387     }
00388     const int x = d_data->center.x() + qRound(xOffset);
00389     const int y = d_data->center.y() - qRound(yOffset);
00390 
00391     return QPoint(x, y);
00392 }

Generated on Mon Jan 30 22:16:26 2006 for Qwt User's Guide by  doxygen 1.4.4