QPainter drawPie起始角度绘制偏移问题求助
问题分析与解决方案
你的问题核心在于椭圆的非均匀缩放会改变角度与坐标的映射关系——直接用圆的角度逻辑(比如drawPie的角度参数)处理椭圆,只有当方向刚好对齐椭圆主轴时才会匹配,其余角度都会因为拉伸变形出现偏移。
为什么原来的逻辑不对?
当你通过painter->rotate(ellipse_rot)绘制椭圆时,椭圆是被旋转后的拉伸图形。drawPie的角度参数是基于圆形的极坐标角度,但椭圆的“方向角度”和圆的极坐标角度不是线性对应的:椭圆上某点与中心连线的实际角度,和圆的参数角(用于drawPie的角度)存在差异,只有在主轴方向上两者才重合。
修正步骤
我们需要直接计算椭圆上沿箭头方向的点,而不是依赖drawPie的圆角度逻辑。具体做法是:
- 将箭头的世界角度转换到椭圆的局部坐标系(减去椭圆自身的旋转角);
- 根据椭圆的半轴长,计算该方向上椭圆边缘的坐标;
- 绘制从中心到该点的线条(后续可以扩展为扇形)。
修改后的代码
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
相关产品推荐
相关产品推荐

