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());
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};
}