// "Java Tech"
// Code provided with book for educational purposes only.
// No warranty or guarantee implied.
// This code freely available. No copyright claimed.
// 2003
//
//package SimClientServer;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* This program simulates an experiment in which measurements
* are made during the fall of a mass in a constant gravitational
* field that will be used to determine the acceleration constant.
* It illustrates the basic components involved with a simulation
* of any physics experiment.
*
* The applet uses DropPanelDetect to simulate the dropping of a
* mass in a constant gravitational field. The
* DropDetector class draws the detector.
*
*
* Data for each drop is passed to an instance of DropAnalyzer,
* which saves the data. At the end of the run (a set of drops),
* the analyzer plots Yaverage vs. Time and fits the points to
* a polynominal c + bT + cT^2. From the c coefficient the gravitational
* value can be determined.
*
* The java.util.Timer and java.util.TimerTask are used
* to update the animation of the drop.
*
*
**/
public class SimApplet extends JApplet
{
// Another class can control this applet simulation if it
// implements the SimController interface.
SimController fSimController;
// 2-D array used to pass data to the controller.
double fData[][] = new double [2][];
// The DropPanel displays the animation of the
// falling mass.
DropPanelDetect fDropPanel;
// The DropModel generates the physics data.
DropModelDetect fDropModel;
// Use a detector to measure the drop times.
Detector fDetector;
// Use the HistPanel JPanel subclass here
HistPanel fHistPanel;
Histogram fHistogram;
int fNumDataPoints = 100;
boolean fMakingHist = false;
boolean fUpdateDisplay = false;
// Use the java.util Timer and TimerTask combo
// for timing events.
java.util.Timer fTimer;
// A text field for getting number of drops per
// run and the position smearing std.dev. in cm.
JTextField fMaxNumDropsField ;
JTextField fPosSigmaFactorField;
// Flag for whether the applet is in a browser
// or running via the main () below.
boolean fInBrowser = true;
//Buttons
JButton fGoButton; // start drop
JButton fClearButton;// resets histogram
JButton fExitButton;
// Starting coordinates of drop
double fXBallStart = 25.0; // cm
double fYBallStart = 200.0; // cm
double fYBallEnd = 0.0; // cm
// Range of the drop time.
double fTStart = 0.00; // sec
double fTEnd = 0.75; // sec
// SD in the measured values for the marker positions and t (sec).
// (Allow for smearing of marker position for further experimentation.)
double [] fMeasurementSigmas = {2.0, 0.0};
// Integer and double arrays to pass info to the detector
int [] fDetectorSetup;
double [] fDetectorParameters;
// Coordinate of ball.
double fXBall;
double fYBall;
// Initial velocity.
double fVfYBallStart = 0.0;
double fVfXBallStart = 0.0;
// Time in millisecs for the drop
double fTDropTotal;
double fTFrame = 0.020; // in secs
// Speed up or slow down factor for animation:
double fTFactor = 1.0;
// Allow for multiple drops per "run"
int fMaxNumDrops = 10;
int fNumDrops = 0;
// Number of times to measure the position during the drop.
int fMaxNumMeasurements = 40;
/**
* Initialize the display. Create Detector and Model
* objects to use for the physics and experiment simulation.
* DropPanelDetect displays the dropping ball and the
* detector. Add a HistPanel to display the data.
**/
public void init () {
// Create a detector
fDetector = new DropDetector2 ();
// Need arrays to pass setup info to the detector.
fDetectorSetup = new int[1];
fDetectorSetup[0] = fMaxNumMeasurements;
// Do a measurement for every frame
fDetectorParameters = new double[1];
fDetectorParameters[0] = fTFrame;
// Pass the detector the necesary setup info
fDetector.init (fDetectorSetup, fDetectorParameters, fMeasurementSigmas);
// Create the drop physics model
fDropModel = new DropModelDetect (fDetector);
fDropModel.reset (fYBallStart, fVfYBallStart);
// Create a User Interface with a textarea with sroll bars
// and a Go button to initiate processing and a Clear button
// to clear the textarea.
JPanel panel = new JPanel (new BorderLayout ());
// Create an instance of the DropPanel
// Make the panel 10% taller than starting position.
fDropPanel = new DropPanelDetect (fYBallStart * 1.1, 0.0, fDetector);
panel.add (fDropPanel,"Center");
// Add text area with scrolling to the contentPane.
add (panel);
} // init
/** Stop the run. **/
public void stop () {
runDone ();
}
/** In the constructor pass the reference to the SimController
* to opperate this simulation.
**/
public void setController (SimController simController) {
fSimController = simController;
}
/**
* This method allows an external class, such as the SimServer,
* to control the drop simulation. Pass the parameters needed for
* the simulation via the array arguments.
**/
public void externalControl (int control, int [] valInt,
double [] valFP) {
switch (control) {
case SimUtil.START:
// Get the number of drops & max measures per drop.
fMaxNumDrops = valInt[0];
fDetectorSetup[0] = valInt[1]; //= fMaxNumMeasurements
// and the smearing on the position measurements
fMeasurementSigmas[0] = valFP[0]; // = std. dev. on y
// and the fTFrame
fDetectorParameters[0] = valFP[1];// = fTFrame
// Update the position smearing
fDetector.init (fDetectorSetup, fDetectorParameters,
fMeasurementSigmas);
// Reset everything and start the run again.
dropReset ();
break;
case SimUtil.GET_SETUP:
// Use the FP data buffer to send the init data to the
// simulation controller.
valFP[0] = fYBallEnd;
valFP[1] = fYBallStart;
valFP[2] = fTStart;
valFP[3] = fTEnd;
break;
case SimUtil.STOP:
runDone ();
break;
}
} // externalControl
/**
* Use the inner class technique to define the
* TimerTask subclass for stepping through the
* drop calculation and the frame refresh.
* Use the real time in the drop calculation instead
* of the given frame rate times in case there were
* delays from thread interruptions, the processing
* in the parts of the program take extra time, etc.
**/
class PaintHistTask extends java.util.TimerTask {
public void run () {
// Drop the ball
fYBall = fDropModel.step (fTFactor * fTFrame);
// Update the position of the ball in the
// animation and redraw the frame.
fDropPanel.updatePosition (fXBall, fYBall);
// Check if ball has crossed the finish line.
if (fYBall <= fYBallEnd) dropDone ();
} // run
} // class PaintHistTask
/**
* Before each set of drops, need to create a new timer,
* and set up its schedule. The PaintHistTask innner class
* object will do the setup for each frame of a drop animation.
**/
void dropReset () {
// Before starting the drop, create the timer task
// that will cause the histogram display to update
// during the filling.
// Create a timer. TimerTask created in MakeHist ()
fTimer = new java.util.Timer ();
fDropModel.reset (fYBallStart, fVfYBallStart);
fDropPanel.reset (fXBallStart, fYBallStart);
// Reset time sum
fTDropTotal = 0.0;
fNumDrops = 0;
fYBall = fYBallStart;
fXBall = fXBallStart;
// Reset the detector.
fDetector.reset ();
repaint ();
// Start the timer after 20ms and then repeat calls
// to run in PaintHistTask object by the rate set by
// the fTFrame value.
fTimer.schedule (new PaintHistTask (), 20, (int) (fTFrame*1000));
} // dropReset
/**
* Invoked after a drop ends bottom. Reset
* all the parameters to set up for another drop.
**/
public void dropDone () {
// Get the data (times and positions during the drop)
// from the detector and analyze it
fData = fDetector.getResults ();
int num_measures = fDetector.getNumMeasurements ();
// Send the event data to the controller
// Two arrays (times and positions) must be sent.
fSimController.message (SimUtil.EVENT_DATA, num_measures, fData);
++fNumDrops;
// Check if all drops completed.
if (fNumDrops == fMaxNumDrops){
// If so then finish up the data recording
// for this run and return.
runDone ();
return;
}
// Reset time sum
fTDropTotal = 0.0;
fYBall = fYBallStart;
fXBall = fXBallStart;
fDropPanel.reset (fXBallStart, fYBallStart);
fDropModel.reset (fYBallStart, fVfYBallStart);
fDetector.reset ();
} // dropDone
/**
* Invoked when all the drops in a run (set of drops) are done.
* Kills the timer to stop the animation. (A new timer will be
* created in the dropReset () for the next run.)
* Tell the DropAnalyser instance to do its job on the run data.
**/
public void runDone () {
// Stop the animation.
fTimer.cancel ();
// Tell controller that run is done.
fSimController.message (SimUtil.RUN_DONE, -1, null);
} // runDone
} // class SimApplet