Fixed adding arc to wxGraphicsPath with GDI+ renderer.
To handle properly all combinations of the start and end angles and to ensure consistency with Cairo renderer behaviour there is necessary: 1. To normalize angle values the same way as it is done in Cairo. and 2. When end angle equals start angle then actually no arc should be added but current point of the path has to be updated. 3. When difference between end angle and start angle >= 2*pi then in addition to the arc itself also one or more full circles have to be added to the path. Closes #17558
This commit is contained in:
parent
9f9d593019
commit
1f49c4bf40
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user