计算两个平面向量之间的转角及Qt代码实现

请先复习一下向量运算的基础知识
1、用QLineF类实现,代码最少
QLineF类提供了计算一条到另一条直线夹角的函数。
qreal QLineF::angleTo(const QLineF &line) const
Returns the angle (in degrees) from this line to the given line, taking the direction of the lines into account. If the lines do not intersect within their range, it is the intersection point of the extended lines that serves as origin (see QLineF::UnboundedIntersection).
The returned value represents the number of degrees you need to add to this line to make it have the same angle as the given line, going counter-clockwise.
翻译一下:
以线的方向为参考,返回从这条线到给定线的角度(以度为单位)。如果这些线在它们的范围内不相交,则以延伸线的交点作为原点(参见QLineF::UnboundedIntersection)。
返回的值表示需要向这条线逆时针方向旋转多少度才能使其与给定的线具有相同的角度。
代码实现。

 //构造正北方向直线
 QLineF line1(rotateCenter,rotateCenter+QPointF(0,-1));
 QPointF newPos=value.toPointF();
 QLineF line2(rotateCenter,newPos);
 double degree=line2.angleTo(line1);

2、用向量计算实现
//以下是计算y轴反方向向量到 另一个向量的转角,正负号按右手定则确定

QVector3D vector_cur=QVector3D(newPos-rotateCenter); //待计算的向量
QVector3D vector_y=QVector3D(0,-1,0);  //y轴反方向向量
QVector3D vector_z=QVector3D(0,0,1);  //z轴正方向向量
//通过点乘运算,得到y轴反方向向量到待计算的向量转角的余弦
float cos_angle=vector_y.dotProduct(vector_y,vector_cur);
//通过叉乘运算,得到y轴反方向向量到待计算的向量转角的按右手定则确定的法向量,
QVector3D vector_N=vector_y.crossProduct(vector_y,vector_cur);

float sin_angle=vector_y.dotProduct(vector_N,vector_z);
float angle=atan2(sin_angle,cos_angle);

看下应用,实现仪表盘的旋转角标,用QGraphicsView、QGrapphicsScene、QGraphicsItem绘图架构实现。
1、实现三角形角标的绘制,从QGraphicsItem派生出TrigonItem类
1.1 TrigonItem类h文件

#ifndef TRIGONITEM_H
#define TRIGONITEM_H

#include <QObject>
#include<QGraphicsItem>
#include <QPen>

class TrigonItem : public QObject,public QGraphicsItem
{
    Q_OBJECT
    Q_INTERFACES(QGraphicsItem)
    enum ItemProperty{ItemPen=1,ItemBrush};
public:
    enum Direction{Left=1,Right=-1};
    explicit TrigonItem(QGraphicsItem *parentItem=NULL,QObject *parent = nullptr);

    void setDirection(Direction orientation=Right);
    void setItemSize(double width,double height);
    void setRange(double _min,double _max);
    void setFixedPos(double posValue);
    void setPen(const QPen &pen);
    void setBrush(const QBrush &brush);
protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
    QRectF boundingRect() const;
    QPainterPath shape() const;
    QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value);
    void mousePressEvent(QGraphicsSceneMouseEvent* e);
    void mouseReleaseEvent(QGraphicsSceneMouseEvent* e);
signals:
    void sig_posChanged(double posValue);  //位置变化坐标值
    void sig_pressChanged(bool);

public slots:
private:
    double _width=20;
    double _height=20;
    Direction m_direction=Left;
    double m_width;
    QPen m_pen;
protected:
    double min=-100;
    double max=100;
    double _posValue=0;
};

#endif // TRIGONITEM_H

1.2 TrigonItem类cpp文件

#include "trigonitem.h"
#include <QBrush>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include<QDebug>
#include <QGraphicsSceneMouseEvent>

TrigonItem::TrigonItem(QGraphicsItem *parentItem, QObject *parent)
    : QObject(parent),QGraphicsItem(parentItem)
{
    setFlags(QGraphicsItem::ItemIsMovable
                   | QGraphicsItem::ItemIsFocusable);

    setFlag(QGraphicsItem::ItemSendsGeometryChanges,true);

    setAcceptHoverEvents(true);

    m_width=m_direction*_width;
    m_pen=Qt::NoPen;
    setData(ItemBrush,QBrush(Qt::red));
}

void TrigonItem::setDirection(TrigonItem::Direction orientation)
{
    m_direction=orientation;
    m_width=m_direction*_width;
    update();
}

