📄 qwt_scldraw.cpp
字号:
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/// vim: expandtab#include <qpainter.h>#include "qwt_math.h"#include "qwt_painter.h"#include "qwt_scldraw.h"#include "qwt_layout_metrics.h"static const double step_eps = 1.0e-6;/*! \brief Constructor The range of the scale is initialized to [0, 100], the angle range is set to [-135, 135], the geometry is initialized such that the origin is at (0,0), the length is 100, and the orientation is QwtScaleDraw::Bottom.*/QwtScaleDraw::QwtScaleDraw(): d_options(Backbone), d_hpad(4), d_vpad(4), d_medLen(6), d_majLen(8), d_minLen(4), d_minAngle(-135 * 16), d_maxAngle(135 * 16), d_fmt('g'), d_prec(4), d_fieldwidth(0), d_labelAlignment(0), d_labelRotation(0.0){ setGeometry(0,0,100,Bottom); setScale(0,100,0,0,10);}//! DestructorQwtScaleDraw::~QwtScaleDraw(){}void QwtScaleDraw::setOptions(int opt){ d_options = opt;}int QwtScaleDraw::options() const{ return d_options;}/*! \brief Adjust the range of the scale If step == 0.0, the step width is calculated automatically dependent on the maximal number of scale ticks. \param x1 Value at the left/low endpoint of the scale \param x2 Value at the right/high endpoint of the scale \param maxMajIntv Max. number of major step intervals \param maxMinIntv Max. number of minor step intervals \param step Step size (default : 0.0) \param logscale Logarithmic scale (default : 0)*/void QwtScaleDraw::setScale(double x1, double x2, int maxMajIntv, int maxMinIntv, double step, int logscale){ d_scldiv.rebuild( x1, x2, maxMajIntv, maxMinIntv, logscale, step, FALSE ); setDblRange( d_scldiv.lBound(), d_scldiv.hBound(), d_scldiv.logScale());}/*! \brief Change the scale division \param sd new scale division*/void QwtScaleDraw::setScale(const QwtScaleDiv &sd){ d_scldiv = sd; setDblRange(d_scldiv.lBound(),d_scldiv.hBound(),d_scldiv.logScale());}/*! \brief Draw the scale \param p the painter*/void QwtScaleDraw::draw(QPainter *p) const{ uint i; for (i=0; i< d_scldiv.majCnt(); i++) { const double val = d_scldiv.majMark(i); drawTick(p, val, d_majLen); drawLabel(p, val); } if (d_scldiv.logScale()) { for (i=0; i< d_scldiv.minCnt(); i++) drawTick(p, d_scldiv.minMark(i), d_minLen); } else { const int kmax = d_scldiv.majCnt() - 1; if (kmax > 0) { double majTick = d_scldiv.majMark(0); double hval = majTick - 0.5 * d_scldiv.majStep(); int k = 0; for (i=0; i< d_scldiv.minCnt(); i++) { const double val = d_scldiv.minMark(i); if (val > majTick) { if (k < kmax) { k++; majTick = d_scldiv.majMark(k); } else { majTick += d_scldiv.majMark(kmax) + d_scldiv.majStep(); } hval = majTick - 0.5 * d_scldiv.majStep(); } if (qwtAbs(val-hval) < step_eps * d_scldiv.majStep()) drawTick(p, val, d_medLen); else drawTick(p, val, d_minLen); } } } if ( options() & Backbone ) drawBackbone(p);}//! Draws a single scale tickvoid QwtScaleDraw::drawTick(QPainter *p, double val, int len) const{ if ( len <= 0 ) return; const int tval = transform(val); switch(d_orient) { case Left: QwtPainter::drawLine(p, d_xorg, tval, d_xorg - len, tval); break; case Right: QwtPainter::drawLine(p, d_xorg, tval, d_xorg + len, tval); break; case Bottom: QwtPainter::drawLine(p, tval, d_yorg, tval, d_yorg + len); break; case Top: QwtPainter::drawLine(p, tval, d_yorg, tval, d_yorg - len); break; case Round: if ((tval <= d_minAngle + 359 * 16) || (tval >= d_minAngle - 359 * 16)) { const double arc = double(tval) / 16.0 * M_PI / 180.0; const int x1 = qwtInt(d_xCenter + sin(arc) * d_radius); const int x2 = qwtInt(d_xCenter + sin(arc) * (d_radius + double(len))); const int y1 = qwtInt(d_yCenter - cos(arc) * d_radius); const int y2 = qwtInt(d_yCenter - cos(arc) * (d_radius + double(len))); QwtPainter::drawLine(p, x1, y1, x2, y2); } break; }}//! Draws the number label for a major scale tickvoid QwtScaleDraw::drawLabel(QPainter *p, double val) const{ QPoint pos; int alignment; double rotation; labelPlacement(QFontMetrics(p->font()), val, pos, alignment, rotation); if ( alignment ) { const QString txt = label(val); if ( !txt.isEmpty() ) { QWMatrix m = labelWorldMatrix(QFontMetrics(p->font()), pos, alignment, rotation, txt); p->save();#ifndef QT_NO_TRANSFORMATIONS p->setWorldMatrix(m, TRUE);#else p->translate(m.dx(), m.dy());#endif QwtPainter::drawText(p, 0, 0, txt); p->restore(); } }}//! Find position, alignment and rotation of the labelvoid QwtScaleDraw::labelPlacement( const QFontMetrics &fm, double val, QPoint &pos, int &alignment, double &rotation) const{ // correct rounding errors if val = 0 if ((!d_scldiv.logScale()) && (qwtAbs(val) < qwtAbs(step_eps * d_scldiv.majStep()))) { val = 0.0; } const int tval = transform(val); int x = 0; int y = 0; int align = 0; switch(d_orient) { case Right: { x = d_xorg + d_majLen + d_hpad + 1; y = tval; align = d_labelAlignment; if ( align == 0 ) align = Qt::AlignRight | Qt::AlignVCenter; break; } case Left: { x = d_xorg - d_majLen - d_hpad - 1; y = tval; align = d_labelAlignment; if ( align == 0 ) align = Qt::AlignLeft | Qt::AlignVCenter; break; } case Bottom: { x = tval; y = d_yorg + d_majLen + d_vpad + 1; align = d_labelAlignment; if ( align == 0 ) align = Qt::AlignHCenter | Qt::AlignBottom; break; } case Top: { x = tval; y = d_yorg - d_majLen - d_vpad - 1; align = d_labelAlignment; if ( align == 0 ) align = Qt::AlignHCenter | Qt::AlignTop; break; } case Round: { if ((tval > d_minAngle + 359 * 16) || (tval < d_minAngle - 359 * 16)) { break; } const int fmh = fm.ascent() - 2; const double arc = tval / 16.0 / 360.0 * 2 * M_PI; const double radius = d_radius + d_majLen + d_vpad; // First we find the point on a circle enlarged // by half of the font height. double xOffset = ( radius + fmh / 2 ) * sin(arc); double yOffset = ( radius + fmh / 2 ) * cos(arc); if ( qwtInt(xOffset) != 0 ) { // The centered label might cut the circle // with distance: d_radius + d_majLen + d_vpad // We align the label to the circle by moving // the x-coordinate, because we have only // horizontal labels here. const int fmw = fm.width(label(val)); const double circleX = radius * sin(arc); if ( xOffset < 0 ) xOffset = circleX - fmw / 2; // left else xOffset = circleX + fmw / 2; // right } x = qwtInt(d_xCenter + xOffset); y = qwtInt(d_yCenter - yOffset); align = Qt::AlignHCenter | Qt::AlignVCenter; break; } } pos = QPoint(x, y); alignment = align; rotation = d_labelRotation;}//! Return the world matrix for painting the label QWMatrix QwtScaleDraw::labelWorldMatrix(const QFontMetrics &fm, const QPoint &pos, int alignment, double rotation, const QString &txt) const{ const int w = fm.boundingRect(0, 0, QCOORD_MAX, QCOORD_MAX, 0, txt).width() - 2; const int h = fm.ascent() - 2; int x, y; if ( alignment & Qt::AlignLeft ) x = -w; else if ( alignment & Qt::AlignRight ) x = 0 - w % 2; else // Qt::AlignHCenter x = -(w / 2); if ( alignment & Qt::AlignTop ) y = 0; else if ( alignment & Qt::AlignBottom ) y = h - 1; else // Qt::AlignVCenter y = h / 2; QWMatrix m; m.translate(pos.x(), pos.y()); m.rotate(rotation); m.translate(x, y); return m;}//! Draws the baseline of the scalevoid QwtScaleDraw::drawBackbone(QPainter *p) const{ const int bw2 = p->pen().width() / 2; switch(d_orient) { case Left: QwtPainter::drawLine(p, d_xorg - bw2, d_yorg, d_xorg - bw2, d_yorg + d_len - 1); break; case Right: QwtPainter::drawLine(p, d_xorg + bw2, d_yorg, d_xorg + bw2, d_yorg + d_len - 1); break; case Top: QwtPainter::drawLine(p, d_xorg, d_yorg - bw2, d_xorg + d_len - 1, d_yorg - bw2); break; case Bottom: QwtPainter::drawLine(p, d_xorg, d_yorg + bw2, d_xorg + d_len - 1, d_yorg + bw2); break; case Round: { const int a1 = qwtMin(i1(), i2()) - 90 * 16; const int a2 = qwtMax(i1(), i2()) - 90 * 16; p->drawArc(d_xorg, d_yorg, d_len, d_len, -a2, a2 - a1 + 1); // counterclockwise break; } }}/*! \brief Specify the geometry of the scale The parameters xorigin, yorigin and length have different meanings, dependent on the orientation: <dl> <dt>QwtScaleDraw::Left <dd>The origin is the topmost point of the baseline. The baseline is a vertical line with the specified length. Scale marks and labels are drawn at the left of the baseline. <dt>QwtScaleDraw::Right <dd>The origin is the topmost point of the baseline. The baseline is a vertical line with the specified length. Scale marks and labels are drawn at the right of the baseline. <dt>QwtScaleDraw::Top <dd>The origin is the leftmost point of the baseline. The baseline is a horizontal line with the specified length. Scale marks and labels are drawn above the baseline. <dt>QwtScaleDraw::Bottom <dd>The origin is the leftmost point of the baseline. The baseline is a horizontal line with the specified length. Scale marks and labels are drawn below the baseline. <dt>QwtScaleDraw::Round <dd>The origin is the top left corner of the bounding rectangle of the baseline circle. The baseline is the segment of a circle with a diameter of the specified length. Scale marks and labels are drawn outside the baseline circle.</dl> \param xorigin x coordinate of the origin \param yorigin y coordinate of the origin \param length length or diameter of the scale, excluding border distance \param o The orientation*/void QwtScaleDraw::setGeometry(int xorigin, int yorigin, int length, Orientation o){ static int minLen = 10; d_xorg = xorigin; d_yorg = yorigin; d_radius = double(length) * 0.5; d_xCenter = double(xorigin) + double(length) * 0.5; d_yCenter = double(yorigin) + double(length) * 0.5; if (length > minLen) d_len = length; else d_len = minLen; d_orient = o; switch(d_orient) { case Left: case Right: setIntRange(d_yorg + d_len - 1, d_yorg); break; case Round: setIntRange(d_minAngle, d_maxAngle); break; case Top: case Bottom: setIntRange(d_xorg, d_xorg + d_len - 1); break; }}/*! \param pen pen \param fm font metrics \return the maximum width of the scale */int QwtScaleDraw::maxWidth(const QPen &pen, const QFontMetrics &fm) const{ int w = 0; switch (d_orient) { case Left: case Right: w += pen.width() + d_majLen + d_hpad + maxLabelWidth(fm); break; case Round: w += pen.width() + d_majLen + d_vpad + maxLabelWidth(fm); break; case Top: case Bottom: w = d_len + maxLabelWidth(fm); break; } return w;}/*! \param pen pen \param fm font metrics \return the maximum height of the scale*/int QwtScaleDraw::maxHeight(const QPen &pen, const QFontMetrics &fm) const { int h = 0; switch (d_orient) { case Top: case Bottom: h = pen.width() + d_vpad + d_majLen + maxLabelHeight(fm); break; case Left: case Right: h = d_len + maxLabelHeight(fm); break; case Round: h = d_vpad + d_majLen; if ( maxLabelHeight(fm) > 0 ) h += fm.ascent() - 2; break; } return h;}/*! Rotate all labels.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -