1.使用QT5繪畫
- 再Qt5中畫一個弧一般使用接口
painter.drawArc(rectangle, startAngle*16, spanAngle*16);
-
rectangle
為圓弧所對應圓的外接矩陣 -
startAngle
為圓弧的起始角 -
spanAngle
為圓弧的夾角 - 16個像素約為1°
2.起始角和夾角的核心算法
- 構建兩個復數,一個是起點的復數,一個是終點的復數,兩者相除即得到旋轉子的復數
- 乘以一個模為1的復數時,不會導致縮放,只會產生旋轉,這樣的復數就稱為旋轉子(rotor)
- 逆時針的旋轉子為
cos(θ) + sin(θ)i
,順時針的旋轉子的共軌復數cos(θ) - sin(θ)i
- 默認逆時針角度為正,順時針為負
- 若span角為0,說明弧是一個整圓,spanAngle需修正為360°
/// 起點向量復數、終點向量復數、旋轉子
ComplexNum c1(startVector.x(), startVector.y());
ComplexNum c2(endVector.x(), endVector.y());
ComplexNum rotor = c2 / c1;
/// 根據順逆方向計算夾角
if (isAcw) {
spanAngle = qAtan2(rotor.B(), rotor.A());
if (spanAngle < 0) {
spanAngle += 2*PI;
}
} else {
spanAngle = -qAtan2(-rotor.B(), rotor.A());
if (spanAngle > 0) {
spanAngle -= 2*PI;
}
}
/// 如果是整圓
if(fabs(spanAngle) < 0.0001) spanAngle = 2 * PI;
/// 計算起始角
c1.setComplexNumValue(1, 0);
c2.setComplexNumValue(startVector.x(),startVector.y());
rotor = c2 / c1;
startAngle = qAtan2(rotor.B(), rotor.A());
image.png
image.png
3.核心代碼
小程序地址:https://gitee.com/liuwentao1234/drawArc
#include <math.h>
#define PI 3.1415926
typedef struct ArcInfo {
double startAngle; /// 起始角 單位°
double spanAngle; /// 夾角 單位°
QRectF rectangle; /// 外接矩陣
}ArcInfo;
static inline void ToAngle(double& num)
{
num = num / PI * 180;
}
ArcInfo DrawArc(QPointF start, QPointF end, QPointF center, bool isAcw)
{
//計算畫弧所需的參數有3個:起始角度、夾角、外切矩形
double startAngle = 0, spanAngle = 0;
QRectF rectangle;
//定義起始向量和終止向量
QPointF startVector = start - center;
QPointF endVector = end - center;
//構建兩個復數,一個是起點的復數,一個是終點的復數,兩者相除即得到旋轉子的復數
//乘以一個模為1的復數時,不會導致縮放,只會產生旋轉,這樣的復數就稱為旋轉子(rotor)
//逆時針:*旋轉子(cos(θ)+sin(θ)i) 順時針:*旋轉子的共軌復數(cos(θ)-sin(θ)i)
//默認逆時針角度為正,順時針為負
//若span角為0,說明弧是一個整圓,spanAngle需修正為360°
ComplexNum c1(startVector.x(), startVector.y());
ComplexNum c2(endVector.x(), endVector.y());
ComplexNum rotor = c2 / c1;
if (isAcw) {
spanAngle = qAtan2(rotor.B(), rotor.A());
if (spanAngle < 0) {
spanAngle += 2*PI;
}
} else {
spanAngle = -qAtan2(-rotor.B(), rotor.A());
if (spanAngle > 0) {
spanAngle -= 2*PI;
}
}
if(fabs(spanAngle) < 0.0001) spanAngle = 2 * PI;
//計算起始角
c1.setComplexNumValue(1, 0);
c2.setComplexNumValue(startVector.x(),startVector.y());
rotor = c2 / c1;
startAngle = qAtan2(rotor.B(), rotor.A());
//弧度轉角度
ToAngle(spanAngle);
ToAngle(startAngle);
ui->span->setText(QString::number(spanAngle));
double r = startVector.manhattanLength();
QPointF upperLeftPointOfRect = QPointF(center.x()-r, -(center.y()+r));
rectangle.setRect(upperLeftPointOfRect.x(), upperLeftPointOfRect.y(), 2 * r, 2 * r);
return {startAngle, spanAngle, rectangle};
}