void TrigonItem::setItemSize(double width, double height)
{
    this->_width=width;
    this->_height=height;
    m_width=m_direction*_width;
}

void TrigonItem::setRange(double _min, double _max)
{
    if(_max>_min)
    {
        min=_min;
        max=_max;
    }
    return;
}

void TrigonItem::setFixedPos(double posValue)
{
    _posValue=posValue;
    QPointF temPos=pos();
    temPos.rx()=posValue;
    setPos(temPos);
}

void TrigonItem::setPen(const QPen &pen)
{
    m_pen=pen;
    update();
}

void TrigonItem::setBrush(const QBrush &brush)
{
    setData(ItemBrush,brush);
    update();
}
void TrigonItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option)
    Q_UNUSED(widget)

    painter->setPen(m_pen);
    painter->setBrush(data(ItemBrush).value<QBrush>());

    QPolygonF polygonF;
    polygonF<<QPointF(0,0)<<QPointF(m_width,-_height/2)<<QPointF(m_width,_height/2);
    painter->drawPolygon(polygonF);
}

QRectF TrigonItem::boundingRect() const
{
    //三角形的指向点坐标总是(0,0)
    double x=0;
    if(m_direction==Right)
    {
        x=m_width;
    }
    return QRectF(x,-_height/2,_width,_height);
}
QPainterPath TrigonItem::shape() const
{
    QPolygonF polygonF;
    polygonF<<QPointF(0,0)<<QPointF(m_width,-_height/2)<<QPointF(m_width,_height/2);

    QPainterPath painterPath;
    painterPath.addPolygon(polygonF);
    return painterPath;
}

QVariant TrigonItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
    return QGraphicsItem::itemChange(change,value);
}

void TrigonItem::mousePressEvent(QGraphicsSceneMouseEvent *e)
{
    if(e->button()==Qt::LeftButton)
    {
        emit sig_pressChanged(true);
    }
    QGraphicsItem::mousePressEvent(e);
}

void TrigonItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *e)
{
    emit sig_pressChanged(false);
    QGraphicsItem::mouseReleaseEvent(e);
}

2、实现三角形角标的旋转运动(用手拖动时,只能旋转,从QGraphicsItem派生出RotateItem类
2.1 RotateItem类h文件

#ifndef ROTATEITEM_H
#define ROTATEITEM_H

#include"trigonitem.h"

class RotateItem : public TrigonItem
{
    Q_OBJECT
public:
    explicit RotateItem(QObject *parent = nullptr, QGraphicsItem* parentItem=NULL);

    void setCenter(const QPointF &centerPos);
protected:
    QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value);
signals:

public slots:
private:
    QPointF rotateCenter=QPointF(200,200);  //公转中心
};

#endif // ROTATEITEM_H

2.2 RotateItem类cpp文件

#include "rotateitem.h"
#include <QVector3D>

RotateItem::RotateItem(QObject *parent, QGraphicsItem *parentItem)
    : TrigonItem(parent,parentItem)
{
   this->min=0;
   this->max=360;
    _posValue=50;
}

void RotateItem::setCenter(const QPointF &centerPos)
{
    rotateCenter=centerPos;
    update();
}

QVariant RotateItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
    if(change==ItemPositionChange)
    {
        QPointF newPos=value.toPointF();
        //构造三维向量
        QVector3D vector_cur=QVector3D(newPos-rotateCenter);
        QVector3D vector_y=QVector3D(0,-1,0);  //y轴反方向向量
        QVector3D vector_z=QVector3D(0,0,1);  //z轴正方向向量
        float cos_angle=vector_y.dotProduct(vector_y,vector_cur);
        QVector3D vector_N=vector_y.crossProduct(vector_y,vector_cur);

        float sin_angle=vector_y.dotProduct(vector_N,vector_z);
        float angle=atan2(sin_angle,cos_angle);

       float x_angle=angle-3.1415926/2; //Qt中旋转时需用与X轴正方向的转角
        setRotation(x_angle*180/3.1415926); //设置自转角度 自转角度和公转角度是一样的
        newPos=rotateCenter+QPointF(cos(x_angle),sin(x_angle))*_posValue;
        emit sig_posChanged(angle*180/3.1415926);
        return newPos;// newPos

    }
    return QGraphicsItem::itemChange(change,value);
}

代码的工程文件见:仪表、表盘的Qt实现

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

蔡云辉

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

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

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

打赏作者

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

抵扣说明:

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

余额充值