QPaint练习000(绘制坐标轴+码表盘)

参考

参考

mychart.h

#ifndef MYCHART_H
#define MYCHART_H#include <QWidget>
#include <QPainter>
#include <QString>struct DataNode
{int value;QString key;
};typedef struct {QString label;double  width;QColor  color;
} CvsInfo;// MyChart继承自QWidget类,是一个窗口小部件。
class MyChart : public QWidget
{Q_OBJECT
public:// `explicit` 是 C++ 中的一个关键字,用于修饰类的构造函数,表示该构造函数只能用于显式地创建对象,不能被隐式地调用。// 只能通过MyChart painter = MyChart(parent)的方式显式地创建一个 `MyChart` 对象:// `parent` 参数的默认值为 `nullptr`,这表示如果没有提供父部件的指针,那么 `MyChart` 就没有父部件,即它是一个独立的窗口部件。explicit MyChart(QWidget *parent = nullptr);~MyChart();void updateValue(const DataNode &node);void AxisCurvesUpdate(const QList<QPoint> & pointList);// 坐标轴参数初始化设置typedef struct {QString titleX;quint32 durationX;QString titleYl;quint32 durationYl;QString titleYr;quint32 dudrationYr;} AxisInfo;// 坐标参数初始化设置typedef struct {QPointF spMin;QPointF spMax;QVector<QPointF> sp;QPointF epMin;QPointF epMax;QVector<QPointF> ep;} MyGtChartAxisYScalesInfo;// 坐标轴初始化设置void AxisInit(const AxisInfo & info);// 曲线参数初始化设置void AxisCurvesAppend(const QString & label, double width, QColor color);// 曲线标题显示与设置void AxisCurvesTitleSet();// 坐标轴刻度线设置void AxisScalesLineSet();// 坐标轴刻度值刷新void AxisScalesValueSet();// 坐标轴标题设置void MyChartTitileSet(QPainter & painter, const QPoint &point, const QString &title, const QColor & color, const qreal & fontSize);// 坐标轴标题设置void AxisTitleSet();// 坐标轴初始化设置void AxisInitSet();// 创建坐标轴void AxisCreateTest();// 曲线坐标点刷新void AxisPointsUpdate(QVector<QList<QPoint>> &pointList);// 平滑曲线绘制void SmoothCurvesDrawTest(const QColor &color, qreal &width, const QList<QPoint> &pointList);// 左侧y轴弧线绘制,刻度点记录void AxisYlArcDrawWidthScales(QPainter &painter, int offsetX, int diameters, int tickCount, int margin);// 右侧y轴弧线绘制,刻度点记录void AxisYrArcDrawWidthScales(QPainter &painter, int offsetX, int diameters, int tickCount, int margin);// 曲线图刷新void ChartViewUpdate();void drawArcAtWidget(QPainter * painter, const QPoint& center, int radius);// 右侧码表    //绘制实时时速数字void DrawDbNum(QPainter& painter, QPoint & point);// 绘制一条中间略粗两边略尖的渐变发光线条void DrawDbLightLine(QPainter& painter, QPoint & point);// 中间小圆void DrawCircle_bom_small(QPainter& painter, QPoint & center, int radius);//渐变发光内圈void DrawCircle_bom_shine(QPainter &painter, QPoint &center, int radius);// 最外细圆线void DrawCircle_line(QPainter& painter, QPoint &center, int radius, int width);// 绘制指针void DrawPointer(QPainter& painter, QPoint &center, int radius, int degRotate);// 动态扇形环void DrawCircle_arc(QPainter& painter, QPoint &center, int radius, int degRotate);// 渐变发光外扇形void DrawCircle(QPainter& painter, QPoint &center, int radius);// 刻度数字void DrawDigital(QPainter& painter, QPoint &center, int radius);// 绘制刻度void DrawSmallScale(QPainter& painter, QPoint &center, int radius);//绘制码表盘void DrawDb(QPainter& painter, QPoint & center);void DashBoardUpdate(const QPoint & point);protected:void paintEvent(QPaintEvent *event);private:QPainter *m_painter;//坐标轴其实结束点QPoint m_pointZero;QPoint m_pointEndX;QPoint m_pointEndY;QPoint m_pointEndA;// 坐标轴起始结束位置int m_axisStartX;int m_axisStartY;int m_axisEndX;int m_axisEndY;int m_lenY;    // 高度int m_lenX;    // 长度double m_periodX; // x轴每个刻度之间间隔的长度double m_periodY; // y轴每个刻度之间间隔的长度quint32 m_marginX = 300; // y轴距离左右边界宽度quint32 m_marginY = 25; // x轴距离上下边界宽度int m_durationX = 100; // x刻度间隔数int m_durationY = 10; // y刻度间隔数QVector<double> m_valYMax;int m_nodeNumMax;QList<CvsInfo> m_cvsInfo;AxisInfo m_axisInfo;bool m_isAxisReady = false;QList<DataNode> m_listDataNode;MyGtChartAxisYScalesInfo m_scalesY;quint32 m_marginY2Dash = 0; // 左右y轴到马表盘的间隔// 马表盘int m_maxValueDashBoard = 50;int m_minValueDashBoard = 0;int m_curValueDashBoard = 20;// painter移动位置QPoint  m_pleftG;QPoint  m_prightT;QPoint  m_pAxis;
};#endif // MYCHART_H

mychart.cpp

