目的
本来设计如图一个环形属性旋转框, 其难点是在于如何在一个圆形的窗口中 如何鼠标拖动指示器实现旋转并依据角度变化, 依据设计范围准确显示当前值。
可能有些会想到利用顺时针, 逆时针, 这虽然是一个好的想法idea, 那么问题来了? 你怎么判断顺时针,逆时针, 这个想法设计我网上搜了下, 感觉问题相对来说就弄复杂了。
一种方法就是可以参考环形进度条原理, 去设计。 我只需要找一个相对某个初始化参考位置, 另一个位置变化, 然后求出转动角度(0-360),结合你给定的数值范围, 360° ,可以求出当前位置的数值。稍微难一点在于如何求出两者之间夹角, 以及弧度与角度转换。
如何求夹角
c++ 弧度值与角度值的转换
数学函数库
double Rad_to_deg = 45.0 / atan(1.0);
弧度值到角度值的转换 用 角度 = 弧度值* Rad_to_deg
角度值到弧度值的转换 用 弧度值 = 角度 / Rad_to_deg
我采用的是三点求夹角, 通过向量夹角余弦公式法
比如已知三点M(1,1),A(2,2),B(2,1)求角度∠AMB
1.先求向量MA,MB
向量公式 MA=(A.x-M.x)i+(B.x-M.x)j
所以:
MA=(2-1,2-1)=(1,1)
MB=(2-1,1-1)=(1,0)
则两向量的数量积为:
MA*MB=1×1+1×0=1
2.求向量的模
向量的模=sqrt(x*x+y*y)
|MA|=√(1×1)+(1×1)=√2
|MB|=√(1*1)+(0*0)=√1
将以上结果带入向量夹角余弦公式得:
cos∠AMB=MA*MB/|MA|*|MB|=√2/2
则∠AMB=45度
核心思路 :以圆心为原点, 正y轴向上一定长度某个点为一个点, 另一个点为窗口鼠标移动或者点击某个点, 然后求其三点之间夹角。
代码: 返回的值是0-360.
double DashBoardWidget::getAngle(const QPointF &point)
{
QPointF v1(m_yOriginPos.x() - m_originPos.x(), m_yOriginPos.y() - m_originPos.y());
QPointF v2(point.x() - m_originPos.x(), point.y() - m_originPos.y());
double N(v2.x() * v1.x() + v2.y() * v1.y());
double M1 = sqrt(v1.x() * v1.x() + v1.y() * v1.y());
double M2 = sqrt(v2.x() * v2.x() + v2.y() * v2.y());
double cosValue = N / (M1 * M2);
double radtoDeg = 45.0 / atan(1.0);
bool positiveAngle = (point.x() >= m_originPos.x()) ? true : false;
double cos = radtoDeg * acos(cosValue);
double realAngle = cos;
if(!positiveAngle){
realAngle = 360.0 - realAngle;
}
qDebug() << __FUNCTION__ << "cosValue!" << cos << realAngle;
// double angel = acos(cosValue);
return realAngle;
}
如下是网上搜到较多的仪表盘之类的博客, 可看看, 拓展思路
博客大佬一
QPainter中坐标系变换问题
基本图形绘制
大佬博客二