1

I have a simple animation in Java that consists of a wheel moving across a window. It is just a plain circle that starts off of the screen from the left, enters and continues to the right until it goes off of the screen. Then it loops and repeats this process.

X is a variable that contains the position of the wheel. It can be between -(wheel width) and the window size + the wheel width.

I would like to simulate rotation by drawing a circle within this wheel, that rotates around the circle as if it were attached.

Imagine a bike wheel in real life with a red flag on the wheel. As the wheel rotates, the red flag would be on the edge on the wheel moving as the wheel progresses. This is the behavior I want.

I am getting a percentage to pass into my wheel class like this:

int percentage = x/windowWidth;

Each frame that the wheel moves, I call wheel.rotate(percentage).

This is the implementation:

private int diameter = 50;        
private final int SPOKE_DIAMETER = diameter/5;

    public void rotate(double percent){
        this.percent = percent;
        this.theta = percent*(PI*2);
        System.out.println(percent*PI);
    }

    public void paintComponent(Graphics canvas)
    {
        // wheel
        canvas.setColor(Color.gray);
        canvas.fillOval(0, 0, diameter, diameter);

        // spinning flag
        canvas.setColor(Color.red);
        canvas.fillOval((int)(percent*diameter),(int)((sin((percent*(PI*2)))*diameter)), SPOKE_DIAMETER,SPOKE_DIAMETER);
    }

The x location works more or less how I wanted, but the y does not. It wiggles like a sin wave, which is expected (I did use sin...), however, I'm not sure how to alter my math to follow the circle around.

What is wrong with my implementation? (I'm not very good with drawing with trigonometric functions)

Peter O.
  • 32,158
  • 14
  • 82
  • 96
Josue Espinosa
  • 5,009
  • 16
  • 47
  • 81
  • Well, you could simply rotate the `Graphics` context... – MadProgrammer Sep 18 '14 at 22:36
  • Yes! I definitely would if I could, except i'm trying to use math (it is for a school project). – Josue Espinosa Sep 18 '14 at 22:37
  • Something like http://stackoverflow.com/questions/12964983/rotate-image-around-character-java/12971987#12971987 – MadProgrammer Sep 18 '14 at 22:40
  • I think the center follows a [trochoid](http://en.wikipedia.org/wiki/Trochoid). I haven't looked at this closely, but offhand it looks like the first parameter to `fillOval` needs a `cos` or something... if I understand the problem correctly. – ajb Sep 18 '14 at 22:40

1 Answers1

6

Basically, you need to calculate the point on the circle, based on an angle that the object should appear...

Like most things, I stole this off the internet somewhere, but it works...

protected Point getPointOnCircle(float degress, float radius) {

    int x = Math.round(getWidth() / 2);
    int y = Math.round(getHeight() / 2);

    double rads = Math.toRadians(degress - 90); // 0 becomes the top

    // Calculate the outter point of the line
    int xPosy = Math.round((float) (x + Math.cos(rads) * radius));
    int yPosy = Math.round((float) (y + Math.sin(rads) * radius));

    return new Point(xPosy, yPosy);

}

Based on an angel (in degrees) and the radius of the circle, this will return the x/y position along the circumference of the circle...

Rotate within

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class RotateWheel {

    public static void main(String[] args) {
        new RotateWheel();
    }

    public RotateWheel() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private float degrees = 0;

        public TestPane() {
            Timer timer = new Timer(40, new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    degrees += 0.5f;
                    repaint();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            int diameter = Math.min(getWidth(), getHeight());
            int x = (getWidth() - diameter) / 2;
            int y = (getHeight() - diameter) / 2;

            g2d.setColor(Color.GREEN);
            g2d.drawOval(x, y, diameter, diameter);

            g2d.setColor(Color.RED);
            float innerDiameter = 20;

            Point p = getPointOnCircle(degrees, (diameter / 2f) - (innerDiameter / 2));
            g2d.drawOval(x + p.x - (int) (innerDiameter / 2), y + p.y - (int) (innerDiameter / 2), (int) innerDiameter, (int) innerDiameter);

            g2d.dispose();
        }

        protected Point getPointOnCircle(float degress, float radius) {

            int x = Math.round(getWidth() / 2);
            int y = Math.round(getHeight() / 2);

            double rads = Math.toRadians(degress - 90); // 0 becomes the top

            // Calculate the outter point of the line
            int xPosy = Math.round((float) (x + Math.cos(rads) * radius));
            int yPosy = Math.round((float) (y + Math.sin(rads) * radius));

            return new Point(xPosy, yPosy);

        }

    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366