The tube-based kaleidoscope was invented in 1816 by Scottish born Sir David Brewster (a scientist and inventor, among other professions). He named his invention kaleidoscope from the Greek words, kalos (beautiful), eidos (form), and scopes (watcher). Simply put, the kaleidoscope is a "beautiful form watcher."
Kaleidoscopes are enchanting devices. This enchantment stems from the symmetric and colorful designs that occur as tubes containing bits of colored glass and mirrors rotate. It's no wonder that many computer programs, including Java applets, have been created to reveal this symmetry. For example, I recently encountered a really nice kaleidoscope applet called Kaleidoscope Painter. This applet paints an endless variety of symmetric and colorful designs.
This Java Fun and Games installment introduces two more kaleidoscope applets. The first applet, Kal1, divides its drawing area into four quadrants. Randomly located and colored lines are drawn in the first quadrant. Symmetry
occurs by reflecting that quadrant's lines into the other three quadrants. Listing 1 presents this applet's source code.
Listing 1. Kal1.java
// Kal1.java
import java.awt.*;
import java.applet.Applet;
public class Kal1 extends Applet implements Runnable
{
// Maximum iterations before background is cleared.
final static int MAXITER = 200;
// Animation thread.
Thread runner;
// Current number of iterations counter.
int counter;
// Width of applet drawing area.
int width;
// Height of applet drawing area.
int height;
// Image buffer.
Image imBuffer;
// Graphics context associated with image buffer.
Graphics imG;
// Initialize the applet. Invoked by Web browser.
public void init ()
{
// Acquire the applet's width and height.
width = getSize ().width;
height = getSize ().height;
// Create an image buffer.
imBuffer = createImage (width, height);
// Get a graphics context associated with the buffer, so we can draw
// onto the buffer.
imG = imBuffer.getGraphics ();
// Initialize image buffer by setting all pixels to black.
imG.setColor (Color.black);
imG.fillRect (0, 0, width, height);
}
// Start the applet. Invoked by Web browser.
public void start ()
{
// If no thread exists, create a Thread object that associates with the
// current Kal object, and start a new thread that invokes the current
// Kal object's run() method. Before doing that, clear the counter so
// we don't draw only a few lines before clearing the applet's drawing
// area.
if (runner == null)
{
counter = 0;
runner = new Thread (this);
runner.start ();
}
}
// Paint the applet's drawing area. Invoked by Web browser.
public void paint (Graphics g)
{
// Clear image buffer before it gets too crowded.
if (++counter == MAXITER)
{
imG.setColor (Color.black);
imG.fillRect (0, 0, width, height);
counter = 0;
}
// Generate a random color and establish that color as the image buffer
// Graphics context's drawing color.
Color c = new Color (rnd (256), rnd (256), rnd (256));
imG.setColor (c);
// Obtain starting coordinates for line in upper-left quadrant.
int x1 = rnd (width / 2);
int y1 = rnd (height / 2);
// Obtain ending coordinates for line in upper-left quadrant.
int x2 = rnd (width / 2);
int y2 = rnd (height / 2);
// Draw the line in the upper-left quadrant.
imG.drawLine (x1, y1, x2, y2);
// Reflect the line into the upper-right quadrant.
imG.drawLine (width - x2, y2, width - x1, y1);
// Reflect the line into the lower-left quadrant.
imG.drawLine (x1, height - y1, x2, height - y2);
// Reflect the line into the lower-right quadrant.
imG.drawLine (width - x2, height - y2, width - x1, height - y1);
// Blit the image buffer to the applet's drawing area.
g.drawImage (imBuffer, 0, 0, this);
}
// Obtain a random integer.
static int rnd (int limit)
{
// Return a random integer that ranges from 0 through limit-1.
return (int) (Math.random () * limit);
}
// Run the animation.
public void run ()
{
// Obtain a reference to the thread that was started in the applet's
// start() method.
Thread current = Thread.currentThread ();
// As long as runner contains the same reference, keep looping. The
// reference in runner becomes null when the applet's stop() method
// executes.
while (current == runner)
{
// Invoke the paint(Graphics g) method for another drawing operation.
repaint ();
// Pause for 50 milliseconds, to achieve an eye-pleasing display.
try
{
Thread.sleep (50);
}
catch (InterruptedException e)
{
}
}
}
// Stop the applet. Invoked by Web browser.
public void stop ()
{
// Tell the drawing thread to terminate.
runner = null;
}
// The AWT invokes the update() method in response to the repaint() method
// calls that are made in the run() method. The default implementation of
// this method, which is inherited from the Container class, clears the
// applet's drawing area to the background color prior to calling paint().
// This clearing followed by drawing causes flicker. Kal1 overrides
// update() to prevent the background from being cleared, which eliminates
// the flicker.
public void update (Graphics g)
{
paint (g);
}
}
Listing 1's run() method contains the applet's animation loop. That loop alternately calls repaint(), which causes the AWT (Abstract Window Toolkit) to invoke update(), or sleeps for 50 milliseconds to achieve an animation rate consistent across different computer speeds.
Archived Discussions (Read only)