如何解释QPainterPath :: arcTo上的角度?

时间:2016-10-12 23:48:12

标签: qt

我正在处理一个图形编辑器的功能,我正在编辑弧线,而当形状是椭圆形时,QPainterPath :: arcTo的行为与我的预期不同;当它成为一个圆圈时,它按预期工作。

下面的两张图显示了结果。在第一种情况下,我创建了一个圆,然后我将其转换为弧,初始起始角为45,跨度角为270.场景坐标空间为方形。对角线为45度。正如预期的那样,圆弧的终点正好在对角线上。

在第二种情况下,我有一个椭圆,它以完全相同的方式转换为弧形,分别为45度和270度角。弧的终点不再落在对角线上,这不是我所期望的。

在这两种情况下,绘图代码为:

painter.arcTo (rect, 45, 270);

零度位于3点钟位置,我相信在该点和从中心点到弧边缘点的直线之间测量了指定的角度。显然,还有其他事情正在发生,我不明白,并且似乎没有记录在QPainter :: arcTo描述中。

这是一个问题,因为我正在编写代码来重塑弧形,我需要能够处理背景,而我只有当前鼠标位置和包围矩形的中心点。现在,当我重塑弧形时,我计算的角度仅在0,90,180和270处准确。我越接近介入的45度角,我的角度就越远。 / p>

我通过以下方式获得了这个角度:

QLineF (rect.center(), mouse_pos).angle ();

同样,对于圈子来说,这非常有效。对于非圆形椭圆,它没有。

写完之后,我发现了这个beautiful illustration,它正好展示了我正在处理的事情。不幸的是,Postscript解决方案对我没有帮助。我需要知道如何计算正确的角度。

Circular arc with start angle of 45 and span angle of 270

Elliptical arc with start angle of 45 and span angle of 270

2 个答案:

答案 0 :(得分:0)

我找到了答案here。正如我所料,我对角度的理解是不正确的。要执行鼠标跟踪以重塑圆弧,我需要找到线段与椭圆的交点,并从参数椭圆方程向后工作以找到正确的角度。

答案 1 :(得分:0)

感谢@goug,我能够使用 QPainterPath::arcTo 解决类似问题。

在我的例子中,我需要一个椭圆弧,它的行为就像一个正常的弧。开始和结束角度由用户控制。起始角不需要任何修正,但终止角需要。

这是一个展示如何绕过这个问题的代码。

qreal startAngle = 10;
qreal endAngle = 60;

qreal radius1 = 30; // X-axis
qreal radius2 = 60; // Y-axis

QPointF center;
QRectF boundingRect(center.x() - radius1, center.y() - radius2, radius1*2, radius2*2);

if (!qFuzzyIsNull(endAngle) &&
        !VFuzzyComparePossibleNulls(endAngle, 90) &&
        !VFuzzyComparePossibleNulls(endAngle, 180) &&
        !VFuzzyComparePossibleNulls(endAngle, 270) &&
        !VFuzzyComparePossibleNulls(endAngle, 360))
{
  // Calculating correct end angle
  qreal endAngleRad = qDegreesToRadians(endAngle);
  endAngle = qRadiansToDegrees(qAtan2(radius1 * qSin(endAngleRad),
                                      radius2 * qCos(endAngleRad)));
}

QLineF startLine(center.x(), center.y(), center.x() + radius1, center.y());
QLineF endLine = startLine;

startLine.setAngle(startAngle);
endLine.setAngle(endAngle);
qreal sweepAngle = startLine.angleTo(endLine);

QPainterPath myPath;
myPath.arcTo(boundingRect, startAngle, sweepLength);