3
votes

I'm working on feature of a graphic editor where I'm editing arcs, and QPainterPath::arcTo is not behaving as I expected when the shape is an ellipse; it works as expected when it's a circle.

The two images below show the results. In the first case, I've created a circle, which I then convert to an arc with an initial start angle of 45 and span angle of 270. The scene coordinate space is square. The diagonal lines are at 45 degrees. As expected, the circular arc's end points are exactly on the diagonal lines.

In the second case, I have an ellipse, which is converted to an arc in exactly the same way with 45 and 270 degree angles respectively. The end points of the arc no longer fall on the diagonal lines, which is not what I expect.

In both cases, the drawing code is:

painter.arcTo (rect, 45, 270);

Zero degrees is at the 3 o'clock position, and I had believed that the specified angle was measured between that and a line from the center point to the point on the arc edge. Clearly, something else is going on that I don't understand and doesn't appear to be documented in the QPainter::arcTo description.

This is an issue because I'm writing code to reshape the arc, and I need to be able to work backgrounds when all I have is the current mouse position and the center point of the encompassing rectangle. Right now, as I reshape the arc, the angle that I'm calculating is only accurate at 0, 90, 180, and 270. The closer I get to the intervening 45 degree angles, the further off my angle is.

I'm getting that angle by:

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

Again, for circles, this works perfectly. For non-circular ellipses, it doesn't.

After writing this up, I found this beautiful illustration, which exactly demonstrates what I'm dealing with. Unfortunately, the Postscript solution isn't helpful for me. I need to know what to do to calculate the correct angles.

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

2 Answers

1
votes

I've found my answer here. As I expected, my understanding of the angles was incorrect. To perform my mouse tracking to reshape the arc, I need to find the intersection of a line segment with an ellipse and work backward from the parametric ellipse equations to find the correct angle.

0
votes

Thanks to @goug I was able to fix a similar issue with QPainterPath::arcTo.

In my case I need an elliptical arc that behaves like a normal arc. Where start and end angles are controlled by a user. The start angle doesn't require any corrections, but the end angle does.

Here is a code that shows how to bypass this issue.

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);