programming-examples/java/Computer_Graphics/NonSynchronizedClock.java
2019-11-15 12:59:38 +01:00

163 lines
6.3 KiB
Java

import java.awt.*;
import java.awt.geom.*;
import java.util.Date;
/**
* An example for an animation based on combined stepwise transformations.
* A square-shaped clock with a seconds hand moves over the window.
* The second hand turns, but not in seconds.
* This example does not use the double buffering technique, so that
* interrupting the program is difficult and flickering might occur.
*
* @author Frank Klawonn
* Last change 22.01.2005
*/
public class NonSynchronizedClock extends Frame
{
private int windowWidth;
private int windowHeight;
/**
* Constructor
*
* @param width The width of the window.
* @param height The height of the window.
*/
NonSynchronizedClock(int width, int height)
{
//Enables the closing of the window.
addWindowListener(new MyFinishWindow());
windowWidth = width;
windowHeight = height;
}
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
//The lines should have a thickness of 3.0 instead of 1.0.
g2d.setStroke(new BasicStroke(3.0f));
//Use of antialiasing to have nicer lines.
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
/*yUp defines a translation allowing the specification of objects in "real"
coordinates where the y-axis points upwards and the origin of the coordinate
system is located in the lower left corner of the window.
*/
AffineTransform yUp = new AffineTransform();
yUp.setToScale(1,-1);
AffineTransform translate = new AffineTransform();
translate.setToTranslation(0,windowHeight);
yUp.preConcatenate(translate);
//Apply the transformation to the Graphics2D object to draw everything
//in "real" coordinates.
g2d.transform(yUp);
//This rectangle serves as a background, framing the whole scene.
Rectangle2D.Double windowFrame = new Rectangle2D.Double(50,50,
windowWidth-100,
windowHeight-100);
//Height and width of the clock.
double frameSize = 100;
//Length of the second hand.
double handLength = 40;
//Width of the second hand.
double handWidth = 5;
//Generate the frame of the clock in the centred around the origin.
Rectangle2D.Double clockFrame = new Rectangle2D.Double(-frameSize/2,
-frameSize/2,
frameSize,
frameSize);
//Generate the second hand starting at the origin and pointing upwards
//in the beginning.
Rectangle2D.Double clockHand = new Rectangle2D.Double(-handWidth/2,
0,
handWidth,
handLength);
//This rotation specifies, how far the second hand should be turned
//in each step.
AffineTransform singleRotation = new AffineTransform();
singleRotation.setToRotation(-Math.PI/180);
//This transformation is for accumulating the single step rotations.
AffineTransform accumulatedRotation = new AffineTransform();
//This translation specifies, how far the clock should move
//in each step.
AffineTransform singleTranslation = new AffineTransform();
singleTranslation.setToTranslation(2,1);
//This transformation is for accumulating the single step translations.
AffineTransform accumulatedTranslation = new AffineTransform();
//In order to position the clock inside the window in the beginning
//of the animation, the translation incorporates already a shift
//to the right and upwards.
accumulatedTranslation.setToTranslation(150,150);
//Accumulated transformation of the second hand: First rotate, then translate.
AffineTransform handTransform = new AffineTransform();
//In this loop, the positions of the clock and the second hand
//are updated and the updated image is drawn.
for (int i=0; i<250; i++)
{
//Accumulated transformation of the second hand: First rotate, then translate.
handTransform.setTransform(accumulatedRotation);
handTransform.preConcatenate(accumulatedTranslation);
//Clear the window.
clearWindow(g2d);
//Draw the background rectangle.
g2d.draw(windowFrame);
//Draw the frame of the clock.
g2d.draw(accumulatedTranslation.createTransformedShape(clockFrame));
//Draw the second hand.
g2d.fill(handTransform.createTransformedShape(clockHand));
//Computation of the accumulated translation of the clock.
accumulatedTranslation.preConcatenate(singleTranslation);
//Computation of the accumulated rotation of the second hand.
accumulatedRotation.preConcatenate(singleRotation);
//A short waiting time until the next frame is drawn.
sustain(100);
}
}
/**
* A method for clearing a window (drawing all white) of windowWidth x windowHeight.
*
* @param g2d Graphics2D object used for drawing.
*/
public void clearWindow(Graphics2D g)
{
g.setPaint(Color.white);
g.fill(new Rectangle(0,0,windowWidth,windowWidth));
g.setPaint(Color.black);
}
/**
* A method for a delay of t milliseconds.
* This method is used here only to keep the program simple.
* This method involves active waiting, consuming unnecessary processor capicity.
* For real applications threads should be used.
*
* @param t Waiting time in milliseconds.
*/
public void sustain(long t)
{
long finish = (new Date()).getTime() + t;
while( (new Date()).getTime() < finish ) {}
}
public static void main(String[] argv)
{
int width = 780;
int height = 530;
NonSynchronizedClock f = new NonSynchronizedClock(width,height);
f.setTitle("Animation based on geometric transformations");
f.setSize(width,height);
f.setVisible(true);
}
}