Short version: How can I convert an SVG elliptical arc to a QPainterPath arc?
Long version: Using SVG++ my code receives a callback in parsing SVG files when it comes curves, ellipses or circles.
void onPathEllipticalArcTo(double rx, double ry, double x_axis_rotation, bool large_arc_flag, bool sweep_flag, double x, double y);
where:
- rx is the X radius of the ellipse
- ry is the Y radius of the ellipse
- x_axis_rotation is effectively the rotation of the ellipses in related to the X-axis
- large_arc_flag indicates whether we mean the outer or the inner arc
- sweep_flag indicates the direction of the arc
- x and y are the end point coordinates of the arc
See this SVG article on elliptical arc curves for an illustration on what these parameters mean.
Note that the starting point of the curve is passed to my program using a simple moveTo(x,y)
instruction sent ahead of the above instruction.
All of this needs to be translated into a call to QPainterPath::arcTo()
[c++] [python].
The problem is, the way in which both achieve the arc is done rather differently as you can see.
A QPainterPath::arcTo()
expects:
- The rectangle in which the curve will fit
- The starting angle of the curve
- The sweep length of the curve
See the linked article(s) for an illustration on how this is achieved.
I think there is a fair amount of maths/geometry involved in this conversion.
My (naive) approach so far comes down to:
In this image (see earlier SVG callback information):
- [A] are the coordinates that SVG++ have us
moveTo()
before we draw the arc. - [B] are the coordinates that SVG++ will have us draw the arc to (i.e.
x
andy
params). rx
andry
are obviously the radii of the ellipse.x_axis_rotation
is 0 degrees.large_arc_flag
would be 0/false.sweep_flag
would be 0/false.
To be able to call QPainterPath::arcTo()
I need to work out the shaded rectangle.
The width of this rectangle is of course very easily calculated. The starting angle of the curve will conveniently be zero deg and sweep angle in this instance will be 180 deg (but it may not be if A and B are not on the same Y coordinate).
But how do I calculate the height of the rectangle?
If it helps in explaining the maths to us, let:
A
= { 2, 3}B
= { 6, 3}rx
~= 2.45ry
~= 4.28
Maybe your solution would demonstrate also that it works even when [A] and [B] are not on the same X-axis or the same Y-axis?
The ultimate goal is that my application needs to be able to draw an arc upon a received SVG instruction. I am aware that there is a chance that I can achieve this in a much simpler way than I suggest here?
Important: I cannot use class QSvgRenderer. Apparently it is too limited in functionality for the complexity of SVG that we parse? So I am told.
Note: there is an error in my logic relating to QPainterPath::arcTo()
. This does not invalidate the comments thus far. Once I have a proven solution then I will update this question with the correct logic and an enhanced graph.