Java by Example - rotating lines and polygons

back 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 next

To rotate things, we need to convert polar to cartesian coordinates:
x = r * Math.cos(theta); and y = r * Math.sin(theta);
Polar coordinates (r, theta) are just another way of specifying points in a 2D plane, where r represents the distance of a point from the center and theta the angle from the horizontal axis (x-axis) through the center. The following applet shows this principle in a minimized form, it rotates a hand around the center and displays the angle accordingly.

//Sourcecode

import java.awt.*;
import java.applet.*;

public class Project40 extends Applet implements Runnable
{
    Thread runner;
    Image Buffer;
    Graphics gBuffer;
    int angle;

    public void init()
    {
        //create graphics buffer, the size of the applet
        Buffer=createImage(size().width,size().height);
        gBuffer=Buffer.getGraphics();
    }

    public void start()
    {
        if (runner == null)
        {
            runner = new Thread (this);
            runner.start();
        }
    }

    public void stop()
    {
        if (runner != null)
        {
            runner.stop();
            runner = null;
        }
    }

    public void run()
    {
        while(true)
        {
            try {runner.sleep(250);}
            catch (Exception e) { }

            repaint();
        }
    }

    void drawStuff()
    {
        //paint background black
        gBuffer.setColor(Color.black);
        gBuffer.fillRect(0,0,size().width,size().height);

        //get the center of the applet
        Point p=new Point(size().width/2, size().height/2);
        //define the hand length
        int LENGTH=70;

        //calculate the vector, using the constant Pi
        double vector = angle * Math.PI*2 / 360.0;

        int vx=(int)(p.x+LENGTH*Math.sin(vector));
        int vy=(int)(p.y-LENGTH*Math.cos(vector));

        gBuffer.setColor(Color.yellow);
        //the hand
        gBuffer.drawLine(p.x, p.y, vx, vy);
        //the round "axis"
        gBuffer.drawOval(p.x-6,p.y-6,12,12);

        //display the angle in degrees
        gBuffer.setFont(new Font("Helvetica",Font.PLAIN,13));
        gBuffer.drawString("Angle="+angle+"°",10,20);

        //increase the angle, to move the hand
        if(angle<360)
            angle++;
        else
            angle=0;
    }

    public void update(Graphics g)
    {
        paint(g);
    }

    public void paint(Graphics g)
    {
        drawStuff();
        g.drawImage (Buffer,0,0, this);
    }
}

With the knowledge we have gained now, it is not very difficult to make a real analog clock with hands, like this one here. Note that Java doesn't allow to specify a pen with more than 1 pixel width, so you would have to draw several parallel lines in order to increase the width of the clock hands.

//Sourcecode

import java.awt.*;
import java.applet.*;
import java.util.*;

public class Project41 extends Applet implements Runnable
{
    Thread runner;
    Image Buffer;
    Graphics gBuffer;
    int angle;

    public void init()
    {
        Buffer=createImage(size().width,size().height);
        gBuffer=Buffer.getGraphics();
    }

    public void start()
    {
        if (runner == null)
        {
            runner = new Thread (this);
            runner.start();
        }
    }

    public void stop()
    {
        if (runner != null)
        {
            runner.stop();
            runner = null;
        }
    }

    public void run()
    {
        while(true)
        {
            try {runner.sleep(100);}
            catch (Exception e) { }

            repaint();
        }
    }

    void drawStuff()
    {
        //paint background black
        gBuffer.setColor(Color.black);
        gBuffer.fillRect(0,0,size().width,size().height);

        //get the center of the applet
        Point p=new Point(size().width/2, size().height/2);

        //define the hand lengths
        int S_LENGTH=85, M_LENGTH=80, H_LENGTH=60;

        Date d=new Date();
        int sec=d.getSeconds();
        int min=d.getMinutes();
        int hour=d.getHours();

        //calculate the vectors, using the constant Pi
        double vs = sec * Math.PI*2 / 60.0;
        double vm = min * Math.PI*2 / 60.0;
        double vh = hour * Math.PI*2 / 12.0 + vm / 12.0;

        int sx=(int)(p.x+S_LENGTH*Math.sin(vs));
        int sy=(int)(p.y-S_LENGTH*Math.cos(vs));

        int mx=(int)(p.x+M_LENGTH*Math.sin(vm));
        int my=(int)(p.y-M_LENGTH*Math.cos(vm));

        int hx=(int)(p.x+H_LENGTH*Math.sin(vh));
        int hy=(int)(p.y-H_LENGTH*Math.cos(vh));

        //the second hand
        gBuffer.setColor(Color.yellow);
        gBuffer.drawLine(p.x, p.y, sx, sy);

        //the minute hand
        gBuffer.setColor(Color.red);
        gBuffer.drawLine(p.x, p.y, mx, my);

        //the hour hand
        gBuffer.setColor(Color.green);
        gBuffer.drawLine(p.x, p.y, hx, hy);

        //the face and axis
        gBuffer.setColor(Color.blue);
        gBuffer.fillOval(p.x-6,p.y-6,12,12);
        gBuffer.drawOval(p.x-90,p.y-90,180,180);
    }

    public void update(Graphics g)
    {
        paint(g);
    }

    public void paint(Graphics g)
    {
        drawStuff();
        g.drawImage (Buffer,0,0, this);
    }
}

