0

I'm making a clock right now and currently my second hand, minute hand, and hour hand are all drawn graphically using a Line object with an (x0, y0) beginning coordinate and (x1, y1) end coordinate.

What's confusing me right now is how to make the second hand "tick" every time a second passes. That is, how can I update the (x1, y1) coordinate (since the beginning coordinate is always in the center of the clock, we don't need to update it) so that it will move clockwise 6 degrees? This is confusing to me because the direction of the unit circle (and thus the direction of radians) goes counter-clockwise.

yiwei
  • 4,022
  • 9
  • 36
  • 54
  • 1
    Take a look at [this answer](http://stackoverflow.com/questions/12964983/rotate-image-around-character-java/12971987#12971987), the basics are the same. You are correct, the direction moves anti-clockwise, so you need to invert you angle (subtract in stead of add) – MadProgrammer Oct 29 '12 at 05:46
  • `System.currentTimeMillis() / 1000` returns a second value, maybe you can track the difference from the start to the current `System.currentTimeMillis() / 1000`. – user1610406 Nov 28 '12 at 22:05

2 Answers2

2

There are a few methods. Since you probably know the radius of the clock, you can do

theta = (theta - 6)%360;
x1 = radius*cos(theta * PI/180);
y1 = radius*sin(theta * PI/180);
ehuang
  • 811
  • 1
  • 8
  • 17
  • can you clarify that a little? what is the `theta - 6` part? – yiwei Oct 29 '12 at 14:42
  • 1
    @59eagle 360 degrees in a circle. There are 60 seconds, so each second tick mark is 360/60 = 6 degrees apart. theta is the current angle, and subtracting 6 degrees will give us the next tick mark. – ehuang Oct 29 '12 at 14:50
  • @59eagle theta = 90 degrees corresponds to the point (0,1) in the unit circle, which is 12 o'clock. – ehuang Oct 29 '12 at 23:35
1

That example works surprisingly well...

public class TestClock {

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

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

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new ClockPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    protected class ClockPane extends JPanel {

        public ClockPane() {
            Timer timer = new Timer(1000, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    repaint();
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(false);
            timer.start();
        }

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

        protected Point getPointTo(float angle) {

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

            double rads = Math.toRadians(angle);
            // This is an arbitrary amount, you will need to correct for this
            // I'm working of a width of 200 pixels, so that makes the radius
            // 100...
            int radius = 100;

            // 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);

        }

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

            g2d.setColor(Color.RED);

            Calendar cal = Calendar.getInstance();
            int seconds = cal.get(Calendar.SECOND);
            float angle = -(360f * (seconds / 60f));
            angle += 90; // Correct for 0 being out to the right instead of up

            Point p = getPointTo(angle);

            int x = getWidth() / 2;
            int y = getHeight() / 2;

            g2d.drawLine(x, y, p.x, p.y);

            FontMetrics fm = g2d.getFontMetrics();
            String text = Integer.toString(seconds);
            g2d.drawString(text, getWidth() - fm.stringWidth(text), getHeight() - fm.getHeight() + fm.getAscent());

            g2d.dispose();
        }
    }
}
Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I used your method of calculating the coordinates, but I can't seem to get it right. My second hand grows progressively longer and the increments between moves are progressively smaller. `secondHand.reDraw(2.5, 2.5, (double) Math.round(secondHand.xEnd + Math.cos(rads) * 1.15), (double) Math.round(secondHand.yEnd - Math.sin(rads) * 1.15), Color.RED);` – yiwei Oct 29 '12 at 16:13
  • The x/y in the calculation are the centre point. The length of the hand is defined by the raids (1.15). From what i can tell, the calculation should look more like Math.round(2.5 + Math.cos(rads) * 1.15), this will give you the end point x point – MadProgrammer Oct 29 '12 at 18:47