// "Java Tech"
// Code provided with book for educational purposes only.
// No warranty or guarantee implied.
// This code freely available. No copyright claimed.
// 2003
//
// Begun from StartJApple11
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
*
* It generates points along a line and then fits a
* straight line to them. This simulates track fitting
* in a detector.
*
* The number of tracks and the SD of
* the smearing of the track measurement errors taken from
* entris in two text fields. Two histograms record differences
* in the slope and intercept for the fitted track with the
* generated track. A third histogram holds the residuals.
*
* This program will run as an applet inside
* an application frame.
*
* The "Go" button starts the track generation and fitting in a
* thread. "Clear" button clears the histograms.
* In standalone mode, the Exit button closes the program.
*
**/
public class LsfLineApplet extends JApplet
implements ActionListener, Runnable
{
// Use the HistPanel JPanel subclass here
HistPanel fSlopePanel;
HistPanel fInterceptPanel;
HistPanel fResidualsPanel;
// Use a DrawPanel to display the points to fit
DrawPanel fDrawPanel = null;
// Thee histograms to record differences between
// generated tracks and fitted tracks.
Histogram fSlopeHist;
Histogram fInterceptHist;
Histogram fResidualsHist;
// Use DrawFunction subclasses to plot on the DrawPanel
DrawFunction [] fDrawFunctions;
// Set values for the tracks including the default number
// of tracks to generate, the track area, the SD smearing
// of the data points, and the x values where the track
// y coordinates are measured.
int fNumTracks = 1;
double fYTrkMin = 0.0;
double fYTrkMax = 10.0;
double fXTrkMin = 0.0;
double fXTrkMax = 100.0;
double fTrkSmear = 0.5;
double [] fXTrk = {10.0,30.0,50.0,70.0,90.0};
double [] fYTrk = new double[5];
// Data array used to pass track points to DrawPoints
double [][] fData = new double[4][];
// Random number generator
java.util.Random fRan;
// Inputs for the number of tracks to generate
JTextField fNumTrksField;
// and the smearing of the tracking points.
JTextField fSmearField;
// Flag for whether the applet is in a browser
// or running via the main () below.
boolean fInBrowser = true;
//Buttons
JButton fGoButton;
JButton fClearButton;
JButton fExitButton;
// Use thread reference as flag.
Thread fThread;
/**
* Create a User Interface with histograms and buttons to
* control the program. Two text files hold number of tracks
* to be generated and the measurement smearing.
**/
public void init () {
// Will need random number generator for generating tracks
// and for smearing the measurement points
fRan = new java.util.Random ();
// Create instances of DrawFunction for use in DrawPanel
// to plot the tracks and the measured points along them.
fDrawFunctions = new DrawFunction[2];
fDrawFunctions[0] = new DrawLine ();
fDrawFunctions[1] = new DrawPoints ();
// Start building the GUI.
JPanel panel = new JPanel (new GridLayout (2,1));
// Will plot the tracks on an instance of DrawPanel.
fDrawPanel =
new DrawPanel (fYTrkMin,fYTrkMax, fXTrkMin, fXTrkMax,
fDrawFunctions);
fDrawPanel.setTitle ("Fit Tracks");
fDrawPanel.setXLabel ("Ymeas vs X");
panel.add (fDrawPanel);
// Create histograms to show the quality of the fits.
fSlopeHist = new Histogram ("Fit-Gen","Slope", 20, -0.1,0.1);
fInterceptHist = new Histogram ("Fit-Gen","Intercept", 20, -5.,5.);
fResidualsHist = new Histogram ("Ydata - Yfit","Residuals", 20, -3,3.);
// Use another panel to hold the histogram and controls panels.
JPanel hist_crls_panel = new JPanel (new BorderLayout ());
JPanel histsPanel = new JPanel (new GridLayout (1,3));
histsPanel.add (fSlopePanel=new HistPanel (fSlopeHist));
histsPanel.add (fInterceptPanel=new HistPanel (fInterceptHist));
histsPanel.add (fResidualsPanel=new HistPanel (fResidualsHist));
// Add the panel of histograms to the main panel
hist_crls_panel.add (histsPanel);
// Use a textfield for an input parameter.
fNumTrksField =
new JTextField (Integer.toString (fNumTracks), 10);
// Use a textfield for an input parameter.
fSmearField =
new JTextField (Double.toString (fTrkSmear), 10);
// If return hit after entering text, the
// actionPerformed will be invoked.
fNumTrksField.addActionListener (this);
fSmearField.addActionListener (this);
fGoButton = new JButton ("Go");
fGoButton.addActionListener (this);
fClearButton = new JButton ("Clear");
fClearButton.addActionListener (this);
fExitButton = new JButton ("Exit");
fExitButton.addActionListener (this);
JPanel control_panel = new JPanel (new GridLayout (1,5));
control_panel.add (fNumTrksField);
control_panel.add (fSmearField);
control_panel.add (fGoButton);
control_panel.add (fClearButton);
control_panel.add (fExitButton);
if (fInBrowser) fExitButton.setEnabled (false);
hist_crls_panel.add (control_panel,"South");
panel.add (hist_crls_panel);
// Add text area with scrolling to the applet.
add (panel);
} // init
public void actionPerformed (ActionEvent e) {
Object source = e.getSource ();
if ( source == fGoButton || source == fNumTrksField
|| source == fSmearField )
{
String strNumDataPoints = fNumTrksField.getText ();
String strTrkSmear = fSmearField.getText ();
try {
fNumTracks = Integer.parseInt (strNumDataPoints);
fTrkSmear = Double.parseDouble (strTrkSmear);
}
catch (NumberFormatException ex) {
// Could open an error dialog here but just
// display a message on the browser status line.
showStatus ("Bad input value");
return;
}
fGoButton.setEnabled (false);
fClearButton.setEnabled (false);
if (fThread != null) stop ();
fThread = new Thread (this);
fThread.start ();
}
else if (source == fClearButton) {
fSlopeHist.clear ();
fInterceptHist.clear ();
fResidualsHist.clear ();
repaint ();
}
else if (!fInBrowser)
System.exit (0);
} // actionPerformed
/** Stop thread by setting reference to null. This stops
* loop in run()
**/
public void stop (){
// If thread is still running, setting this
// flag will kill it.
fThread = null;
} // stop
/** Generate the tracks in a thread. */
public void run (){
for (int i=0; i < fNumTracks; i++){
// Stop the thread if flag set
if (fThread == null) return;
// Generate a random track.
double [] genParams = genRanTrack (fXTrkMax-fXTrkMin,
fYTrkMax-fYTrkMin,
fXTrk, fYTrk, fTrkSmear);
// Fit points to a straight line. Use constant error.
double [] fitParams = new double[4];
FitLine.fit (fitParams, fXTrk, fYTrk, null, null, fXTrk.length);
// Pass the parameters to the straight line fit.
fDrawFunctions[0].setParameters (fitParams,null);
// Pass the data points to the DrawPoints object via
// the 2-D array.
fDrawFunctions[1].setParameters (null, fData);
// Redrawing the panel will cause the paintContents (Graphics g)
// method in DrawPanel to invoke the draw () method for the line
// and points drawing functions.
fDrawPanel.repaint ();
// Add fit measurement values to the respective histograms.
fInterceptHist.add (fitParams[0]-genParams[0]);
fSlopeHist.add (fitParams[1]-genParams[1]);
// Include residuals == difference between the measured value
// and the fitted value at the points at each x position
for (int j=0; j < fXTrk.length; j++){
double y = fitParams[0] + fitParams[1]*fXTrk[j];
fResidualsHist.add (fYTrk[j] - y);
}
// Pause briefly to let users see the track.
try
{
Thread.sleep (30);
}
catch (InterruptedException e){}
}
repaint ();
fGoButton.setEnabled (true);
fClearButton.setEnabled (true);
} // run
/**
* Generate a track and obtain points along the track.
* Smear the vertical coordinate with a Gaussian.
**/
double [] genRanTrack (double xRange, double yRange,
double [] xTrack,double [] yTrack,
double smear) {
// Line intercept and slope values in array.
double [] lineParam = new double[2];
// Simulated tracks for creating the desired distibution.
double y0 = yRange * fRan.nextDouble ();
double y1 = yRange * fRan.nextDouble ();
lineParam[1] = (y1-y0)/xRange;
for (int i=0; i < xTrack.length; i++){
yTrack[i] = y0 + lineParam[1]*xTrack[i];
yTrack[i] += smear*fRan.nextGaussian ();
}
// Set up the parameters in the drawing function.
lineParam[0] = y0; //intercept
fDrawFunctions[0].setParameters (lineParam,null);
// The LineFit function will need this data via
// a 2-D array.
fData[0] = yTrack;
fData[1] = xTrack;
fData[2] = null;
fData[3] = null;
// Return the track parameters.
return lineParam;
} // genRanTrack
/**
* Allow for option of running the program in standalone mode.
* Create the applet and add to a frame.
**/
public static void main (String[] args) {
//
int frame_width=450;
int frame_height=450;
//
LsfLineApplet applet = new LsfLineApplet ();
applet.fInBrowser = false;
applet.init ();
// Following anonymous class used to close window & exit program
JFrame f = new JFrame ("Demo");
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
// Add applet to the frame
f.getContentPane ().add ( applet);
f.setSize (new Dimension (frame_width,frame_height));
f.setVisible (true);
} // main
} // LsfLineApplet