diff --git a/src/msw/graphics.cpp b/src/msw/graphics.cpp index be6c7bce1b..16aee51d0b 100644 --- a/src/msw/graphics.cpp +++ b/src/msw/graphics.cpp @@ -1293,26 +1293,88 @@ void wxGDIPlusPathData::GetCurrentPoint( wxDouble* x, wxDouble* y) const void wxGDIPlusPathData::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAngle, double endAngle, bool clockwise ) { - double sweepAngle = endAngle - startAngle ; - if( fabs(sweepAngle) >= 2*M_PI) + double angle; + + // For the sake of consistency normalize angles the same way + // as it is done in Cairo. + if ( clockwise ) { - sweepAngle = 2 * M_PI; + // If endAngle < startAngle it needs to be progressively + // increased by 2*M_PI until endAngle > startAngle. + if ( endAngle < startAngle ) + { + while ( endAngle <= startAngle ) + { + endAngle += 2.0*M_PI; + } + } + + angle = endAngle - startAngle; } else { - if ( clockwise ) + // If endAngle > startAngle it needs to be progressively + // decreased by 2*M_PI until endAngle < startAngle. + if ( endAngle > startAngle ) { - if( sweepAngle < 0 ) - sweepAngle += 2 * M_PI; + while ( endAngle >= startAngle ) + { + endAngle -= 2.0*M_PI; + } + } + + angle = startAngle - endAngle; + } + + // Native GraphicsPath.AddArc() does nothing when sweep + // angle equals 0 (even current point is not updated) + // so we have to handle this case on our own. + if ( angle == 0 ) + { + wxPoint2DDouble start = wxPoint2DDouble(cos(startAngle) * r, sin(startAngle) * r); + + if (m_figureOpened) + { + AddLineToPoint(start.m_x + x, start.m_y + y); } else { - if( sweepAngle > 0 ) - sweepAngle -= 2 * M_PI; - + MoveToPoint(start.m_x + x, start.m_y + y); } - } - m_path->AddArc((REAL) (x-r),(REAL) (y-r),(REAL) (2*r),(REAL) (2*r),wxRadToDeg(startAngle),wxRadToDeg(sweepAngle)); + + return; + } + + REAL x0 = (REAL)(x-r); + REAL y0 = (REAL)(y-r); + REAL dim = (REAL)(2*r); + if ( angle >= 2.0*M_PI ) + { + // In addition to arc we need to draw full circle(s). + // Remarks: + // 1. Parity of the number of the circles has to be + // preserved because this matters when path would be + // filled with wxODDEVEN_RULE flag set (using + // FillModeAlternate mode) when number of the edges + // is counted. + // 2. With GraphicsPath.AddEllipse() we cannot + // control the start point of the drawn circle + // so we need to construct it from two arcs (halves). + int numCircles = (int)(angle / (2.0*M_PI)); + numCircles = (numCircles - 1) % 2 + 1; + for( int i = 0; i < numCircles; i++ ) + { + m_path->AddArc(x0, y0, dim, dim, + wxRadToDeg(startAngle), clockwise ? 180 : -180); + m_path->AddArc(x0, y0, dim, dim, + wxRadToDeg(startAngle+M_PI), clockwise ? 180 : -180); + } + // We need to reduce the angle to [0..2*M_PI) range + angle = fmod(angle, 2.0*M_PI); + } + + m_path->AddArc(x0, y0, dim, dim, wxRadToDeg(startAngle), + wxRadToDeg(clockwise ? angle : -angle)); // After calling AddArc() the native current point will be updated and can be used. m_logCurrentPointSet = false; }