Qt 两点+弧度 定圆弧

定义

  • o: 圆心
  • p1: 圆弧起点
  • p2: 圆弧终点
  • a: 弧度(逆时针方向)
  • a1: 以圆心为原点建轴,圆弧起点到正半轴的弧度
  • a2: 以圆心为原点建轴,圆弧终点到正半轴的弧度

推导

p 1 − o = r { c o s ( a 1 ) , s i n ( a 1 ) } p 2 − o = r { c o s ( a 2 ) , s i n ( a 2 ) } a 2 − a 1 = a p 2 − p 1 = r { c o s ( a 2 ) − c o s ( a 1 ) , s i n ( a 2 ) − s i n ( a 1 ) } d x = r ( c o s ( a 2 ) − c o s ( a 1 ) ) d y = r ( s i n ( a 2 ) − s i n ( a 1 ) ) d x d y = c o s ( a + a 1 ) − c o s ( a 1 ) s i n ( a + a 1 ) − s i n ( a 1 ) d x d y = c o s ( a ) c o s ( a 1 ) − s i n ( a ) s i n ( a 1 ) − c o s ( a 1 ) s i n ( a ) c o s ( a 1 ) + c o s ( a ) s i n ( a 1 ) − s i n ( a 1 ) d x d y = ( c o s ( a ) − 1 ) c o s ( a 1 ) − s i n ( a ) s i n ( a 1 ) ( c o s ( a ) − 1 ) s i n ( a 1 ) + s i n ( a ) c o s ( a 1 ) ( ( c o s ( a ) − 1 ) d x + s i n ( a ) d y ) s i n ( a 1 ) = ( ( c o s ( a ) − 1 ) d y − s i n ( a ) d x ) c o s ( a 1 ) t a n ( a 1 ) = s i n ( a 1 ) c o s ( a 1 ) = ( c o s ( a ) − 1 ) d y − s i n ( a ) d x ( c o s ( a ) − 1 ) d x + s i n ( a ) d y \begin{align} p_1-o=r\{cos(a_1),sin(a_1)\} \\ p_2-o=r\{cos(a_2),sin(a_2)\} \\ a_2-a_1=a \\ p_2-p_1=r\{cos(a_2)-cos(a_1),sin(a_2)-sin(a_1)\} \\ dx=r(cos(a_2)-cos(a_1)) \\ dy=r(sin(a_2)-sin(a_1)) \\ \dfrac{dx}{dy}=\dfrac{cos(a+a_1)-cos(a_1)}{sin(a+a_1)-sin(a_1)} \\ \dfrac{dx}{dy}=\dfrac{cos(a)cos(a_1)-sin(a)sin(a_1)-cos(a_1)}{sin(a)cos(a_1)+cos(a)sin(a_1)-sin(a_1)} \\ \dfrac{dx}{dy}=\dfrac{(cos(a)-1)cos(a_1)-sin(a)sin(a_1)}{(cos(a)-1)sin(a_1)+sin(a)cos(a_1)} \\ ((cos(a)-1)dx+sin(a)dy)sin(a_1)=((cos(a)-1)dy-sin(a)dx)cos(a_1) \\ tan(a_1)=\dfrac{sin(a_1)}{cos(a_1)}=\dfrac{(cos(a)-1)dy-sin(a)dx}{(cos(a)-1)dx+sin(a)dy} \end{align} p1o=r{cos(a1),sin(a1)}p2o=r{cos(a2),sin(a2)}a2a1=ap2p1=r{cos(a2)cos(a1),sin(a2)sin(a1)}dx=r(cos(a2)cos(a1))dy=r(sin(a2)sin(a1))dydx=sin(a+a1)sin(a1)cos(a+a1)cos(a1)dydx=sin(a)cos(a1)+cos(a)sin(a1)sin(a1)cos(a)cos(a1)sin(a)sin(a1)cos(a1)dydx=(cos(a)1)sin(a1)+sin(a)cos(a1)(cos(a)1)cos(a1)sin(a)sin(a1)((cos(a)1)dx+sin(a)dy)sin(a1)=((cos(a)1)dysin(a)dx)cos(a1)tan(a1)=cos(a1)sin(a1)=(cos(a)1)dx+sin(a)dy(cos(a)1)dysin(a)dx

代码

因为 Qt 窗口坐标系与笛卡尔坐标系在视觉上是垂直翻转的,故作顺逆时针翻转变换

#include <QtCore>
#include <QPainter>

void drawArc(QPainter* painter, const QPointF& p1, const QPointF& p2, double radian) {
	//! 方向翻转
	const auto& q1	  = p2;
	const auto& q2	  = p1;

	//! 参数计算
	const auto	dx	  = q2.x() - q1.x();
	const auto	dy	  = q2.y() - q1.y();
	const auto	u	  = cos(radian) - 1;
	const auto	v	  = sin(radian);
	const auto	a1	  = atan2(u * dy - v * dx, u * dx + v * dy);
	const auto	a2	  = a1 + radian;
	const auto	r	  = fabs(dx) < 1e-6 ? dy / (sin(a2) - sin(a1)) : dx / (cos(a2) - cos(a1));
	const auto	ox	  = q1.x() - r * cos(a1);
	const auto	oy	  = q1.y() - r * sin(a1);
	const auto	bb	  = QRectF(ox - r, oy - r, r * 2, r * 2);

	//! 方向翻转
	const auto	start = -qRadiansToDegrees(a1) * 16;
	const auto	span  = -qRadiansToDegrees(radian) * 16;
	
	//! 圆弧绘制
	painter->drawArc(bb, start, span);
}

写在后头

上述代码中之所以翻转是为了在视觉上得到与常规笛卡尔坐标系相同的结果,实际经过顺逆时钟变换过后,代码中计算得出的圆心、弧度等值并不与形参对应。

若要获取实际的数据,只需将代码中方向翻转的部分去除即可。

而为了实现视觉上的一致性,之所以要进行顺逆时钟翻转的原因主要有两点:

  1. 调用绘制时,通常会默认传入参数是遵从 Qt 窗口坐标系的,但又会潜在地期望绘制结果是遵从笛卡尔坐标系的,于是坐标系之间就产生了分歧,需要处理垂直翻转的问题。
  2. QPainter 提供的 drawArc 方法的逆时针是习惯下的,视觉上的逆时针,而非 Qt 窗口坐标系下的逆时针(其实就是第 1 点)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周上行Ryer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值