00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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 ¢er)
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);
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() );
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
00367
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
00375
00376
00377
00378
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;
00385 else
00386 xOffset = circleX + brw / 2;
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 }