Qt绘图:求圆和椭圆上任意角度点的坐标

(2021-02-11 之前把笛卡尔坐标的 x 和 y 标注反了,已修正)

(2023-07-18 之前把旋转矩阵坐标算错了,已修正)

0.圆相关公式

在笛卡尔坐标系上,一个标准的圆是这样的:

已知圆心坐标 (x0,y0),半径 R,角度 a,则圆边上点(x',y')的坐标为:

C 的三角函数参数为弧度,转换如下:

角度转弧度: radian =\frac{\pi \cdot angle}{180}

弧度转角度: angle =\frac{180 \cdot radian }{\pi}

但我们知道,Qt 绘图是屏幕坐标系,起点在左上角,以右下角为正方向:

(可以把计算后的 y 取反来得到想要的效果)

void MainWindow::paintEvent(QPaintEvent *event)
{
    event->accept();

    QPainter painter(this);
    painter.setPen(QPen(Qt::red,2));
    //移动坐标中心点到窗口中心,默认左上角为起点,往右下为正方向
    painter.translate(width()/2,height()/2);
    //画一个圆,圆心为起点(上一步移动到的正中),半径100px
    const int R=100;
    painter.drawEllipse(QPoint(0,0),R,R);
    //计算45度角圆边上的点,角度需要转换为弧度
    const double a=qDegreesToRadians((double)45);
    const int x=0+R*cos(a);
    const int y=0+R*sin(a);
    //因为屏幕坐标系y轴正方向和笛卡尔坐标系相反,所以y取反就是我们要的结果了
    painter.drawLine(QPoint(0,0),QPoint(x,-y)); //y取反
}

运行结果:

1.椭圆相关公式

在笛卡尔坐标系上,一个标准的椭圆是这样的:

已知圆心坐标 (x0,y0),横轴 A(长半轴),竖轴 B(短半轴),角度 a,则圆边上点(x',y')的坐标为:

椭圆半径:

(可以发现,与普通圆相比,不考虑椭圆角度的话只是半径变化了,其他部分是一样的)

void MainWindow::paintEvent(QPaintEvent *event)
{
    event->accept();

    QPainter painter(this);
    painter.setPen(QPen(Qt::red,2));
    //移动坐标中心点到窗口中心,默认左上角为起点,往右下为正方向
    painter.translate(width()/2,height()/2);
    //画一个圆,圆心为起点(上一步移动到的正中),半径100px
    const int A=150; //横轴
    const int B=100; //竖轴
    painter.drawEllipse(QPoint(0,0),A,B);
    //计算45度角圆边上的点,角度需要转换为弧度
    const double a=qDegreesToRadians((double)45);
    const int R=A*B/sqrt(pow(A*sin(a),2)+pow(B*cos(a),2)); //计算对应角度的半径
    const int x=0+R*cos(a);
    const int y=0+R*sin(a);
    //因为屏幕坐标系y轴正方向和笛卡尔坐标系相反,所以y取反就是我们要的结果了
    painter.drawLine(QPoint(0,0),QPoint(x,-y)); //y取反
}

运行结果:

2.旋转矩阵

上面的角度都是从右侧开始,椭圆也是标准椭圆,如果我们想旋转一定角度来绘制,就需要用到我们的旋转矩阵了。

(本节主要来自参考博客)

已知 A(x,y) ,求旋转 a 角度后的 B(x’,y’) 坐标:

在这里插入图片描述

公式推导:

在这里插入图片描述

根据矩阵乘法计算规则,可以推出:

在这里插入图片描述

操作流程:

  • 把图形的各点平移,令旋转中心平移至原点;
  • 乘以旋转矩阵;
  • 再平移至原来的旋转中心。

在这里插入图片描述

我们将上面椭圆的代码改一下,逆时针旋转 45 度:


void MainWindow::paintEvent(QPaintEvent *event)
{
    event->accept();

    QPainter painter(this);
    painter.setPen(QPen(Qt::red,2));
    //移动坐标中心点到窗口中心,默认左上角为起点,往右下为正方向
    painter.translate(width()/2,height()/2);
    //画一个圆,圆心为起点(上一步移动到的正中),半径100px
    const int A=150; //横轴
    const int B=100; //竖轴
    painter.rotate(-45); //在屏幕坐标系,qpainter是顺时针转的
    painter.drawEllipse(QPoint(0,0),A,B);
    painter.rotate(45);

    //计算45度角圆边上的点,角度需要转换为弧度
    const double a=qDegreesToRadians((double)45);
    const int R=A*B/sqrt(pow(A*sin(a),2)+pow(B*cos(a),2)); //计算对应角度的半径
    const int x=0+R*cos(a);
    const int y=0+R*sin(a);
    //根据旋转矩阵计算
    const double a2=qDegreesToRadians((double)45);
    const int x2=x*cos(a2)-y*sin(a2);
    const int y2=x*sin(a2)+y*cos(a2);
    //因为屏幕坐标系y轴正方向和笛卡尔坐标系相反,所以y取反就是我们要的结果了
    painter.drawLine(QPoint(0,0),QPoint(x2,-y2)); //y取反
}

运行结果:

(第一次计算的角度坐标是计算标准椭圆下的位置,第二次是根据椭圆的旋转角度做旋转得到的坐标)

(本来就有 45 度,从右侧逆时针旋转,再旋转 45 度就成了垂直向上了)

(虽然线可以直接 QPainter 旋转的方式绘制,但是这样文本也旋转了)

3.参考

博客(圆和椭圆坐标):求圆和椭圆上任意角度的点的坐标_椭圆上任意角度点的坐标_xiamentingtao的博客-CSDN博客

博客(椭圆坐标):【C#】 根据椭圆边框和任意角度计算椭圆二维坐标_c# 椭圆 角度求半径_少莫千华的博客-CSDN博客

博客(二维旋转矩阵):二维旋转矩阵推导_whoNamedCody的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

龚建波

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

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

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

打赏作者

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

抵扣说明:

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

余额充值