#include "mychart.h"
#include <QDebug>
#include <QtMath>MyChart::MyChart(QWidget *parent) : QWidget(parent)
{m_painter = new QPainter(this);
}MyChart::~MyChart()
{delete m_painter;
}// 数据刷新
void MyChart::updateValue(const DataNode &node)
{if(m_listDataNode.size() >= m_nodeNumMax) {m_listDataNode.removeFirst();}m_listDataNode.append(node);update();
}void MyChart::AxisCurvesUpdate(const QList<QPoint> & pointList)
{QPen pen;// 折线线条宽度pen.setWidth(3);// 折现线条颜色pen.setColor(Qt::green);m_painter->setPen(pen);// 遍历并连接个数据节点,绘制折线for(int i = 0; i < pointList.size(); i++) {if((i+1) < pointList.size()) {// 连接个数据点,绘制折线m_painter->drawLine(pointList.at(i), pointList.at(i+1));}}
}// 坐标轴初始化设置
void MyChart::AxisInit(const MyChart::AxisInfo &info)
{m_axisInfo = info;m_durationX = info.durationX;m_nodeNumMax = m_durationX + 1;m_durationY = info.durationYl;// 初始化设置m_valYMax.append(10);m_valYMax.append(10);m_isAxisReady = true;
}// 曲线参数初始化设置
void MyChart::AxisCurvesAppend(const QString &label, double width, QColor color)
{CvsInfo info;info.label = label;info.width = width;info.color = color;m_cvsInfo.append(info);
}// 曲线标题显示与设置
void MyChart::AxisCurvesTitleSet()
{QVector<double> strlen; // 每个标题长度double lenSum = 0; // 所有标题总长度double linelen = 40; // 标题前面线条长度double spacelen = 30.0; // 标题之间间隔长度double fontSize = 10.0; // 字体大小// 计算标题占用的总长度for (int i = 0; i < m_cvsInfo.size(); ++i) {m_painter->setFont(font());QFontMetrics fm(m_painter->font());double len = (double)fm.width(m_cvsInfo[i].label + spacelen + linelen);strlen.append(len);lenSum += len;}// 起始偏移长度double startLen = (m_lenX - lenSum) / 2;for (int i = 0; i < m_cvsInfo.size(); ++i) {QPen pen(m_cvsInfo[i].color);pen.setWidthF(m_cvsInfo[i].width);m_painter->setPen(pen);m_painter->drawLine(QPoint(m_scalesY.sp.last().x() + startLen, m_scalesY.sp.last().y() / 2),QPoint(m_scalesY.sp.last().x() + startLen + linelen, m_scalesY.sp.last().y() / 2));m_painter->setPen(Qt::NoPen);startLen += linelen; // 偏移已经占用的长度QFont font("Century", fontSize, QFont::Bold);font.setLetterSpacing(QFont::AbsoluteSpacing, 0.1);m_painter->setFont(font);pen.setColor(Qt::black);m_painter->setPen(pen);m_painter->drawText(QPoint(m_scalesY.sp.last().x() + startLen, m_scalesY.sp.last().y() - fontSize / 2), m_cvsInfo[i].label);startLen += strlen[i]; // 偏移已经占用的长度}
}// 坐标轴刻度线设置
void MyChart::AxisScalesLineSet()
{QPen pen;// 轴线刻度绘制m_periodX = (double) (m_lenX * 1.0) / (m_durationX); // x刻度间隔长度m_periodY = m_lenY / (m_durationY - 1); // y刻度间隔长度// x刻度线绘制pen.setWidthF(0.5);pen.setColor(Qt::blue);m_painter->setPen(pen);for (int i = 0; i < m_durationX; ++i) {m_painter->drawLine(QPointF((double)(m_scalesY.spMax.x() + i * m_periodX) + 80, m_scalesY.sp.first().y() + 5),QPointF((double)(m_scalesY.spMax.x() + i * m_periodX) + 80, m_scalesY.sp.first().y() - 5));for (int j = 0; j < m_scalesY.sp.size(); ++j) {}}
}// 坐标轴刻度值刷新
void MyChart::AxisScalesValueSet()
{QPen pen;pen.setWidthF(0.2);pen.setColor(Qt::black);m_painter->setPen(pen);QFont font;font.setPointSizeF(10);m_painter->setFont(font);// 刷新左侧y轴刻度值for (int i = 0; i < m_durationY; ++i) {double lenY = m_valYMax[0];QString value = QString::number(i * (lenY / m_durationY), 'f', 2);QFontMetrics f(m_painter->font());int w = f.width(value);m_painter->setPen(QPen(Qt::red, 1.1));m_painter->drawLine(m_scalesY.sp[i], QPoint(m_scalesY.sp[i].x() + w + 5, m_scalesY.sp[i].y()));m_painter->setPen(Qt::NoPen);m_painter->setPen(pen);if (m_scalesY.sp[i].y() > m_scalesY.spMax.y()) {if (i == 0) {m_painter->drawText(QPoint(m_scalesY.sp[i].x() + 6, m_scalesY.sp[i].y()), value);} else if (i == 1) {m_painter->drawText(QPoint(m_scalesY.sp[i].x() + 4, m_scalesY.sp[i].y()), value);} else if (i == 2) {m_painter->drawText(QPoint(m_scalesY.sp[i].x() + 3, m_scalesY.sp[i].y()), value);} else {m_painter->drawText(QPoint(m_scalesY.sp[i].x() + m_scalesY.sp.size() - 2 * i, m_scalesY.sp[i].y()), value);}} else {m_painter->drawText(QPoint(m_scalesY.sp[i].x() + 1, m_scalesY.sp[i].y()), value);}}// 刷新右侧y轴刻度值for (int i = 0; i < m_durationY; ++i) {double lenY = m_valYMax[1];QString value = QString::number(i * (lenY / m_durationY), 'f', 2);QFontMetrics f(m_painter->font());int w = f.width(value);m_painter->setPen(QPen(Qt::red, 1.1));m_painter->drawLine(m_scalesY.ep[i], QPoint(m_scalesY.ep[i].x() - w - 5, m_scalesY.ep[i].y()));m_painter->setPen(Qt::NoPen);m_painter->setPen(pen);if (m_scalesY.ep[i].y() > m_scalesY.epMax.y()) {if (i == 0) {m_painter->drawText(QPoint(m_scalesY.ep[i].x() - w - 6, m_scalesY.ep[i].y()), value);} else if (i == 1) {m_painter->drawText(QPoint(m_scalesY.ep[i].x() - w - 4, m_scalesY.ep[i].y()), value);} else if (i == 2) {m_painter->drawText(QPoint(m_scalesY.ep[i].x() - w - 3, m_scalesY.ep[i].y()), value);} else {m_painter->drawText(QPoint(m_scalesY.ep[i].x()  - w - 2, m_scalesY.ep[i].y()), value);}} else {m_painter->drawText(QPoint(m_scalesY.ep[i].x() - w - 1, m_scalesY.ep[i].y()), value);}}// 刷新x轴刻度值for (int i = 0; i < m_durationX; ++i) {if (i >= m_listDataNode.size()) {break;}QTransform transform;transform.translate(m_pointZero.x() + i * m_periodX + 2, m_pointZero.y() - 5);transform.rotate(-45);m_painter->setTransform(transform);m_painter->drawText(0, 3, m_listDataNode[i].key);m_painter->resetTransform();}
}// 坐标轴标题设置
void MyChart::MyChartTitileSet(QPainter & painter, const QPoint &point, const QString &title, const QColor & color, const qreal & fontSize)
{painter.save();painter.setPen(QPen(color, fontSize));QFont font("Century", fontSize, QFont::Bold);font.setPointSizeF(fontSize);painter.setFont(font);painter.drawText(point, title);painter.restore();
}// 坐标轴标题设置
void MyChart::AxisTitleSet()
{// x轴标题设置MyChartTitileSet(*m_painter,QPoint((m_scalesY.ep.first().x() - m_scalesY.sp.first().x()) / 2 + m_scalesY.sp.first().x(), m_scalesY.sp.first().y() + 15),m_axisInfo.titleX,Qt::red,12.0);// 左侧y轴MyChartTitileSet(*m_painter,QPoint(m_scalesY.sp.last().x() + 50, m_scalesY.sp.last().y()),m_axisInfo.titleYl,Qt::black,10.0);// 右侧y轴MyChartTitileSet(*m_painter,QPoint(m_scalesY.ep.last().x() - 180, m_scalesY.ep.last().y()),m_axisInfo.titleYr,Qt::black,10.0);
}// 坐标轴初始化设置
void MyChart::AxisInitSet()
{QPen pen;pen.setWidthF(0.5);pen.setColor(Qt::gray);m_painter->setPen(pen);double maxValue = m_valYMax[0];QString strMax = QString::number(m_durationY * (maxValue / m_durationY), 'f', 2);QFontMetrics f(m_painter->font());int xMargin = f.width(strMax);m_axisStartX = xMargin - 3 + qMin(width(), height());maxValue = m_valYMax[1];strMax = QString::number(m_durationY * (maxValue / m_durationY), 'f', 2);xMargin = f.width(strMax);m_axisEndX = this->width() - xMargin - qMin(width(), height());m_axisStartY = this->height() - m_marginY;m_axisEndY = m_marginY;m_lenX = m_axisEndX - m_axisStartX;m_lenY = m_axisStartY - m_axisEndY;// 坐标点设置m_pointZero = QPoint(m_axisStartX, m_axisStartY);m_pointEndX = QPoint(m_axisEndX, m_axisStartY);m_pointEndY = QPoint(m_axisStartX, m_axisEndY);m_pointEndA = QPoint(m_axisEndX, m_axisEndY);// 左侧y轴弧线绘制int offsetXl = qMin(width(), height()) + m_marginY2Dash;int diameters = qMin(width(), height()) + qMin(width(), height()) / 2;AxisYlArcDrawWidthScales(*m_painter, offsetXl, diameters, 10, m_marginY);// 右侧y轴弧线绘制,刻度点记录int diametersR = qMin(width(), height()) + qMin(width(), height()) / 2;int offsetXr = width() - qMin(width(), height()) - m_marginY2Dash;AxisYrArcDrawWidthScales(*m_painter, offsetXr, diametersR, 10, m_marginY);// 底侧x轴线与y轴刻度等分线绘制QPen level; // 等分线for (int i = 0; i < m_scalesY.sp.size(); ++i) {m_painter->setPen(Qt::NoPen);if (i == 0) {level.setColor(Qt::cyan);level.setWidthF(0.5);} else if (i % 2) {level.setColor(Qt::lightGray);level.setWidthF(0.3);} else {level.setColor(Qt::gray);level.setWidthF(0.3);}m_painter->setPen(level);m_painter->drawLine(m_scalesY.sp[i], m_scalesY.ep[i]);}// 坐标轴刻度线设置AxisScalesLineSet();
}// 创建坐标轴
void MyChart::AxisCreateTest()
{m_painter->setRenderHint(QPainter::Antialiasing);// 坐标轴初始化设置AxisInitSet();// 坐标轴刻度值刷新AxisScalesValueSet();// 坐标轴标题设置AxisTitleSet();// 曲线标题显示与设置AxisCurvesTitleSet();
}// 曲线坐标点刷新
void MyChart::AxisPointsUpdate(QVector<QList<QPoint>> &pointList)
{quint16 level = 15;for (int i = 0; i < m_listDataNode.size(); ++i) {DataNode node = m_listDataNode.at(i);for (int j = 0; j < 1; ++j) {if (j >=m_valYMax.size()) {m_valYMax.resize(j + 1);}if (m_valYMax[j] < node.value + node.value / 4) {m_valYMax[j] = node.value + node.value / 4 + j * level;}}}// 刷新曲线坐标点for (int i = 0; i < m_listDataNode.size(); ++i) {DataNode node = m_listDataNode.at(i);quint8 num = 1;if (pointList.size() < num) {pointList.resize(num);}int offsetX = m_pointZero.x() + i * m_periodX;for (int j = 0; j < num; ++j) {if (j >= m_valYMax.size()) {return;}double offsetY = (double)((node.value / m_valYMax[j]) * m_lenY);pointList[j] << QPoint(offsetX, m_pointZero.y() - offsetY);}}
}// 平滑曲线绘制
void MyChart::SmoothCurvesDrawTest(const QColor &color, qreal &width, const QList<QPoint> &pointList)
{QPainterPath path(pointList[0]);for (int i = 0; i < pointList.size() - 1; ++i) {QPointF sp = pointList[i];QPointF ep = pointList[i + 1];QPointF c1 = QPointF((sp.x() + ep.x()) / 2, sp.y());QPointF c2 = QPointF((sp.x() + ep.x()) / 2, ep.y());path.cubicTo(c1, c2, ep);}m_painter->setRenderHints(QPainter::Antialiasing, true);m_painter->setPen(QPen(color, width));m_painter->drawPath(path);
}// 左侧y轴弧线绘制,刻度点记录
// offsetX: 弧线最右侧举例widget最左侧的长度
// diameters: 圆弧直径,即外切举行的边长
// tickCount : 刻度个数
// margin : y轴最上边刻度与最下边刻度距离widget上下边界的距离
void MyChart::AxisYlArcDrawWidthScales(QPainter &painter, int offsetX, int diameters, int tickCount, int margin)
{painter.save();painter.setRenderHint(QPainter::Antialiasing);painter.resetTransform();painter.setPen(QPen(QColor(0, 85, 127), 3.0));// 当前widget内包含最大正方形的边长int rectLen = qMin(width(), height());// 外切矩形的起始位置int rectStartX = offsetX - diameters;// 弧线实际外接矩形的y方向起始位置int rectStartY = (rectLen - diameters) / 2;QPoint rectStartPoint = QPoint(rectStartX, rectStartY);// 弧线实际外切矩形边长设置QSize size = QSize(diameters, diameters);// 弧线实际外切矩形QRect rect(rectStartPoint, size);// 半径长度,对应三角函数中斜边长度int radius = diameters / 2;qreal opSideLen = ((qreal)((rectLen > diameters) ? diameters : rectLen)) / 2;// 起始角度qreal startAngle = -qRadiansToDegrees(qAsin(opSideLen / radius));// 旋转角度qreal spanAngle = 2 * startAngle;// 绘制弧线painter.drawArc(rect, (int)(startAngle * 16), -(int)(spanAngle * 16));// 刻度点记录opSideLen -= margin;startAngle = -qRadiansToDegrees(qAsin(opSideLen / radius));spanAngle = 2 * startAngle;// 刻度点之间的角度间隔qreal intervalAngle = spanAngle / (tickCount - 1);m_scalesY.sp.clear();int i = 0;// 当前刻度对应的角度数qreal angle = startAngle - i * intervalAngle;// 刻度圆点的x坐标qreal x = rectStartX + radius + radius * qCos(qDegreesToRadians(angle));// 刻度点的y轴坐标qreal y = rectStartY + radius - radius * qSin(qDegreesToRadians(angle));m_scalesY.spMin = QPoint(x, y);m_scalesY.sp.append(QPoint(x, y));painter.setPen(QPen(Qt::red, 5));painter.drawPoint(x, y);for (i = 1; i < tickCount; ++i) {angle = startAngle - i * intervalAngle;x = rectStartX + radius + radius * qCos(qDegreesToRadians(angle));y = rectStartY + radius - radius * qSin(qDegreesToRadians(angle));m_scalesY.sp.append(QPoint(x, y));painter.drawPoint(x, y);if (m_scalesY.spMin.x() > x) {m_scalesY.spMin = QPoint(x, y);}if (m_scalesY.spMax.x() < x) {m_scalesY.spMax = QPoint(x, y);}}painter.restore();
}// 右侧y轴弧线绘制,刻度点记录
// offsetX: 弧线最右侧举例widget最左侧的长度
// diameters: 圆弧直径,即外切举行的边长
// tickCount : 刻度个数
// margin : y轴最上边刻度与最下边刻度距离widget上下边界的距离
void MyChart::AxisYrArcDrawWidthScales(QPainter &painter, int offsetX, int diameters, int tickCount, int margin)
{painter.save();painter.setRenderHint(QPainter::Antialiasing);painter.resetTransform();painter.setPen(QPen(QColor(0, 85, 127), 3.0));// 当前widget内包含最大正方形的边长int rectLen = qMin(width(), height());// 外切矩形的起始位置int rectStartX = offsetX;// 弧线实际外接矩形的y方向起始位置int rectStartY = (rectLen - diameters) / 2;QPoint rectStartPoint = QPoint(rectStartX, rectStartY);// 弧线实际外切矩形边长设置QSize size = QSize(diameters, diameters);// 弧线实际外切矩形QRect rect(rectStartPoint, size);// 半径长度,对应三角函数中斜边长度int radius = diameters / 2;qreal opSideLen = ((qreal)((rectLen > diameters) ? diameters : rectLen)) / 2;// 起始角度qreal startAngle = qRadiansToDegrees(qAsin(opSideLen / radius));// 旋转角度qreal spanAngle = 2 * startAngle;// 起始角度从widget下边界开始startAngle = 180 + startAngle;// 绘制弧线painter.drawArc(rect, (int)(startAngle * 16), -(int)(spanAngle * 16));// 刻度点记录opSideLen -= margin;startAngle = qRadiansToDegrees(qAsin(opSideLen / radius));spanAngle = 2 * startAngle;startAngle += 180;// 刻度点之间的角度间隔qreal intervalAngle = spanAngle / (tickCount - 1);m_scalesY.ep.clear();int i = 0;// 当前刻度对应的角度数qreal angle = startAngle + i * intervalAngle;// 刻度圆点的x坐标qreal x = rectStartX + radius + radius * qCos(qDegreesToRadians(angle));// 刻度点的y轴坐标qreal y = rectStartY + radius - radius * qSin(qDegreesToRadians(angle));m_scalesY.epMin = QPoint(x, y);m_scalesY.ep.append(QPoint(x, y));painter.setPen(QPen(Qt::red, 5));painter.drawPoint(x, y);for (i = 1; i < tickCount; ++i) {angle = startAngle - i * intervalAngle;x = rectStartX + radius + radius * qCos(qDegreesToRadians(angle));y = rectStartY + radius - radius * qSin(qDegreesToRadians(angle));m_scalesY.ep.append(QPoint(x, y));painter.drawPoint(x, y);if (m_scalesY.epMin.x() > x) {m_scalesY.epMin = QPoint(x, y);}if (m_scalesY.epMax.x() < x) {m_scalesY.epMax = QPoint(x, y);}}painter.restore();
}// 曲线图刷新
void MyChart::ChartViewUpdate()
{static int speed = 0;m_curValueDashBoard = speed++;QVector<QList<QPoint>> pointList;// 曲线坐标点刷新AxisPointsUpdate(pointList);if (m_valYMax.size() >= 2) {// 创建坐标轴AxisCreateTest();}// 坐标轴标题设置AxisTitleSet();for (int i = 0; i < pointList.size(); ++i) {if (i >= m_cvsInfo.size()) {break;}SmoothCurvesDrawTest(m_cvsInfo[i].color, m_cvsInfo[i].width, pointList[i]);}speed %= 239;
}//绘制实时数字
void MyChart::DrawDbNum(QPainter& painter, QPoint & point)
{painter.save();painter.setPen(QColor(0,255,255));QFont font;font.setFamily("Arial");font.setPointSize(8);painter.setFont(font);// 根据 QFont 对象创建 QFontMetrics 实例QFontMetrics font_metrics(painter.font());QString str = QString::number(m_curValueDashBoard) + QString("kb/s");// 获取文本的长度int text_width = font_metrics.width(str);// 获取文本的高度int text_height = font_metrics.height();QPoint curPoint = QPoint(point.x() - text_width / 2, point.y() - text_height);painter.drawText(curPoint, str);str = "数据传输速率";text_width = font_metrics.width(str);QPoint curPoint2 = QPoint(point.x() - text_width / 2, point.y() + text_height);painter.drawText(curPoint2, str);painter.restore();
}// 绘制一条中间略粗两边略尖的渐变发光线条
void MyChart::DrawDbLightLine(QPainter& painter, QPoint & point)
{painter.save();// 创建白色的画笔,设置较粗的线条和略圆形的线帽QPen pen(QColor(255, 255, 255));pen.setWidth(6);pen.setCapStyle(Qt::RoundCap);// 创建一个渐变,将颜色从白色渐变到透明色QLinearGradient gradient(0, point.y() - 100, 0, point.y() + 100);gradient.setColorAt(0, QColor(255, 255, 255));gradient.setColorAt(1, QColor(255, 255, 255, 0));// 设置画笔的颜色为渐变pen.setBrush(gradient);// 将这个画笔设置给 QPainterpainter.setPen(pen);// 绘制一条直线painter.drawLine(QPoint(point.x() - 100, point.y()), QPoint(point.x() + 100, point.y()));painter.restore();
}// 中间小圆
void MyChart::DrawCircle_bom_small(QPainter& painter, QPoint & center, int radius)
{//保存绘图对象painter.save();//计算圆的位置和大小int x = center.x() - radius;int y = center.y() - radius;int width = 2 * radius;int height = 2 * radius;//创建圆形路径QPainterPath inCircle;inCircle.moveTo(center);inCircle.addEllipse(x, y, width, height);//设置画刷和画笔painter.setBrush(QColor(0, 73, 107));painter.setPen(QColor(255, 255, 255));//绘制圆形painter.drawPath(inCircle);//恢复绘图对象painter.restore();
}// 渐变发光内圈
void MyChart::DrawCircle_bom_shine(QPainter &painter, QPoint &center, int radius)
{painter.save();//计算圆的位置和大小int x = center.x() - radius;int y = center.y() - radius;int width = 2 * radius;int height = 2 * radius;//创建渐变对象QRadialGradient radialGradient(center, radius, center);radialGradient.setColorAt(0.5, QColor(10, 68, 185, 150));radialGradient.setColorAt(1.0, Qt::transparent);//设置画刷painter.setBrush(QBrush(radialGradient));painter.setPen(Qt::transparent);//计算圆形路径QPainterPath path;path.addEllipse(x, y, width, height);//绘制圆形渐变painter.setClipPath(path);painter.drawEllipse(x, y, width, height);//恢复绘图对象painter.restore();
}// 最外细圆线
void MyChart::DrawCircle_line(QPainter& painter, QPoint &center, int radius, int width)
{painter.save();QPainterPath outRing;QPainterPath inRing;outRing.moveTo(center);inRing.moveTo(center);// 计算弧线的起点和终点位置QPoint startPoint(center.x() + radius * cos(60 * M_PI / 180), center.y() - radius * sin(60 * M_PI / 180));QPoint endPoint(center.x() + radius * cos(300 * M_PI / 180), center.y() - radius * sin(300 * M_PI / 180));outRing.arcTo(center.x() - radius, center.y() - radius, 2 * radius, 2 * radius, -30, 240);inRing.addEllipse(center.x() - radius + width, center.y() - radius + width, 2 * (radius - width), 2 * (radius - width));outRing.closeSubpath();painter.setBrush(QColor(5,228,255));painter.drawPath(outRing.subtracted(inRing));painter.restore();
}// 绘制指针
void MyChart::DrawPointer(QPainter& painter, QPoint &center, int radius, int degRotate)
{//组装点的路径图QPainterPath pointPath;pointPath.moveTo(0, 0);pointPath.moveTo(10,0);pointPath.lineTo(1,-radius);pointPath.lineTo(-1,-radius);pointPath.lineTo(-10,0);pointPath.arcTo(-10,0,20,20,180,180);QPainterPath inRing;inRing.addEllipse(-5,-5,10,10);painter.save();// 计算绘制相对原点的坐标系painter.save();painter.translate(center);painter.setPen(Qt::transparent);//计算并选择绘图对象坐标painter.rotate(degRotate - 120);painter.setBrush(QColor(0,255,255));painter.drawPath(pointPath.subtracted(inRing));painter.restore();
}// 动态扇形环
void MyChart::DrawCircle_arc(QPainter& painter, QPoint &center, int radius, int degRotate)
{// 计算绘制相对原点的坐标系painter.save();// painter移动至centerpainter.translate(center);// 设置扇形渐变色QRect rect(-radius, -radius, 2 * radius, 2 * radius);QConicalGradient gradient(0,0,-70);gradient.setColorAt(0.1, QColor(255, 88, 127, 200)); // 红色gradient.setColorAt(0.5, QColor(53, 179, 251, 150)); // 蓝色painter.setBrush(gradient);// 绘制扇形painter.drawPie(rect,210*16,-(degRotate)*16);painter.restore();
}// 渐变发光外扇形
void MyChart::DrawCircle(QPainter& painter, QPoint &center, int radius)
{//保存绘图对象painter.save();// painter移动至centerpainter.translate(center);//计算大小圆路径QPainterPath outRing;QPainterPath inRing;outRing.moveTo(0,0);inRing.moveTo(0,0);outRing.arcTo(-radius,-radius, 2*radius,2*radius,-30,240);inRing.addEllipse(-radius+50,-radius + 50,2*(radius-50),2*(radius-50));outRing.closeSubpath();//设置渐变色kQRadialGradient radialGradient(0,0,radius,0,0);radialGradient.setColorAt(1,QColor(0,82,199));radialGradient.setColorAt(0.92,Qt::transparent);//设置画刷painter.setBrush(radialGradient);painter.setPen(Qt::transparent);//大圆减小圆painter.drawPath(outRing.subtracted(inRing));painter.restore();
}// 刻度数字
void MyChart::DrawDigital(QPainter& painter, QPoint &center, int radius)
{//保存绘图对象painter.save();// painter移动至centerpainter.translate(center);//设置画笔,画笔默认NOPENpainter.setPen(QColor(250,0,150));QFont font;font.setFamily("Arial");font.setPointSize(8);font.setBold(true);painter.setFont(font);for(int i=0;i<13;++i){QPointF point(0,0);painter.save();point.setX(radius*qCos(((210-i*20)*M_PI)/180));point.setY(radius*qSin(((210-i*20)*M_PI)/180));painter.translate(point.x(),-point.y());painter.rotate(-120+i*20);painter.drawText(-25, 0, 50, 20,Qt::AlignCenter,QString::number(i*20));painter.restore();}//还原画笔painter.setPen(Qt::NoPen);painter.restore();
}// 绘制刻度
void MyChart::DrawSmallScale(QPainter& painter, QPoint &center, int radius)
{//保存绘图对象painter.save();// painter移动至centerpainter.translate(center);//组装点的路径图QPainterPath pointPath_small;pointPath_small.moveTo(-2,-2);pointPath_small.lineTo(2,-2);pointPath_small.lineTo(2,8);pointPath_small.lineTo(-2,8);QPainterPath pointPath_big;pointPath_big.moveTo(-2,-2);pointPath_big.lineTo(2,-2);pointPath_big.lineTo(2,20);pointPath_big.lineTo(-2,20);painter.setPen(Qt::transparent);//绘制121个小点for(int i=0;i<121;i+=2){QPointF point(0,0);painter.save();point.setX(radius*qCos(((210-i*2)*M_PI)/180));point.setY(radius*qSin(((210-i*2)*M_PI)/180));painter.translate(point.x(),-point.y());painter.rotate(-120+i*2);if(i<80){painter.setBrush(QColor(255,255,255));}if(i>=80){painter.setBrush(QColor(235,70,70));}if(i%5 == 0){painter.drawPath(pointPath_big);//绘画大刻度}else{painter.drawPath(pointPath_small);//绘画小刻度}painter.restore();}painter.restore();
}//绘制码表盘
void MyChart::DrawDb(QPainter& painter, QPoint & center)
{int radius = qMin(width() / 2, height() / 2);// 绘制刻度DrawSmallScale(painter, center, radius - 40);// 刻度数字DrawDigital(painter, center, radius - 50);// 渐变发光外扇形DrawCircle(painter, center, radius - 20);// 动态扇形环DrawCircle_arc(painter, center, radius - 20, m_curValueDashBoard);// 绘制指针DrawPointer(painter, center, radius - 30, m_curValueDashBoard);// 最外细圆线DrawCircle_line(painter, center, radius - 20, 4);// 中间大圈DrawCircle_bom_small(painter, center, radius - 80);// 渐变发光内圈,-80用于调节渐变圆圈的宽度DrawCircle_bom_shine(painter, center, radius - 100);//中间小圆DrawCircle_bom_small(painter, center, radius - 120);//绘制实时时速数字DrawDbNum(painter, center);// 绘制一条中间略粗两边略尖的渐变发光线条DrawDbLightLine(painter, center);
}// 马表盘
void MyChart::DashBoardUpdate(const QPoint & point)
{m_painter->translate(point);// 画一个带有渐变色的圆圈// 镜像渐变QRadialGradient ra(0, 0, qMin(width(), height() / 2));// 设置起点颜色ra.setColorAt(0, Qt::green);// 终点颜色ra.setColorAt(1, Qt::cyan);m_painter->setBrush(ra);m_painter->setPen(Qt::NoPen);m_painter->drawEllipse(QPoint(0, 0), qMin(width(), height()) / 2, qMin(width(), height()) / 2);qreal angle = 270 * 1.0 / (m_maxValueDashBoard - m_minValueDashBoard);// 135°为刻度的起始点对应的角度m_painter->rotate(135);// 绘制刻度线m_painter->setPen(QPen(Qt::white, 4));m_painter->setFont(QFont("微软雅黑", 18));for (int i = m_minValueDashBoard; i <= m_maxValueDashBoard; ++i) {if (i % 10 == 0) {if (135 + angle * i < 270) {m_painter->rotate(180);m_painter->drawText(-qMin(width(), height()) / 2 + 30, 10, QString::number(i));m_painter->rotate(-180);} else {m_painter->drawText(qMin(width(), height()) / 2 - 20 - 50, 10, QString::number(i));}// 第一个参数是起始点的 x 坐标,第二个参数是起始点的 y 坐标,第三个参数是终止点的 x 坐标,第四个参数是终止点的 y 坐标。m_painter->drawLine(qMin(width(), height()) / 2 - 20, 0, qMin(width(), height()) / 2, 0);} else {m_painter->drawLine(qMin(width(), height()) / 2 - 10, 0, qMin(width(), height()) / 2, 0);}m_painter->rotate(angle);}// 刻度画完后,将painter旋转至水平向下的角度,以便在中心位置绘制文字// 之前时顺时针旋转的,现在逆时针旋转45°就可以了m_painter->rotate( - angle - 45);// 绘制一个圆圈// `painter.drawEllipse()` 函数的第二个和第三个参数分别表示椭圆的半长轴长度和半短轴长度。m_painter->drawEllipse(QPoint(0, 0), 100, 100);// 绘制文字m_painter->drawText(QRect(-100, -100, 200, 200), Qt::AlignCenter, QString::number(m_curValueDashBoard));// painter的x轴回到刻度起始位置m_painter->rotate(135 + m_curValueDashBoard * angle);// `width()` 和 `height()` 函数返回的分别是 `QWidget` 控件的宽度和高度。m_painter->drawLine(100, 0, qMin(width(), height()) / 2 - 20 - 50, 0);// 绘制扇形渐变色m_painter->rotate(-135 - m_curValueDashBoard * angle);m_painter->setBrush(QColor(255, 0, 0, 100));m_painter->setPen(Qt::NoPen);m_painter->drawPie(QRect(-qMin(width(), height()) / 2 + 20 + 50,-qMin(width(), height()) / 2 + 20 + 50,qMin(width(), height()) - 40 - 100,qMin(width(), height()) - 40 - 100),(360 - 135) * 16,-m_curValueDashBoard * angle * 16);// 释放画刷m_painter->setBrush(Qt::NoBrush);
}void MyChart::drawArcAtWidget(QPainter * painter, const QPoint& center, int radius)
{int startAngle = -30 * 16; // 弧线的起始角度,从 x 轴负方向开始int endAngle = -90 * 16 + 180 * 16; // 弧线的终止角度,绘制从正上方到正下方的弧线int startX = center.x();int startY = painter->device()->height() * 0.1;int arcHeight = painter->device()->height() * 0.8;// 调用 drawArc() 函数绘制弧线painter->drawArc(startX - radius, startY, radius * 2, arcHeight, startAngle, endAngle);
}void MyChart::paintEvent(QPaintEvent *event)
{(void)event;m_painter->begin(this);// 左侧码盘刷新DashBoardUpdate(QPoint(qMin(width(), height() / 2), qMin(width(), height() / 2)));
#if 1// 将坐标系回到原点m_painter->resetTransform();// 曲线图刷新ChartViewUpdate();// 右侧码盘刷新
#endif#if 1// 右侧码盘刷新// DashBoardUpdate(QPoint(m_axisEndX + qMin(width(), height()) / 2 + 100, qMin(width(), height()) / 2));QPoint dbrPoint = QPoint(width() - qMin(width(), height()) / 2, qMin(width(), height()) / 2);DrawDb(*m_painter, dbrPoint);#endifm_painter->end();
}

