Drawing a sine wave using Swing: The number of cycles is adjustable. Code Source: Thinking In Java 4th Edition.
Code :
Code :
import javax.swing.*; import javax.swing.event.*; import java.awt.*; class SineDraw extends JPanel { //Scalefactor manipulates the number of points on the screen //Joining these points forms our wave. It will represent the clarity //of the display but low values may distort the wave private static final int SCALEFACTOR = 200; //The number of complete waves to display on the screen private int cycles; //Total number of points that will be joined to form the wave private int points; //The actual sine values calculated. Drawing will be done relative to //the height (actual vertical coordinates calculated from sine values). These aren't used as some coordinates. private double[] sines; //The actual coordinates (vertical) calculated based on the sine values private int[] pts; public SineDraw() { //Constructor Sets the number of cycles to display on the screen setCycles(1); } public void paintComponent(Graphics g) { super.paintComponent(g); //The current width of the Panel int maxWidth = getWidth(); //hstep mean the horizontal distance between two points on the screen double hstep = (double) maxWidth / (double) points; //The maximum height int maxHeight = getHeight(); pts = new int[points]; for (int i = 0; i < points; ++i) { /* This is for calculating the vertical coordinates of the points to be joined to form the wave. Horizontal coordinates are calculated based on hstep ( horizontal distance between consecutive points ) eg. if sine[i] is 1, maxHeight = 500 pts[i] = 1 * 250 * 0.95 (which means 95%) + maxHeight / 2 = 237.5 + 250 = 487.5 This is the bottom of the wave [*0.95 sets a 95% margin on display]
Now if sine[i] is -1, maxHeight = 500 pts[i] = -1 * 250 * 0.95 (which means 95%) + maxHeight / 2 = -237.5 + 250 = 12.5 This is the top of the display. Note that +maxHeight/2 is necessary ( * maxHeight / 2 ) calculates vertical coordinate values relative to sine values as sines are positive, the graph will rise, and if sine is negative, the graph will fall */ pts[i] = (int) (sines[i] * maxHeight / 2 * 0.95 + maxHeight / 2); } g.setColor(Color.RED); for (int i = 1; i < points; ++i) { /* Lets say first point gets x1 = 0 * hstep = 0 x2 = 0 * hstep = 0 as expected. Second one x1 = 1 * hstep = Lets say the points have a horizontal distance of 0.1 x2 = 2 * hstep = Add the same horizontal distance to the second point two times as the values are caculated from the left most edge of the panel and so on... */ int x1 = (int) ((i - 1) * hstep); int x2 = (int) (i * hstep); //The vertical values have already been calculated int y1 = pts[i - 1]; int y2 = pts[i]; //Now draw a line based on these calculated coordinates based on sine values g.drawLine(x1, y1, x2, y2); } } public void setCycles(int newCycles) { cycles = newCycles; /*Total number of points = SCALEFACTOR ( here this is manipulating the sharpness of display by changing the total number of points ) * cycles ( Lets say 1 cycle ) so that by multiplying it with SCALEFACTOR is becomes 200 cycles in this case. We need both negative values and positive values to draw. So the number of points is multiplied by 2. [One cycle is represented by an upper + lower curve on the graph]. If you remove the (*2) and set the slider to 1, notice that the upper curve isn't drawn. Before the first half that is before the effect of *2, sines have +ve values After the first half, negative sin values begin. */ points = SCALEFACTOR * cycles * 2; sines = new double[points]; for (int i = 0; i < points; ++i) { if(i == points/2){ System.out.println("***** Rest half *****"); } /* FYI, 1 radian is the angle subtended by an arc of the circle that has the same length as the radius of the circle. And PI is the angle subtended by half the circle on the center = 180 Degrees. Hers's a nice GIF explanation : http://en.wikipedia.org/wiki/Radian Multiply Math.PI by i (to get reltively increasing radian values and divide by SCALEFACTOR for getting values relative to the number of points. Angle is getting increased by 180deg (Math.PI) every time and then divided by SCALEFACTOR to get small increasing sine values based on these slowly increasing radian values */ double radians = (Math.PI / SCALEFACTOR) * i; //Notice that last iteration (in case scalefactor = 200, cycles = 2, points = 800 //radians = PI * 800 / 200 = PI * 4 = 180 degrees 4 times which gets you 2 complete cycles. //Now calculate the actual sin values based on radians sines[i] = Math.sin(radians); System.out.println("Radian = " + radians + " sines = " + sines[i]); } repaint(); } } public class SineWave extends JFrame { private SineDraw sines = new SineDraw(); private JSlider adjustCycles = new JSlider(1, 30, 1); public SineWave() { add(sines); adjustCycles.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { //Slider sets the number of cycles sines.setCycles( ((JSlider) e.getSource()).getValue()); } }); add(BorderLayout.SOUTH, adjustCycles); setSize(700, 400); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } public static void main(String[] args) { //Nimbus look and feel. Looks nice to me. try { for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (Exception e) { // If Nimbus is not available, you can set the GUI to another look and feel. } new SineWave(); } }
No comments:
Post a Comment