You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QPainter drawPie起始角度绘制偏移问题求助

问题分析与解决方案

你的问题核心在于椭圆的非均匀缩放会改变角度与坐标的映射关系——直接用圆的角度逻辑(比如drawPie的角度参数)处理椭圆,只有当方向刚好对齐椭圆主轴时才会匹配,其余角度都会因为拉伸变形出现偏移。

为什么原来的逻辑不对?

当你通过painter->rotate(ellipse_rot)绘制椭圆时,椭圆是被旋转后的拉伸图形。drawPie的角度参数是基于圆形的极坐标角度,但椭圆的“方向角度”和圆的极坐标角度不是线性对应的:椭圆上某点与中心连线的实际角度,和圆的参数角(用于drawPie的角度)存在差异,只有在主轴方向上两者才重合。

修正步骤

我们需要直接计算椭圆上沿箭头方向的点,而不是依赖drawPie的圆角度逻辑。具体做法是:

  1. 将箭头的世界角度转换到椭圆的局部坐标系(减去椭圆自身的旋转角);
  2. 根据椭圆的半轴长,计算该方向上椭圆边缘的坐标;
  3. 绘制从中心到该点的线条(后续可以扩展为扇形)。

修改后的代码

1. 主轴绘制优化(替换原来的drawPie为直线)

原来的drawPie参数长度为0,实际上只画了一个点,改成直接绘制主轴直线更清晰:

painter->setPen(QPen(Qt::red));
// 绘制椭圆X方向主轴
painter->drawLine(QPointF(-ellipse_x, 0), QPointF(ellipse_x, 0));
painter->setPen(QPen(Qt::green));
// 绘制椭圆Y方向主轴
painter->drawLine(QPointF(0, -ellipse_y), QPointF(0, ellipse_y));

2. 蓝色线条(箭头方向到椭圆边缘)的修正

替换原来的蓝色drawPie代码,用向量计算椭圆上的对应点:

painter->setPen(QPen(Qt::blue));
// 转换箭头角度到椭圆局部坐标系(转为弧度计算)
double local_angle_rad = qDegreesToRadians(arrow_angle - ellipse_rot);
// 箭头方向的单位向量
double dx = cos(local_angle_rad);
double dy = sin(local_angle_rad);

double a = ellipse_x; // 椭圆X半轴
double b = ellipse_y; // 椭圆Y半轴

// 计算椭圆上沿该方向的点坐标
// 公式推导:椭圆方程x²/a² + y²/b² = 1,代入y = (dy/dx)x(或处理dx=0的情况)
double denominator = sqrt(pow(dx, 2) + pow(a*dy/b, 2));
double ellipse_edge_x = a * dx / denominator;
double ellipse_edge_y = b * dy / denominator;

// 绘制从中心到椭圆边缘的蓝色线条
painter->drawLine(QPointF(0, 0), QPointF(ellipse_edge_x, ellipse_edge_y));

完整的paint函数修改后版本

void EllipseItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
    Q_UNUSED(option);
    Q_UNUSED(widget);
    painter->setPen(pen());
    painter->setBrush(brush());

    // 绘制箭头
    QPolygonF arrow;
    arrow.append(QPointF(0, -arrow_scale / 2));
    arrow.append(QPointF(arrow_scale * 3 / 4, 0));
    arrow.append(QPointF(0, arrow_scale / 2));
    arrow.append(QPointF(-arrow_scale / 4, 0));

    painter->save();
    painter->rotate(arrow_angle);
    painter->drawPolygon(arrow);
    painter->restore();

    // 绘制椭圆及辅助线
    painter->save();
    painter->rotate(ellipse_rot);
    painter->drawEllipse(QPointF(0, 0), ellipse_x, ellipse_y);

    // 绘制红、绿主轴
    painter->setPen(QPen(Qt::red));
    painter->drawLine(QPointF(-ellipse_x, 0), QPointF(ellipse_x, 0));
    painter->setPen(QPen(Qt::green));
    painter->drawLine(QPointF(0, -ellipse_y), QPointF(0, ellipse_y));

    // 绘制蓝色箭头方向线(到椭圆边缘)
    painter->setPen(QPen(Qt::blue));
    double local_angle_rad = qDegreesToRadians(arrow_angle - ellipse_rot);
    double dx = cos(local_angle_rad);
    double dy = sin(local_angle_rad);
    double a = ellipse_x;
    double b = ellipse_y;
    double denominator = sqrt(pow(dx, 2) + pow(a*dy/b, 2));
    double ellipse_edge_x = a * dx / denominator;
    double ellipse_edge_y = b * dy / denominator;
    painter->drawLine(QPointF(0, 0), QPointF(ellipse_edge_x, ellipse_edge_y));

    painter->restore();
}

扩展到扇形绘制

如果后续要绘制扇形,更准确的方式是用QPainterPath构建路径:先添加椭圆的扇形弧,再连接中心到弧的两端点,这样能保证扇形完全贴合椭圆的边缘,不会因为拉伸出现角度偏移。

内容的提问来源于stack exchange,提问作者apalomer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:54:24