Don't know if this is any better, but has some advantages:
Code: Select all
void Graphics::DrawCircle( double _ox, double _oy, double _outer_radius, const Rect<double>& _clip, Color _color ) noexcept
// For outline thickness of 1
const auto rSq_inner = Square( _outer_radius - 1.0 );
const auto rSq_outer = Square( _outer_radius );
const auto outer_double = _outer_radius * 2.0;
// Calculate the bounding rectangle of the circle
const auto left = _ox - _outer_radius;
const auto top = _oy - _outer_radius;
const auto right = _ox + _outer_radius;
const auto bottom = _oy + _outer_radius;
// Clip the bounding rectangle to screen boundaries and translate
// back to -radius ( left_clip, top_clip ), +radius ( right_clip, bottom_clip )
const auto left_clip = std::max( 0.0, -left ) - _outer_radius;
const auto top_clip = std::max( 0.0, -top ) - _outer_radius;
const auto right_clip = std::min( ScreenWidth - right, outer_double ) - _outer_radius;
const auto bottom_clip = std::min( ScreenHeight - bottom, outer_double ) - _outer_radius;
// Loop through clipped bounding rectangle, from top to bottom,
// left to right skipping any pixels contained in the _clip Rect passed
// as parameter to the function
for( double y = top_clip; y < bottom_clip; ++y )
{
for( double x = left_clip; x < right_clip; ++x )
{
const auto sqDist = Square( x ) + Square( y );
if( sqDist > rSq_inner && sqDist < rSq_outer )
{
const auto px = x + _ox;
const auto py = y + _oy;
if( !_clip.Contains( Vec2<double>{ px, py } ) )
{
PutPixel( int( std::round( px ) ), int( std::round( py ) ), _color );
}
}
}
}
}
Advantages:
- Doesn't require calculating the begin and end angles before calling draw function.
- Doesn't require calculating sine or cosine.
- Only deals with per pixel changes, instead of arbitrary angle increments.
- Doesn't require calculating square root.
- Allows for easy screen clipping
Disadvantages:
- Requires iterating over the entire bounding rectangle.
- Doesn't actually calculate arcs.
Based on your criteria of just needing to clip a circle ( avoid drawing parts of the circle you want hidden ), this algorithm will work both for clipping against bounding rectangles and against drawing outside the screen boundaries preventing crashes.
Another way you could draw arcs is to use bezier curves. I'll have to refresh my memory a bit before I could show code for them or you can look them up yourself. Best thing about them is no angles, just plotting a few points and interpolating between them.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com