// // Pendulum.java // (c) Neil Gershenfeld 3/2/03 // integrates a parametrically-driven pendulum // import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import javax.swing.*; public class Pendulum extends JApplet implements Runnable, ActionListener { JTextField amplitude_field,frequency_field; final static int SIZE=500, NPTS=2000; double theta0=0.01, theta1=0, t=0, omega=1.5, amplitude=1, z; float x[] = new float[NPTS]; float y[] = new float[NPTS]; Thread thread; public void init() { int i; amplitude_field = new JTextField("1",5); amplitude_field.addActionListener(this); frequency_field = new JTextField("1.5",5); frequency_field.addActionListener(this); JLabel amplitude_label = new JLabel("Amplitude: "); JLabel frequency_label = new JLabel(" Frequency: "); ImagePanel image_panel = new ImagePanel(); image_panel.setSize(SIZE,SIZE+SIZE/2); image_panel.setBackground(Color.white); JPanel control_panel = new JPanel(); control_panel.add(amplitude_label); control_panel.add(amplitude_field); control_panel.add(frequency_label); control_panel.add(frequency_field); control_panel.setBackground(Color.white); Container contentPane = getContentPane(); contentPane.setLayout(new BorderLayout()); contentPane.add(image_panel,BorderLayout.CENTER); contentPane.add(control_panel,BorderLayout.SOUTH); for (i = 0; i < NPTS ; ++i) { x[i] = SIZE*i/((float) NPTS); y[i] = (float) (1.25*SIZE+0.2*SIZE*theta0/25); } } public void start() { if (thread == null) { Thread thread = new Thread(this); thread.start(); } } public void stop() { if (thread != null) { thread = null; } } public void run() { double l,g,A,dt; double k1_0,k2_0,k3_0,k4_0,k1_1,k2_1,k3_1,k4_1; int i; dt = 0.01; g = 1; l = 1; while (true) { repaint(); for (i = 0; i < (NPTS-1) ; ++i) { y[i] = y[i+1]; } y[NPTS-1] = (float) (1.25*SIZE+0.2*SIZE*theta0/25); t = t + dt; k1_0 = dt * theta1; k1_1 = dt * (-(g-amplitude*omega*omega*Math.sin(omega*t)) * Math.sin(theta0)/l); k2_0 = dt * (theta1+k1_1/2); k2_1 = dt * (-(g-amplitude*omega*omega*Math.sin(omega*(t+dt/2))) * Math.sin(theta0+k1_0/2)/l); k3_0 = dt * (theta1+k2_1/2); k3_1 = dt * (-(g-amplitude*omega*omega*Math.sin(omega*(t+dt/2))) * Math.sin(theta0+k2_0/2)/l); k4_0 = dt * (theta1+k3_1); k4_1 = dt * (-(g-amplitude*omega*omega*Math.sin(omega*(t+dt))) * Math.sin(theta0+k3_0)/l); theta0 = theta0 + k1_0/6 + k2_0/3 + k3_0/3 + k4_0/6; theta1 = theta1 + k1_1/6 + k2_1/3 + k3_1/3 + k4_1/6; z = amplitude*Math.sin(omega*t); try {Thread.sleep(10);} catch (InterruptedException e) { } } } class ImagePanel extends JPanel { public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; double x0,y0,x1,y1; int i; x0 = SIZE/2; y0 = SIZE/2-z*SIZE/10; x1 = x0 + (SIZE/3)*Math.sin(theta0); y1 = y0 + (SIZE/3)*Math.cos(theta0); super.paintComponent(g2); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setStroke(new BasicStroke(3)); g2.draw(new Line2D.Double(x0,y0,x1,y1)); g2.fill(new Ellipse2D.Double(x1-15,y1-15,30,30)); GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD,NPTS); path.moveTo(x[0],y[0]); for (i = 1; i < (NPTS-1); ++i) { path.lineTo(x[i],y[i]); } g2.draw(path); } } public void actionPerformed(ActionEvent event) { String amplitude_text = amplitude_field.getText(); amplitude = Double.valueOf(amplitude_text).doubleValue(); String frequency_text = frequency_field.getText(); omega = Double.valueOf(frequency_text).doubleValue(); } }