新手程序员工作心得:网络上代码框架可以借鉴,但是其中某些参数放进去效果不理想,个人更改了部分参数,使其满足使用习惯(参考了CAD中三点画弧的操作模式)。
void MainWindow::paintEvent(QPaintEvent* event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(QPen(Qt::black, 5));
// 给定的三个点
QPoint p1(198, 236); // 起点
painter.drawPoint(p1);
QPoint p2(132, 233);
painter.drawPoint(p2);
QPoint p3(167, 56); // 终点
painter.drawPoint(p3);
// 计算圆心和半径
QPoint center = calculateArcCenter(p1, p2, p3);
qDebug() << "圆心坐标:" << center;
painter.drawPoint(center);
int radius = calculateArcRadius(p1, center);
qDebug() << "半径:" << radius;
painter.setPen(QPen(Qt::black, 1));
// 计算起始角度和跨度角度
qreal startAngle = calculateArcStartAngle(p1, center);
if (startAngle < 0) {
startAngle += 360; // 将负角度转换为正角度
}qDebug() << "起始角度:" << startAngle;
qreal mediumAngle = calculateArcStartAngle(p2, center);
if (mediumAngle < 0) {
mediumAngle += 360; // 将负角度转换为正角度
}qDebug() << "中间角度:" << mediumAngle;
qreal endAngle = calculateArcEndAngle(p3, center);
if (endAngle < 0) {
endAngle += 360; // 将负角度转换为正角度
}qDebug() << "终止角度:" << endAngle;
qreal spanAngle = 0;
if (startAngle > endAngle)
{
if(mediumAngle > startAngle)
{
spanAngle = 360-(startAngle-endAngle);
}
else if (mediumAngle < endAngle)
{
spanAngle = 360-(startAngle - endAngle);
}
else if(mediumAngle < startAngle)
{
spanAngle = -(startAngle - endAngle);
}
}
else if(startAngle < endAngle)
{
if(mediumAngle > endAngle)
{
spanAngle = -(360-(endAngle - startAngle));
}
else if (mediumAngle < startAngle)
{
spanAngle = -(360-endAngle+startAngle);
}
else if(startAngle < mediumAngle && mediumAngle < endAngle)
{
spanAngle = endAngle - startAngle;
}
}
qDebug() << "偏移角度:" << spanAngle;
// 起始角度和终止角度是以圆心为中心的极坐标系中的角度。x 轴正方向对应的角度为0度,沿着顺时针方向递增,最大为360度(即完整的圆)。
// 绘制圆弧
painter.drawArc(center.x() - radius, center.y() - radius, radius * 2, radius * 2, -startAngle * 16, -spanAngle * 16);
}
/*** center.x() - radius:弧形所在矩形的左上角 x 坐标。计算方式为圆心的 x 坐标减去半径。 200 - 100 = 100
center.y() - radius:弧形所在矩形的左上角 y 坐标。计算方式为圆心的 y 坐标减去半径。 200 - 100 = 100
radius * 2:弧形所在矩形的宽度。计算方式为半径的两倍。
radius * 2:弧形所在矩形的高度。计算方式为半径的两倍。
startAngle * 16:起始角度相对于 x 轴正方向的角度值(逆时针方向)。乘以16是为了将角度转换为16进制,因为drawArc()方法接受的是以1/16度为单位的角度值。这里的-endAngle表示方向相反,即顺时针方向。
spanAngle * 16:绘制弧形的角度跨度。同样乘以16是为了将角度转换为16进制。 ***/
/*** 上述代码在一个自定义的 QWidget 上绘制一个由给定的三个点构成的弧线。在 paintEvent() 函数内部,我们首先设置画笔和画刷的样式。
接下来,我们定义了三个点的坐标,可以根据实际需要修改这些点的坐标值。
然后,我们调用 calculateArcCenter() 函数计算弧线的圆心坐标。该函数使用三个点的坐标通过向量和内积的性质计算圆心。
接着,我们调用 calculateArcRadius() 函数计算弧线的半径。该函数使用给定点与圆心的距离作为半径。
然后,我们调用 calculateArcStartAngle() 和 calculateArcEndAngle() 函数分别计算弧线的起始角度和终止角度。这两个函数使用给定点与圆心的坐标差值来计算角度。
最后,我们使用 drawArc() 方法绘制该弧线,其中使用了上述计算得到的圆心坐标、半径和角度参数。
请注意,此代码仅在给定的三个点能够构成一个合法的弧线时才能正常工作。如果三个点无法构成一个弧线,结果将会是不确定的。
因此,在实际应用中,建议在绘制弧线之前进行额外的检查来确保给定的三个点能够构成一个有效的弧线。 ***/
QPoint MainWindow::calculateArcCenter(const QPoint& p1, const QPoint& p2, const QPoint& p3)
{
// 使用向量和内积的性质计算圆心
qreal A = p2.x() - p1.x();
qreal B = p2.y() - p1.y();
qreal C = p3.x() - p1.x();
qreal D = p3.y() - p1.y();
qreal E = A * (p1.x() + p2.x()) + B * (p1.y() + p2.y());
qreal F = C * (p1.x() + p3.x()) + D * (p1.y() + p3.y());
qreal G = 2 * (A * (p3.y() - p2.y()) - B * (p3.x() - p2.x()));
if (G == 0) {
// 三点共线,无法构成弧线
return QPoint();
}
qreal centerX = (D * E - B * F) / G;
qreal centerY = (A * F - C * E) / G;
return QPoint(centerX, centerY);
}
int MainWindow::calculateArcRadius(const QPoint& p, const QPoint& center)
{
// 计算距离圆心的半径
return qRound(QLineF(center, p).length());
}
float MainWindow::calculateArcStartAngle(const QPoint& p, const QPoint& center)
{
// 计算起始角度
float dx = p.x() - center.x();
float dy = p.y() - center.y();
return qRadiansToDegrees(qAtan2(dy, dx));
}
float MainWindow::calculateArcEndAngle(const QPoint& p, const QPoint& center)
{
// 计算终止角度
float dx = p.x() - center.x();
float dy = p.y() - center.y();
return qRadiansToDegrees(qAtan2(dy, dx));
}