Josue Espinosa Josue Espinosa - 3 months ago 16
Java Question

Simple circle rotation (simulate motion)

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)

Answer

Basically, you need to calculate the point on the circle, based on an angel 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);

        }

    }

}