charttest.h

#ifndef CHARTTEST_H
#define CHARTTEST_H#include <QWidget>
#include <QTimer>
#include <QTime>
#include "mychart.h"
#include <QGroupBox>QT_BEGIN_NAMESPACE
namespace Ui { class ChartTest; }
QT_END_NAMESPACEtypedef enum {TRANS_GL_PHY_SEND = 0,TRANS_TL_PHY_SEND,TRANS_GL_PHY_RECV,TRANS_TL_PHY_RECV,TRANS_GL_MAC_SEND,TRANS_TL_MAC_SEND,TRANS_GL_MAC_RECV,TRANS_TL_MAC_RECV,TRANS_GL_LC_SEND,TRANS_TL_LC_SEND,TRANS_GL_LC_RECV,TRANS_TL_LC_RECV,TRANS_MAX,
} GtDataTransType;class ChartTest : public QWidget
{Q_OBJECTpublic:ChartTest(QWidget *parent = nullptr);~ChartTest();void initState();typedef struct {quint32 userId;quint32 sfr;quint32 vol;} RcvVolInfo;typedef struct {QVector<quint32> userOn;QVector<RcvVolInfo> infoG; // 获取g的吞吐量数据QVector<QVector<RcvVolInfo>> infoT; // 获取多个t的吞吐量数据} UserInfo;typedef struct {quint32 vol;quint32 sfr;} GtTransInfoGnode;typedef struct {quint32 userId;double rcvRat;} UserRcvRateInfo;typedef struct {QVector<UserRcvRateInfo> ratlc;QVector<UserRcvRateInfo> ratmac;QVector<UserRcvRateInfo> ratphy;} RcvRateInfo;typedef struct {quint32 phyId;quint32 sfrLc;quint32 volLc;quint32 sfrMac;quint32 volMac;quint32 sfrPhy;quint32 volPhy;} GtTransInfoUser;typedef struct {GtTransInfoGnode infoG[TRANS_MAX];quint32 userNum;QVector<GtTransInfoUser> infoT;} GtDataTransAllInfo;typedef enum {RCV_TYPE_LC = 0,RCV_TYPE_MAC,RCV_TYPE_PHY,RCV_TYPE_MAX,} TransRcvType;// 原始数据刷新void VolDataUpdate();// 码速率计算结果数据刷新void TransRetUpdate();// 码速率计算结果txt文本显示void TextViewRefreshTransRate(RcvRateInfo & m_rcvRat);protected:void resizeEvent(QResizeEvent *event);private slots:void on_splitter_splitterMoved(int pos, int index);private:Ui::ChartTest *ui;int index = 0;QTimer timer;   //定时器QVector<MyChart *> m_chart;QVector<QGroupBox *> m_chartView;quint32 m_userNum = 5;RcvRateInfo m_rcvRat;};
#endif // CHARTTEST_H

charttest.cpp

#include "charttest.h"
#include "ui_charttest.h"
#include <QDebug>ChartTest::ChartTest(QWidget *parent): QWidget(parent), ui(new Ui::ChartTest)
{ui->setupUi(this);initState();
}ChartTest::~ChartTest()
{timer.stop();delete ui;
}// 页面大小变化触发
void ChartTest::resizeEvent(QResizeEvent *event)
{QWidget::resizeEvent(event);
}void ChartTest::initState()
{m_chart.append(ui->chartViewD0);m_chart.append(ui->chartViewD1);m_chart.append(ui->chartViewD2);m_chartView.append(ui->groupBoxD0);m_chartView.append(ui->groupBoxD1);m_chartView.append(ui->groupBoxD2);ui->groupBox_showSet->setMaximumHeight(50);ui->groupBox_showSet->setMinimumHeight(50);MyChart::AxisInfo axisInfo;// 坐标轴参数初始化设置axisInfo.titleX      = "time";axisInfo.durationX   = 100;axisInfo.titleYl     = "码速率(kbs/s)";axisInfo.durationYl  = 10;axisInfo.titleYr     = "码速率(kbs/s)";axisInfo.dudrationYr = 10;for (int i = 0; i < m_chart.size(); ++i) {m_chart[i]->AxisInit(axisInfo);// 曲线参数初始化设置m_chart[i]->AxisCurvesAppend("user100", 3, Qt::cyan);m_chart[i]->AxisCurvesAppend("user101", 3, Qt::green);m_chart[i]->AxisCurvesAppend("user102", 3, Qt::blue);m_chart[i]->AxisCurvesAppend("user103", 3, Qt::yellow);m_chart[i]->AxisCurvesAppend("user104", 3, Qt::magenta);}connect(&timer, &QTimer::timeout, [=](){// 码速率计算结果数据刷新TransRetUpdate();TextViewRefreshTransRate(m_rcvRat);// 模拟数据int y = rand() % 4 + 3;static int value = 0;DataNode node = {y, "ABC" + QString::number(value++)};// 刷新数据for (int i = 0; i < m_chart.size(); ++i) {m_chart[i]->updateValue(node);}});timer.start(100);
}// 码速率计算结果数据刷新
void ChartTest::TransRetUpdate()
{// lcm_rcvRat.ratlc.clear();static double lcRatG = 120.0;UserRcvRateInfo lcInfoG = {0, lcRatG};m_rcvRat.ratlc.append(lcInfoG);for (quint32 i = 0; i < m_userNum; ++i) {UserRcvRateInfo inf = {100 + i, double(20 + i * 10)};m_rcvRat.ratlc.append(inf);}// macm_rcvRat.ratmac.clear();static double macRatG = 120.0;UserRcvRateInfo macInfoG = {0, macRatG};m_rcvRat.ratmac.append(macInfoG);for (quint32 i = 0; i < m_userNum; ++i) {UserRcvRateInfo inf = {100 + i, double(20 + i * 10)};m_rcvRat.ratmac.append(inf);}// phym_rcvRat.ratphy.clear();static double phyRatG = 120.0;UserRcvRateInfo phyInfoG = {0, phyRatG};m_rcvRat.ratphy.append(phyInfoG);for (quint32 i = 0; i < m_userNum; ++i) {UserRcvRateInfo inf = {100 + i, double(20 + i * 10)};m_rcvRat.ratphy.append(inf);}if (lcRatG++ >= 130) {lcRatG = 120;}if (macRatG++ >= 130) {macRatG = 120;}if (phyRatG++ >= 130) {phyRatG = 120;}
}void ChartTest::TextViewRefreshTransRate(RcvRateInfo & info)
{QDateTime current_time = QDateTime::currentDateTime();QString time = current_time.toString("yyyy-MM-dd hh:mm:ss");// QString str = "[" + time + "]\r\n";QString str = "";// lcstr += "[" + time + "] " + "lc  recv rate :  ";for (int i = 0; i < info.ratlc.size(); ++i) {str += "user[" + QString::number(info.ratlc[i].userId) + "] :  " + QString::number(info.ratlc[i].rcvRat) + ",  ";}str += "\n";// macstr += "[" + time + "] " + "mac recv rate :  ";for (int i = 0; i < info.ratmac.size(); ++i) {str += "user[" + QString::number(info.ratmac[i].userId) + "] :  " + QString::number(info.ratmac[i].rcvRat) + ",  ";}str += "\n";// phystr += "[" + time + "] " + "phy recv rate :  ";for (int i = 0; i < info.ratphy.size(); ++i) {str += "user[" + QString::number(info.ratphy[i].userId) + "] :  " + QString::number(info.ratphy[i].rcvRat) + ",  ";}str += "\n";ui->textEdit_transRate->append(str);ui->textEdit_originData->append(str);
}void ChartTest::on_splitter_splitterMoved(int pos, int index)
{int hi = pos;if (index == 1) {hi += ui->groupBox_showSet->height() * 1.0 / 2;} else {hi -= ui->groupBox_showSet->height() * 1.0 / 2;}double hRate1 = (double)(hi * 1.0 / height());qDebug() << "index " << index << "rate = " << hRate1 << endl;if (hRate1 < 0.10) {ui->groupBox_showSet->setVisible(false);} else if (hRate1 < 0.20) {ui->groupBox_showSet->setVisible(true);m_chartView[0]->setVisible(false);m_chartView[1]->setVisible(false);m_chartView[2]->setVisible(false);} else if (hRate1 < 0.3) {m_chartView[0]->setVisible(false);m_chartView[1]->setVisible(false);m_chartView[2]->setVisible(true);} else if (hRate1 < 0.4) {m_chartView[0]->setVisible(false);m_chartView[1]->setVisible(true);m_chartView[2]->setVisible(true);}  else {m_chartView[0]->setVisible(true);m_chartView[1]->setVisible(true);m_chartView[2]->setVisible(true);ui->groupBox_textInfo->setVisible(true);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/508745.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EdgeX Foundry - MQTT 设备服务

文章目录 一、MQTT 设备服务1.概述2.服务配置3.协议属性4.多级 Topics4.1.异步数据4.2.命令 二、连接 MQTT 设备1.docker-comepse2.设备配置文件3.安装自定义配置4.启动 EdgeX Foundry5.创建 MQTT 设备模拟器6.访问 UI6.1. consul6.2. EdgeX Console 7.测试7.1.命令7.2.事件7.3…

命令行启动mongodb服务器的问题及解决方案 -- Unrecognized option: storage.journal

目录 mongodb命令行启动问题 -- Unrecognized option: storage.journal问题日志&#xff1a;问题截图&#xff1a;问题来源&#xff1a;错误原因&#xff1a;解决方式&#xff1a; mongodb命令行启动问题 – Unrecognized option: storage.journal 同样是格式出问题的问题分析和…

如何为在线课程定价以获得最大收益(7个步骤)

如果您是独立内容创建者或小创业者&#xff0c;希望用 WordPress LMS 在线学习和教练网站获利&#xff0c;您可能会意识到构建在线课程并非易事。 您可能已经浏览了迷宫般的选择&#xff1a; 弄清楚要教什么主题&#xff1b;收集您需要的所有设备&#xff1b;决定弹出的标题和…

如何自己系统的学python

学习Python是一项很好的投资&#xff0c;因为它是一种既强大又易于学习的编程语言&#xff0c;适用于多种应用&#xff0c;如数据分析、人工智能、网站开发等。下面是一个系统学习Python的步骤建议&#xff1a; 基础准备 安装Python&#xff1a; 访问Python官网下载最新版本的…

冒泡排序 和 qsort排序

目录 冒泡排序 冒泡排序部分 输出函数部分 主函数部分 总代码 控制台输出显示 总代码解释 冒泡排序优化 冒泡排序 主函数 总代码 代码优化解释 qsort 排序 qsort 的介绍 使用qsort排序整型数据 使用qsort排序结构数据 冒泡排序 首先&#xff0c;我先介绍我的冒泡…

ARM总结and复习

安装交叉编译工具链 a. 为什么安装 因为arm公司的指令集在不断迭代升级&#xff0c;指令集日益增多,而架构是基于指令集研发的&#xff0c;所以架构不一样&#xff0c;指令集也不一样 eg:arm架构使用的是arm指令集 x86架构使用的是x86指令集 而我们日常开发环境中linux的架构…

常用的电阻、电容的种类和应用场合?

电阻的 a.按阻值特性:固定电阻、可调电阻、特种电阻(敏感电阻)&#xff0c;不能调节的,我们称之为固定电阻,而可以调节的,我们称之为可调电阻.常见的例如收音机音量调节的,主要应用于电压分配的,我们称之为电位器. b.按制造材料:碳膜电阻、金属膜电阻、线绕电阻&#xff0c;捷…

win11修改网络算法为BBR2_提升网络环境质量

Win11 BBR2 是Google开发的一种高效的网络拥塞控制算法&#xff0c;玩 Linux 的朋友应该对它还有锐速不陌生。相比Windows默认使用的 CUBIC 算法&#xff0c;BBR2 在网络吞吐量、延迟、全局性能等方面都有一定优势。 如果你日常网络经常丢包或者高延迟可以尝试切换为BBR2算法。…

OpenAI工作环境曝光:高薪背后的996;Quora的转变:由知识宝库至信息垃圾场

&#x1f989; AI新闻 &#x1f680; OpenAI工作环境曝光&#xff1a;高薪背后的996 摘要&#xff1a;近日&#xff0c;多位OpenAI匿名员工在求职网站Glassdoor上披露了公司的工作环境和公司文化&#xff0c;包括高薪水和优厚的福利待遇&#xff0c;但同时伴随着996的加班文化…

CV论文--2024.3.4

1、Deep Networks Always Grok and Here is Why 中文标题&#xff1a;深度网络总是让人摸不着头脑&#xff0c;原因如下 简介&#xff1a;本文探讨了深度神经网络&#xff08;DNN&#xff09;中一种称为"延迟泛化"或"Grokking"的现象。在接近零的训练误差…

00X集——样条曲线(spline)和多线段(pl)和面域(region)

样条曲线是经过或接近影响曲线形状的一系列点的平滑曲线。 默认情况下&#xff0c;样条曲线是一系列 3 阶&#xff08;也称为“三次”&#xff09;多项式的过渡曲线段。这些曲线在技术上称为非均匀有理 B 样条 (NURBS)&#xff0c;但为简便起见&#xff0c;称为样条曲线。三次…

怎么倒放视频?3个倒放方法分享给你

怎么倒放视频&#xff1f;倒放视频不仅有趣且充满创意&#xff0c;而且还能创造出一种令人惊叹的视觉效果&#xff0c;将观众带入一个全新的时空维度。通过将动作和事件倒放&#xff0c;我们可以观察到平时难以察觉的细节&#xff0c;理解事物运行的逆向逻辑。这种独特的编辑手…