// Sound1.java // /************************************************************************* * * * Copyright (c) 1998, 2004 Greg W. Anderson * * * * This program is free software. You can copy, modify, or redistribute * * this software under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version, provided that both * * the above copyright notice appears in all copies and that this * * permission notice appear in any supporting documentation. * * * * This software is provided "as is" in the hope that it will be useful, * * but WITHOUT any expressed or implied warranty of merchantability or * * fitness for any particular purpose. Your mileage may vary. * * See the GNU General Public License for more details. * * * *************************************************************************/ /* Modification History * Date Initials Change * 2/01/98 GWA Initial release * 10/09/04 GWA Partially updated to J2SDK 1.4.2 * 11/08/04 GWA wave fronts fade with age * Abstract: * * This applet demonstrates the Doppler effect and Shock waves for * sound waves propagating from a moving source. * This code is built over various classes from SUN's JDK. * This version of the applet was build over j2sre-1.4.2 * but it still containes deprecated code. The methods Thread.suspend() * still need replacing and Thred.resume() * * @author Greg Anderson * @version 0.3, October 2004 */ import java.awt.Graphics; import java.awt.*; import java.applet.*; public class Sound1 extends java.applet.Applet implements Runnable{ Sound1Controls controls; Sound1Canvas c; Sound1Banner banner; Label vplName = new Label ("The Virtual Physics Laboratory"); Label department = new Label ("Physics & Astronomy"); Label university = new Label ("Northeastern Illinois University"); Label appletName = new Label ("Sound Wave Propagation"); public void init(){ setLayout(new BorderLayout()); c = new Sound1Canvas(); banner = new Sound1Banner (2,2); banner.add("Center",department); banner.add(vplName); banner.add("Center",university); banner.add("South", appletName); add ("North",banner); add("Center",c); add("South", controls = new Sound1Controls(c)); c.annimationThread = null; c.stopAnnimation = false; } public void run(){ while (c.annimationThread != null){ try {Thread.sleep(300);} catch (InterruptedException e){} c.repaint(); } c.annimationThread = null; } public void start(){ controls.setEnabled(true); if (c.annimationThread == null){ c.annimationThread = new Thread(this); c.annimationThread.start(); } } public void stop(){ controls.setEnabled(false); c.offg = null; c.offImage = null; } public boolean handleEvent(Event e){ if (e.id == Event.WINDOW_DESTROY){ System.exit(0); } return false; } } class Sound1Canvas extends Canvas { Dimension offDimension; // These objects are used for Image offImage; // Double Buffering to Graphics offg; // "offline graphics" Thread annimationThread; boolean stopAnnimation; int t = 0; /* elapsed time */ double T = 4; /* period */ double u = 3; /* Source Speed, */ double v = 2; /* speed of sound */ double k = 0.5; /* k = w/v */ double w = 2*Math.PI/T; /* angular frequency */ double R; /* pulse radius */ double dist; /* distance traveled by source */ int x0 = 40; int y0 = 200; int x; int dx; int y; int dy; // The displacement plotted is actually measured from // the top of the screen downward, hence the -A1 etc // below. public void paint(Graphics g) { update(g); } public void update(Graphics g) { Dimension d = getSize(); //onscreen drawing area: if ( (offg == null) || (d.width != offDimension.width) || (d.height != offDimension.height) ) { offDimension = d; offImage = createImage(d.width, d.height); offg = offImage.getGraphics(); } //Erase the previous image. offg.setColor(getBackground()); offg.fillRect(0, 0, d.width, d.height); setBackground(Color.white); Color darkmagenta = new Color(150,0,150); y0 = d.height/2; /** The outer envelope of the pulse */ R = v*t; /* pulse radius */ dist = u*t; /* distance traveled by source */ /** The Source of the pulse */ offg.setColor(Color.red); int Amp; Amp = (int) Math.abs(3*Math.sin(w*t/2)); Amp +=1; x = x0 + (int) dist; offg.fillOval(x-Amp,y0-Amp,2*Amp,2*Amp); offg.setColor(Color.blue); Color fadingblue = new Color(0,0,255); for (int n = 0; n*T< t; n++){ double Tn = n*T; /* time pulse was made */ R = v*(t-Tn); dist = u*Tn; /* distance traveled before pulse */ x = (int)(x0 + dist - R); dx = (int)(2*R); y = y0 - (int) R; dy = (int) (2*R); if ( (int) R <= 255){ fadingblue = new Color((int)R,(int)R,255); // fading blue } else { fadingblue = new Color(255,255,255); // fading blue } offg.setColor(fadingblue); offg.drawOval(x,y,dx,dy); } g.drawImage(offImage, 0, 0, this); t++; if (dist > d.width) t = 0; } public static int abs(int a){ return (a < 0) ? -a : a; } public static double fabs(double a){ return (a < 0) ? -a : a; } public void redraw(Double V, Double U, Double Tp){ v = V.doubleValue(); u = U.doubleValue(); T = Tp.intValue(); t = 0; repaint(); } public boolean mouseDown(java.awt.Event evt, int x, int y) { if (stopAnnimation) { annimationThread.resume(); } else { annimationThread.suspend(); } stopAnnimation = !stopAnnimation; return true; } } class Sound1Controls extends Panel{ Button btemp; TextField v; TextField u; TextField t; Sound1Canvas canvas; Double dtemp; public Sound1Controls(Sound1Canvas canvas){ setLayout(new GridLayout(2,6,5,5)); /* nr,nc, vg, hg */ this.canvas = canvas; Color darkmagenta = new Color(150,0,150); this.setForeground(Color.black); add (new Label("Sound Speed:",Label.LEFT)); btemp = new Button("V = "); btemp.setForeground(darkmagenta); add (btemp); dtemp = new Double(canvas.v); add (v = new TextField(dtemp.toString(),4)); add (new Label("Source Speed:",Label.LEFT)); btemp = new Button("U = "); btemp.setForeground(darkmagenta); add (btemp); dtemp = new Double(canvas.u); add (u = new TextField(dtemp.toString(),4)); add (new Label("Period:",Label.LEFT)); btemp = new Button("T = "); btemp.setForeground(darkmagenta); add (btemp); dtemp = new Double(canvas.T); add (t = new TextField(dtemp.toString(),4)); add (new Label("",Label.LEFT)); add (new Label("",Label.LEFT)); add (new Label("",Label.LEFT)); } public boolean action(Event ev, Object arg){ if(ev.target instanceof Button // Redispla on Button click || ev.id == ev.END ){ // Redisplay if Return String label = (String)arg; canvas.redraw(Double.valueOf( v.getText().trim() ), Double.valueOf( u.getText().trim() ), Double.valueOf( t.getText().trim() ) ); return true; } return false; } } class Sound1Banner extends Panel{ public Sound1Banner(int n, int m){ Color darkBlue = new Color(0,0,150); setBackground(darkBlue); setForeground(Color.white); setLayout(new GridLayout(n,m,40,-5)); /* nr,nc, vg, hg */ } }