Michener’s Algorithm An efficient scheme for drawing circles (and filling circular disks)

advertisement
Michener’s Algorithm
An efficient scheme for drawing
circles (and filling circular disks)
on a raster graphics display
Scan conversion
•
•
•
•
•
•
Geometric objects possess implicit parameters
Example: A circle has a ‘center’ and a ‘radius’
Its equation is: (x – xc)2 + (y - yc)2 = R2
x and y are from the continuum of real numbers
CRT display is a discrete 2D array of ‘pixels’
So drawing a circle requires a conversion, from
something continuous into something discrete
• In computer graphics it’s called scan conversion
• Imperfections: unavoidable, but to be minimized
Graphics Animations
• Fast drawing is essential for animations
• Some guidelines for speed:
– eliminate all redundant computations
– prefer integer arithmetic to floating-point
– prefer add and subtract to multiply or divide
• Famous example: ‘Michener Algorithm’
• We can use it later with our ‘pong’ game
Eight-fold symmetry
(-x, y)
(x, y)
(-y, x)
(y, x)
(-y, -x)
(y, -x)
(-x, -y)
(x, -y)
Compute only one octant
Subroutine: draw_octant_points
Arguments: int x, y, xcent, ycent, color;
draw_pixel( xcent + x, ycent + y, color );
draw_pixel( xcent + y, ycent + x, color );
draw_pixel( xcent - x, ycent + y, color );
draw_pixel( xcent - y, ycent + x, color );
draw_pixel( xcent + x, ycent - y, color );
draw_pixel( xcent + y, ycent - x, color );
draw_pixel( xcent - x, ycent - y, color );
draw_pixel( xcent - y, ycent - x, color );
The “best” pixel to draw?
Blue pixel: too far from center
(E>0)
Red pixel: too near the center
(E<0)
Error-term: E = (x2 + y2) – R2
Decision at n-th stage
Pn-1
An ?
yn-1
Bn ?
xn-1
xn
Algorithm: compute sum = error( An ) + error( Bn );
If ( sum < 0 ) choose A n; otherwise choose B n.
Formula: sum of error-terms
•
•
•
•
Assume circle has radius R, center (0,0)
error( An) = (xn-1+1)2 + (yn-1)2 – R2
error( Bn) = (xn-1+1)2 + (yn-1 – 1)2 – R2
sumn = 2(xn-1+1)2 + 2(yn-1)2 –2(yn-1) + 12R2
• Now, how is sumn different from sumn+1:
– If An is chosen at the n-th step?
– If Bn is chosen at the n-th step?
Difference Equation
• Observe that: sumn+1 – sumn =
4xn-1 + 6 + 2(yn2 – yn-12) – 2(yn – yn-1)
• When An is selected at n-th stage:
– we will have yn = yn-1
– thus: sumn+1 = sumn + 4xn-1 + 6
• When Bn is selected at n-th stage:
– we will have yn = yn-1 - 1
– thus: sumn+1 = sumn + 4(xn-1 – yn-1) + 10
Algorithm initialization
• We start with the point P0 = (x0,y0), where
x0 = 0 and y0 = R
• In this case: A1 = (1, R) and B1 = (1, R-1)
• So the initial ‘sum-of-errors’ term will be:
sum1 = error(A1) + error(B1)
= [(12 + R2) – R2] + [(12 + R2–2R+1) – R2]
= 3 – 2R
Michener’s Algorithm
int x = 0, y = R, sum = 3 – 2*R;
while ( x <= y )
{
draw_octant_points( x, y, xc, yc, color );
if ( sum < 0 ) sum += 4*x + 6;
else { sum += 4*(x - y) + 10; --y; }
++x;
}
Reference
• Francis S. Hill, jr., “Computer Graphics,”
Macmillan (1990), pp. 433-435.
• NOTE: Michener’s circle-drawing method
owes its inspiration to a famous algorithm
for efficient line-drawing, devised in 1965
by J. E. Bresenham (see the IBM Systems
Journal, vol 4, pp. 305-311).
Circle ‘fill’ also exploits symmetry
(-x, y)
(x, y)
(-y, x)
(y, x)
(-y, -x)
(y, -x)
(-x, -y)
(x, -y)
Subroutine: draw_segments
Arguments: int x, y, xc, yc, color;
draw_horiz( xc – x, xc + x, yc + y, color );
draw_horiz( xc – x, xc + x, yc - y, color );
draw_horiz( xc – y, xc + y, yc + x, color );
draw_horiz( xc – y, xc + y, yc - x, color );
draw_horiz( int xlo, xhi, y, color );
Clipping to screen boundaries:
If (( y < ymin )||( y > ymax )) return;
if ( xlo < xmin ) xlo = xmin;
if ( xhi > xmax ) xhi = xmax;
Drawing the horizontal segment:
for (x = xlo; x <= xhi; x++)
draw_pixel( x, y, color );
Demo-program
•
•
•
•
•
Try the ‘michener.cpp’ demo
It uses VESA graphics-mode 0x0103
Screen resolution is 800x600
Color depth is 8 bits-per-pixel (8bpp)
SVGA’s Linear Frame Buffer is enabled by
calling VESA’s Set Display Mode service
with bit #14 of the mode ID-number set
In-Class Exercise #1
• Modify the ‘michener.cpp’ demo:
– Use the standard ‘rand()’ function
– Draw lots of color-filled circles
– Stop if user hits <ESCAPE> key
• NOTE: For this latter feature, we need to
recall how to set up the terminal keyboard
so it uses a ‘non-canonical’ input-mode
Animation with ‘image tearing’
• We used Michner’s Algorithm in a graphics
animation demo (named ‘bouncing.cpp’)
• But you will see undesirable ‘tearing’ of the
bouncing ball’s image – because we drew
a large number of pixels, and computed a
large number of pixel-locations – twice for
each displayed frame (erase, then redraw)
• Not enough drawing time during ‘retrace’!
What can we do about it?
• One idea is to draw a smaller-sized ball
• Another idea is to draw only once – i.e.
include enough extra pixels around the
new ball’s perimeter to hide the old one
• Also we could ‘pre-compute’ coordinates
• An important general technique is to use
off-screen display memory to ‘prepare’ a
new screen-image, and then do a ‘bitblit’
SuperVGA’s hardware
• The graphics processor has the capability
to switch the CRTC’s ‘start_address’, so
we see a new full-screen image displayed
almost instantly (i.e., just one or two CPU
instructions), instead of a copying a screen
• But doing this for higher-resolution SVGA
display-modes requires accessing one or
more of the nonstandard VGA extensions
VESA’s BIOS-Extensions
• Video Electronics Standards Association
defines a ROM-BIOS service that can be
invoked to reprogram CRT Start_Address
in a standard way for compliant systems
• For a particular vendor’s graphics card, we
can discover how to directly reprogram the
CRT’s Start-Address, by ‘trapping’ the I/O
instructions used in the ROM-BIOS routine
Using ‘off-screen’ video memory
CRT Controller’s Start-Address (default=0)
Visible
screen
The currently displayed image is
defined in this region of VRAM
while an alternative image is prepared
for display in this region of VRAM
When the ‘alternate’ memory region
is ready to be displayed, the CRT
Start-Address register is rewritten,
instantaneously changing what the
user sees on the display monitor
The technique is called ‘page flipping’
Alternate
screen
VRAM
VBE service 0x07
• This ROM-BIOS service can be called to
obtain or modify the CRT Start-Address
• It isn’t instantaneous – because of all the
parameter-passing and changing of CPU
execution-mode and transitions back and
forth from user-space to kernel-space
• But it might be fast enough to ‘cure’ the
image-tearing we saw in ‘bouncing’ demo
In-class exercise #2
• Look at documentation for VESA service 7
• See if you can modify the main animation
loop in our ‘bouncing.cpp’ program so the
image-frames are alternately drawn in two
different ‘pages’ of the video memory (i.e.,
implement the ‘page-flipping’ idea): while
one frame is being viewed by the user, the
next frame is being readied out-of-sight
Download