From 1e0719ad81b76ededd69f44ff734249ceb2df665 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sat, 4 Jun 2016 14:31:47 +0200 Subject: [PATCH] Fixed drawing elliptic arcs in wxSVGFileDC. For some combinations of start and end angles, the wrong large-arc-flag was calculated. Fixed by correctly converting the wxDC angles to SVG angles (shift -90 degrees, and invert to clockwise direction). Arcs with the same start and end point (circles) where not drawn because the angle becomes 0 degrees. Fixed by drawing two half circles. Elliptic arcs with a non-transparent brush had an extra line from the center to the start point of the arc. Fixed by first drawing the arc without border, then only the border. Arcs with small angles would become invisible because the start and end point map to the same (integer) coordinate. Very large arcs would be distorted because the start and end point coordinates did not line up. Using floating point values resolves this. See issue #17557. --- src/common/dcsvg.cpp | 82 ++++++++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 25 deletions(-) diff --git a/src/common/dcsvg.cpp b/src/common/dcsvg.cpp index fbc93b1802..1cce7464da 100644 --- a/src/common/dcsvg.cpp +++ b/src/common/dcsvg.cpp @@ -812,12 +812,11 @@ void wxSVGFileDCImpl::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, write(s); } -void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea) +void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x, wxCoord y, wxCoord w, wxCoord h, double sa, double ea) { /* Draws an arc of an ellipse. The current pen is used for drawing the arc - and the current brush is used for drawing the pie. This function is - currently only available for X window and PostScript device contexts. + and the current brush is used for drawing the pie. x and y specify the x and y coordinates of the upper-left corner of the rectangle that contains the ellipse. @@ -831,45 +830,78 @@ void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h, counter-clockwise motion. If start is equal to end, a complete ellipse will be drawn. */ - //known bug: SVG draws with the current pen along the radii, but this does not happen in wxMSW - - NewGraphicsIfNeeded(); - - wxString s; //radius - double rx = w / 2; - double ry = h / 2; + double rx = w / 2.0; + double ry = h / 2.0; // center double xc = x + rx; double yc = y + ry; + // start and end coords double xs, ys, xe, ye; xs = xc + rx * cos (wxDegToRad(sa)); xe = xc + rx * cos (wxDegToRad(ea)); ys = yc - ry * sin (wxDegToRad(sa)); ye = yc - ry * sin (wxDegToRad(ea)); - ///now same as circle arc... + // svg arcs have 0 degrees at 12-o'clock instead of 3-o'clock + double start = (sa - 90); + if (start < 0) + start += 360; + while (abs(start) > 360) + start -= (start / abs(start)) * 360; - double theta1 = atan2(ys-yc, xs-xc); - double theta2 = atan2(ye-yc, xe-xc); + double end = (ea - 90); + if (end < 0) + end += 360; + while (abs(end) > 360) + end -= (end / abs(end)) * 360; - int fArc; // flag for large or small arc 0 means less than 180 degrees - if ( (theta2 - theta1) > 0 ) fArc = 1; else fArc = 0; + // svg arcs are in clockwise direction, reverse angle + double angle = end - start; + if (angle <= 0) + angle += 360; - int fSweep; - if ( fabs(theta2 - theta1) > M_PI) fSweep = 1; else fSweep = 0; + int fArc = angle > 180 ? 1 : 0; // flag for large or small arc + int fSweep = 0; // flag for sweep always 0 - s.Printf ( wxT(" \n"); - - if (m_OK) + wxString arcPath; + if (angle == 360) { - write(s); + // Drawing full circle fails with default arc. Draw two half arcs instead. + fArc = 1; + arcPath = wxString::Format(wxS(" \n"); + write(arcFill); + } + + wxDCBrushChanger setTransp(*GetOwner(), *wxTRANSPARENT_BRUSH); + NewGraphicsIfNeeded(); + + wxString arcLine = arcPath + wxS("\"/>\n"); + write(arcLine); } void wxSVGFileDCImpl::DoSetClippingRegion(int x, int y, int width, int height)