Now let's rotate some polygons! This is not quite easy, we will need a few helper functions to do the conversions for us. They can handle any polygon you define and rotate it with the specified angle. Everything should become clear from the sourcecode Only your imagination is the limit now for your own creations!

//Sourcecode

import java.awt.*;
import java.applet.*;

public class Project42 extends Applet implements Runnable
{
    Thread runner;
    Image Buffer;
    Graphics gBuffer;
    //cx, cy = center of rotation
    int angle, cx, cy;
    //variables for rotation
    double radians = 0.0;
    double cos = 1.0;
    double sin = 0.0;

    public void init()
    {
        //create graphics buffer, the size of the applet
        Buffer=createImage(size().width,size().height);
        gBuffer=Buffer.getGraphics();
        cx=size().width/2;
        cy=size().height/2;
    }

    public void start()
    {
        if (runner == null)
        {
            runner = new Thread (this);
            runner.start();
        }
    }

    public void stop()
    {
        if (runner != null)
        {
            runner.stop();
            runner = null;
        }
    }

    public void run()
    {
        while(true)
        {
            try {runner.sleep(25);}
            catch (Exception e) { }

            repaint();
        }
    }

    int rotate_x(int x, int y)
    {
        return ((int) (cx + x * cos - y * sin));
    }

    int rotate_y(int x, int y)
    {
        return ((int) (cy + y * cos + x * sin));
    }

    void SetAngle(double a)
    {
        radians = (a * 2 * Math.PI) / 360;

        cos = Math.cos(radians);
        sin = Math.sin(radians);
    }

    void RotatePolygon(int x[], int y[], int n)
    {
        int new_x[] = new int [n];
        int new_y[] = new int [n];

        for(int i=0; i<n; i++)
        {
            new_x[i]=rotate_x(x[i], y[i]);
            new_y[i]=rotate_y(x[i], y[i]);
        }

        gBuffer.fillPolygon(new_x, new_y, n);
    }

    void drawStuff()
    {
        //paint background black
        gBuffer.setColor(Color.black);
        gBuffer.fillRect(0,0,size().width,size().height);

        int radius;
        int x[];
        int y[];

        //the triangle
        radius=140;
        x= new int[3];
        y= new int[3];

        x[0]=-20;
        x[1]=0;
        x[2]=20;

        y[0]=-radius+80;
        y[1]=-radius;
        y[2]=-radius+80;

        gBuffer.setColor(Color.red);
        RotatePolygon(x, y, 3);

        //the square
        radius=60;
        x= new int[4];
        y= new int[4];

        x[0]=radius;
        x[1]=radius+50;
        x[2]=radius+50;
        x[3]=radius;

        y[0]=-25;
        y[1]=-25;
        y[2]=25;
        y[3]=25;

        gBuffer.setColor(Color.blue);
        RotatePolygon(x, y, 4);

        //the top-down triangle
        radius=60;
        x= new int[3];
        y= new int[3];

        x[0]=-50;
        x[1]=0;
        x[2]=50;

        y[0]=radius+50;
        y[1]=radius;
        y[2]=radius+50;

        gBuffer.setColor(Color.green);
        RotatePolygon(x, y, 3);

        //the hexagon
        radius=120;
        x= new int[6];
        y= new int[6];

        x[0]=-radius;
        x[1]=-radius+30;
        x[2]=-radius+60;
        x[3]=-radius+60;
        x[4]=-radius+30;
        x[5]=-radius;

        y[0]=-20;
        y[1]=-35;
        y[2]=-20;
        y[3]=20;
        y[4]=35;
        y[5]=20;

        gBuffer.setColor(Color.magenta);
        RotatePolygon(x, y, 6);

        //display the angle in degrees
        gBuffer.setColor(Color.yellow);
        gBuffer.setFont(new Font("Helvetica",Font.PLAIN,13));
        gBuffer.drawString("Angle="+angle+"°",10,20);

        //the center mark
        gBuffer.setColor(Color.white);
        gBuffer.drawOval(cx-6,cy-6,12,12);
        gBuffer.drawLine(cx-12,cy,cx+12,cy);
        gBuffer.drawLine(cx,cy-12,cx,cy+12);

        if(angle<360)
            angle++;
        else
            angle=0;

        SetAngle(angle);
    }

    public void update(Graphics g)
    {
        paint(g);
    }

    public void paint(Graphics g)
    {
        drawStuff();
        g.drawImage (Buffer,0,0, this);
    }
}

back 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 next

0 - setup - getting your tools ready
1 - basic graphics functions
2 - simple methods and basic data types
3 - IF, ELSE and SWITCH: basic control structures
4 - introducing the operators
5 - methods with and without a return value
6 - using methods and basic mouse functions
7 - fonts, random numbers and timers
8 - flicker free graphics, GIF and JPEG display
9 - animation with GIF pictures, sprite animation
10 - loops, advanced color functions
11 - random colors and arrays
12 - digital clocks, HTML page parameters
13 - introducing classes and objects
14 - using the Vector class
15 - using mouseMove and mouseDrag
16 - keyboard commands and playing sound
17 - detecting collisions and intersections
18 - a Bouncing Balls applet
19 - fun with letters and words
20 - rotating lines and polygons
21 - sorting and shuffling


© 2000 by Johannes Wallroth
www.programming.de

watson@programming.de