Changeset 2314


Ignore:
Timestamp:
02/22/07 10:46:28 (13 years ago)
Author:
curtis
Message:

Use picoseconds for tau unit instead of histogram bin range.
Better error reporting during Slim Plotter startup.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/loci/apps/slim/SlimPlotter.java

    r2261 r2314  
    150150    // * Creating plots - 4% 
    151151    ProgressMonitor progress = new ProgressMonitor(null, 
    152       "Launching SlimPlotter", "Initializing", 0, 1000); 
     152      "Launching Slim Plotter", "Initializing", 0, 1000); 
    153153    progress.setMillisToPopup(0); 
    154154    progress.setMillisToDecideToPopup(0); 
    155155 
    156     // check for required libraries 
     156    int maxChan = -1; 
    157157    try { 
    158       Class.forName("javax.vecmath.Point3d"); 
    159     } 
    160     catch (Throwable t) { 
    161       String os = System.getProperty("os.name").toLowerCase(); 
    162       String url = null; 
    163       if (os.indexOf("windows") >= 0 || 
    164         os.indexOf("linux") >= 0 || os.indexOf("solaris") >= 0) 
    165       { 
    166         url = "https://java3d.dev.java.net/binary-builds.html"; 
    167       } 
    168       else if (os.indexOf("mac os x") >= 0) { 
    169         url = "http://www.apple.com/downloads/macosx/apple/" + 
    170           "java3dandjavaadvancedimagingupdate.html"; 
    171       } 
    172       else if (os.indexOf("aix") >= 0) { 
    173         url = "http://www-128.ibm.com/developerworks/java/jdk/aix/index.html"; 
    174       } 
    175       else if (os.indexOf("hp-ux") >= 0) { 
    176         url = "http://www.hp.com/products1/unix/java/java2/java3d/downloads/" + 
    177           "index.html"; 
    178       } 
    179       else if (os.indexOf("irix") >= 0) { 
    180         url = "http://www.sgi.com/products/evaluation/6.5_java3d_1.3.1/"; 
    181       } 
    182       JOptionPane.showMessageDialog(null, 
    183         "SlimPlotter requires Java3D, but it was not found." + 
    184         (url == null ? "" : ("\nPlease install it from:\n" + url)), 
    185         "SlimPlotter", JOptionPane.ERROR_MESSAGE); 
    186       System.exit(3); 
    187     } 
    188  
    189     // parse command line arguments 
    190     String filename = null; 
    191     File file = null; 
    192     if (args == null || args.length < 1) { 
    193       JFileChooser jc = new JFileChooser(System.getProperty("user.dir")); 
    194       jc.addChoosableFileFilter(new ExtensionFileFilter("sdt", 
    195         "Becker & Hickl SPC-Image SDT")); 
    196       int rval = jc.showOpenDialog(null); 
    197       if (rval != JFileChooser.APPROVE_OPTION) { 
    198         System.out.println("Please specify an SDT file."); 
    199         System.exit(1); 
    200       } 
    201       file = jc.getSelectedFile(); 
    202       filename = file.getPath(); 
    203     } 
    204     else { 
    205       filename = args[0]; 
    206       file = new File(filename); 
    207     } 
    208  
    209     if (!file.exists()) { 
    210       System.out.println("File does not exist: " + filename); 
    211       System.exit(2); 
    212     } 
    213  
    214     // read SDT file header 
    215     SDTReader reader = new SDTReader(); 
    216     SDTInfo info = reader.getInfo(file.getPath()); 
    217     reader.close(); 
    218     int offset = info.dataBlockOffs + 22; 
    219     width = info.width; 
    220     height = info.height; 
    221     timeBins = info.timeBins; 
    222     channels = info.channels; 
    223     timeRange = 12.5f; 
    224     minWave = 400; 
    225     waveStep = 10; 
    226  
    227     // show dialog confirming data parameters 
    228     paramDialog = new JDialog((Frame) null, "SlimPlotter", true); 
    229     JPanel paramPane = new JPanel(); 
    230     paramPane.setBorder(new EmptyBorder(10, 10, 10, 10)); 
    231     paramDialog.setContentPane(paramPane); 
    232     paramPane.setLayout(new GridLayout(11, 3)); 
    233     wField = addRow(paramPane, "Image width", width, "pixels"); 
    234     hField = addRow(paramPane, "Image height", height, "pixels"); 
    235     tField = addRow(paramPane, "Time bins", timeBins, ""); 
    236     cField = addRow(paramPane, "Channel count", channels, ""); 
    237     trField = addRow(paramPane, "Time range", timeRange, "nanoseconds"); 
    238     wlField = addRow(paramPane, "Starting wavelength", minWave, "nanometers"); 
    239     sField = addRow(paramPane, "Channel width", waveStep, "nanometers"); 
    240     JButton ok = new JButton("OK"); 
    241     paramDialog.getRootPane().setDefaultButton(ok); 
    242     ok.addActionListener(this); 
    243     // row 8 
    244     peaksBox = new JCheckBox("Align peaks", true); 
    245     peaksBox.setToolTipText("<html>Computes the peak of each spectral " + 
    246       "channel, and aligns those peaks <br>to match by adjusting the " + 
    247       "lifetime histograms. This option corrects<br>for skew across channels " + 
    248       "caused by the multispectral detector's<br>variable system response " + 
    249       "time between channels. This option must<br>be enabled to perform " + 
    250       "exponential curve fitting.</html>"); 
    251     paramPane.add(peaksBox); 
    252     paramPane.add(new JLabel()); 
    253     paramPane.add(new JLabel()); 
    254     // row 8 
    255     cutBox = new JCheckBox("Cut 1.5ns from fit", true); 
    256     cutBox.setToolTipText("<html>When performing exponential curve fitting, " + 
    257       "excludes the last 1.5 ns<br>from the computation. This option is " + 
    258       "useful because the end of the <br>the lifetime histogram sometimes " + 
    259       "drops off unexpectedly, skewing<br>the fit results.</html>"); 
    260     paramPane.add(cutBox); 
    261     paramPane.add(new JLabel()); 
    262     paramPane.add(new JLabel()); 
    263     // row 10 
    264     paramPane.add(new JLabel()); 
    265     paramPane.add(new JLabel()); 
    266     paramPane.add(new JLabel()); 
    267     // row 11 
    268     paramPane.add(new JLabel()); 
    269     paramPane.add(ok); 
    270     paramDialog.pack(); 
    271     Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 
    272     Dimension ps = paramDialog.getSize(); 
    273     paramDialog.setLocation((screenSize.width - ps.width) / 2, 
    274       (screenSize.height - ps.height) / 2); 
    275     paramDialog.setVisible(true); 
    276     if (cVisible == null) System.exit(0); // dialog canceled (closed with X) 
    277     maxWave = minWave + (channels - 1) * waveStep; 
    278     roiCount = width * height; 
    279     roiPercent = 100; 
    280  
    281     // pop up progress monitor 
    282     setProgress(progress, 1); // estimate: 0.1% 
    283     if (progress.isCanceled()) System.exit(0); 
    284  
    285     // read pixel data 
    286     progress.setNote("Reading data"); 
    287     DataInputStream fin = new DataInputStream(new FileInputStream(file)); 
    288     fin.skipBytes(offset); // skip to data 
    289     byte[] data = new byte[2 * channels * height * width * timeBins]; 
    290     int blockSize = 65536; 
    291     for (int off=0; off<data.length; off+=blockSize) { 
    292       int len = data.length - off; 
    293       if (len > blockSize) len = blockSize; 
    294       fin.readFully(data, off, len); 
    295       setProgress(progress, (int) (700L * 
    296         (off + blockSize) / data.length)); // estimate: 0% -> 70% 
     158      // check for required libraries 
     159      try { 
     160        Class.forName("javax.vecmath.Point3d"); 
     161      } 
     162      catch (Throwable t) { 
     163        String os = System.getProperty("os.name").toLowerCase(); 
     164        String url = null; 
     165        if (os.indexOf("windows") >= 0 || 
     166          os.indexOf("linux") >= 0 || os.indexOf("solaris") >= 0) 
     167        { 
     168          url = "https://java3d.dev.java.net/binary-builds.html"; 
     169        } 
     170        else if (os.indexOf("mac os x") >= 0) { 
     171          url = "http://www.apple.com/downloads/macosx/apple/" + 
     172            "java3dandjavaadvancedimagingupdate.html"; 
     173        } 
     174        else if (os.indexOf("aix") >= 0) { 
     175          url = "http://www-128.ibm.com/developerworks/java/jdk/aix/index.html"; 
     176        } 
     177        else if (os.indexOf("hp-ux") >= 0) { 
     178          url = "http://www.hp.com/products1/unix/java/java2/java3d/" + 
     179            "downloads/index.html"; 
     180        } 
     181        else if (os.indexOf("irix") >= 0) { 
     182          url = "http://www.sgi.com/products/evaluation/6.5_java3d_1.3.1/"; 
     183        } 
     184        JOptionPane.showMessageDialog(null, 
     185          "Slim Plotter requires Java3D, but it was not found." + 
     186          (url == null ? "" : ("\nPlease install it from:\n" + url)), 
     187          "Slim Plotter", JOptionPane.ERROR_MESSAGE); 
     188        System.exit(3); 
     189      } 
     190 
     191      // parse command line arguments 
     192      String filename = null; 
     193      File file = null; 
     194      if (args == null || args.length < 1) { 
     195        JFileChooser jc = new JFileChooser(System.getProperty("user.dir")); 
     196        jc.addChoosableFileFilter(new ExtensionFileFilter("sdt", 
     197          "Becker & Hickl SPC-Image SDT")); 
     198        int rval = jc.showOpenDialog(null); 
     199        if (rval != JFileChooser.APPROVE_OPTION) { 
     200          System.out.println("Please specify an SDT file."); 
     201          System.exit(1); 
     202        } 
     203        file = jc.getSelectedFile(); 
     204        filename = file.getPath(); 
     205      } 
     206      else { 
     207        filename = args[0]; 
     208        file = new File(filename); 
     209      } 
     210 
     211      if (!file.exists()) { 
     212        System.out.println("File does not exist: " + filename); 
     213        System.exit(2); 
     214      } 
     215 
     216      // read SDT file header 
     217      SDTReader reader = new SDTReader(); 
     218      SDTInfo info = reader.getInfo(file.getPath()); 
     219      reader.close(); 
     220      int offset = info.dataBlockOffs + 22; 
     221      width = info.width; 
     222      height = info.height; 
     223      timeBins = info.timeBins; 
     224      channels = info.channels; 
     225      timeRange = 12.5f; 
     226      minWave = 400; 
     227      waveStep = 10; 
     228 
     229      // show dialog confirming data parameters 
     230      paramDialog = new JDialog((Frame) null, "Slim Plotter", true); 
     231      JPanel paramPane = new JPanel(); 
     232      paramPane.setBorder(new EmptyBorder(10, 10, 10, 10)); 
     233      paramDialog.setContentPane(paramPane); 
     234      paramPane.setLayout(new GridLayout(11, 3)); 
     235      wField = addRow(paramPane, "Image width", width, "pixels"); 
     236      hField = addRow(paramPane, "Image height", height, "pixels"); 
     237      tField = addRow(paramPane, "Time bins", timeBins, ""); 
     238      cField = addRow(paramPane, "Channel count", channels, ""); 
     239      trField = addRow(paramPane, "Time range", timeRange, "nanoseconds"); 
     240      wlField = addRow(paramPane, "Starting wavelength", minWave, "nanometers"); 
     241      sField = addRow(paramPane, "Channel width", waveStep, "nanometers"); 
     242      JButton ok = new JButton("OK"); 
     243      paramDialog.getRootPane().setDefaultButton(ok); 
     244      ok.addActionListener(this); 
     245      // row 8 
     246      peaksBox = new JCheckBox("Align peaks", true); 
     247      peaksBox.setToolTipText("<html>Computes the peak of each spectral " + 
     248        "channel, and aligns those peaks <br>to match by adjusting the " + 
     249        "lifetime histograms. This option corrects<br>for skew across " + 
     250        "channels caused by the multispectral detector's<br>variable system " + 
     251        "response time between channels. This option must<br>be enabled to " + 
     252        "perform exponential curve fitting.</html>"); 
     253      paramPane.add(peaksBox); 
     254      paramPane.add(new JLabel()); 
     255      paramPane.add(new JLabel()); 
     256      // row 8 
     257      cutBox = new JCheckBox("Cut 1.5ns from fit", true); 
     258      cutBox.setToolTipText("<html>When performing exponential curve " + 
     259        "fitting, excludes the last 1.5 ns<br>from the computation. This " + 
     260        "option is useful because the end of the <br>the lifetime histogram " + 
     261        "sometimes drops off unexpectedly, skewing<br>the fit results.</html>"); 
     262      paramPane.add(cutBox); 
     263      paramPane.add(new JLabel()); 
     264      paramPane.add(new JLabel()); 
     265      // row 10 
     266      paramPane.add(new JLabel()); 
     267      paramPane.add(new JLabel()); 
     268      paramPane.add(new JLabel()); 
     269      // row 11 
     270      paramPane.add(new JLabel()); 
     271      paramPane.add(ok); 
     272      paramDialog.pack(); 
     273      Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 
     274      Dimension ps = paramDialog.getSize(); 
     275      paramDialog.setLocation((screenSize.width - ps.width) / 2, 
     276        (screenSize.height - ps.height) / 2); 
     277      paramDialog.setVisible(true); 
     278      if (cVisible == null) System.exit(0); // dialog canceled (closed with X) 
     279      maxWave = minWave + (channels - 1) * waveStep; 
     280      roiCount = width * height; 
     281      roiPercent = 100; 
     282 
     283      // pop up progress monitor 
     284      setProgress(progress, 1); // estimate: 0.1% 
    297285      if (progress.isCanceled()) System.exit(0); 
    298     } 
    299     fin.close(); 
    300  
    301     // create types 
    302     progress.setNote("Creating types"); 
    303     RealType xType = RealType.getRealType("element"); 
    304     RealType yType = RealType.getRealType("line"); 
    305     ScaledUnit ns = new ScaledUnit(1e-9, SI.second, "ns"); 
    306     ScaledUnit nm = new ScaledUnit(1e-9, SI.meter, "nm"); 
    307     bcUnits = new Unit[] {ns, nm}; 
    308     bType = RealType.getRealType("bin", ns); 
    309     cType = RealType.getRealType("channel", nm); 
    310     RealType vType = RealType.getRealType("count"); 
    311     RealTupleType xy = new RealTupleType(xType, yType); 
    312     FunctionType xyvFunc = new FunctionType(xy, vType); 
    313     Integer2DSet xySet = new Integer2DSet(xy, width, height); 
    314     FunctionType cxyvFunc = new FunctionType(cType, xyvFunc); 
    315     Linear1DSet cSet = new Linear1DSet(cType, 
    316       minWave, maxWave, channels, null, new Unit[] {nm}, null); 
    317     bc = new RealTupleType(bType, cType); 
    318     RealType vType2 = RealType.getRealType("tau"); 
    319     RealTupleType vv = new RealTupleType(vType, vType2); 
    320     bcvFunc = new FunctionType(bc, vv); 
    321     RealType vTypeFit = RealType.getRealType("value_fit"); 
    322     bcvFuncFit = new FunctionType(bc, vTypeFit); 
    323     RealType vTypeRes = RealType.getRealType("value_res"); 
    324     bcvFuncRes = new FunctionType(bc, vTypeRes); 
    325     setProgress(progress, 710); // estimate: 71% 
    326     if (progress.isCanceled()) System.exit(0); 
    327  
    328     // plot intensity data in 2D display 
    329     progress.setNote("Building displays"); 
    330     iPlot = new DisplayImplJ3D("intensity", new TwoDDisplayRendererJ3D()); 
    331     iPlot.getMouseBehavior().getMouseHelper().setFunctionMap(new int[][][] { 
    332       {{MouseHelper.DIRECT, MouseHelper.NONE}, // L, shift-L 
    333        {MouseHelper.NONE, MouseHelper.NONE}}, // ctrl-L, ctrl-shift-L 
    334       {{MouseHelper.CURSOR_TRANSLATE, MouseHelper.CURSOR_ZOOM}, // M, shift-M 
    335        {MouseHelper.CURSOR_ROTATE, MouseHelper.NONE}}, // ctrl-M, ctrl-shift-M 
    336       {{MouseHelper.ROTATE, MouseHelper.ZOOM}, // R, shift-R 
    337        {MouseHelper.TRANSLATE, MouseHelper.NONE}}, // ctrl-R, ctrl-shift-R 
    338     }); 
    339     iPlot.enableEvent(DisplayEvent.MOUSE_DRAGGED); 
    340     iPlot.addDisplayListener(this); 
    341     setProgress(progress, 720); // estimate: 72% 
    342     if (progress.isCanceled()) System.exit(0); 
    343  
    344     iPlot.addMap(new ScalarMap(xType, Display.XAxis)); 
    345     iPlot.addMap(new ScalarMap(yType, Display.YAxis)); 
    346     intensityMap = new ScalarMap(vType, Display.RGB); 
    347     iPlot.addMap(intensityMap); 
    348     iPlot.addMap(new ScalarMap(cType, Display.Animation)); 
    349     DataReferenceImpl intensityRef = new DataReferenceImpl("intensity"); 
    350     iPlot.addReference(intensityRef); 
    351     setProgress(progress, 730); // estimate: 73% 
    352     if (progress.isCanceled()) System.exit(0); 
    353  
    354     // set up curve manipulation renderer in 2D display 
    355     roiGrid = new float[2][width * height]; 
    356     roiMask = new boolean[height][width]; 
    357     for (int h=0; h<height; h++) { 
    358       for (int w=0; w<width; w++) { 
    359         int ndx = h * width + w; 
    360         roiGrid[0][ndx] = w; 
    361         roiGrid[1][ndx] = h; 
    362         roiMask[h][w] = true; 
    363       } 
    364     } 
    365     final DataReferenceImpl curveRef = new DataReferenceImpl("curve"); 
    366     UnionSet dummyCurve = new UnionSet(xy, new Gridded2DSet[] { 
    367       new Gridded2DSet(xy, new float[][] {{0}, {0}}, 1) 
    368     }); 
    369     curveRef.setData(dummyCurve); 
    370     CurveManipulationRendererJ3D curve = 
    371       new CurveManipulationRendererJ3D(0, 0, true); 
    372     iPlot.addReferences(curve, curveRef); 
    373     CellImpl cell = new CellImpl() { 
    374       public void doAction() throws VisADException, RemoteException { 
    375         // save latest drawn curve 
    376         curveSet = (UnionSet) curveRef.getData(); 
    377       } 
    378     }; 
    379     cell.addReference(curveRef); 
    380     roiRef = new DataReferenceImpl("roi"); 
    381     roiRef.setData(new Real(0)); // dummy 
    382     iPlot.addReference(roiRef, new ConstantMap[] { 
    383       new ConstantMap(0, Display.Blue), 
    384       new ConstantMap(0.1, Display.Alpha) 
    385     }); 
    386     setProgress(progress, 740); // estimate: 74% 
    387     if (progress.isCanceled()) System.exit(0); 
    388  
    389     ac = (AnimationControl) iPlot.getControl(AnimationControl.class); 
    390     iPlot.getProjectionControl().setMatrix( 
    391       iPlot.make_matrix(0, 0, 0, 0.85, 0, 0, 0)); 
    392  
    393     setProgress(progress, 750); // estimate: 75% 
    394     if (progress.isCanceled()) System.exit(0); 
    395  
    396     // plot decay curves in 3D display 
    397     decayPlot = channels > 1 ? new DisplayImplJ3D("decay") : 
    398       new DisplayImplJ3D("decay", new TwoDDisplayRendererJ3D()); 
    399     ScalarMap xMap = new ScalarMap(bType, Display.XAxis); 
    400     ScalarMap yMap = new ScalarMap(cType, Display.YAxis); 
    401     DisplayRealType heightAxis = channels > 1 ? Display.ZAxis : Display.YAxis; 
    402     zMap = new ScalarMap(vType, heightAxis); 
    403     zMapFit = new ScalarMap(vTypeFit, heightAxis); 
    404     zMapRes = new ScalarMap(vTypeRes, heightAxis); 
    405     vMap = new ScalarMap(vType2, Display.RGB); 
    406     //vMapFit = new ScalarMap(vTypeFit, Display.RGB); 
    407     vMapRes = new ScalarMap(vTypeRes, Display.RGB); 
    408     decayPlot.addMap(xMap); 
    409     if (channels > 1) decayPlot.addMap(yMap); 
    410     decayPlot.addMap(zMap); 
    411     decayPlot.addMap(zMapFit); 
    412     decayPlot.addMap(zMapRes); 
    413     decayPlot.addMap(vMap); 
    414     //decayPlot.addMap(vMapFit); 
    415     decayPlot.addMap(vMapRes); 
    416     setProgress(progress, 760); // estimate: 76% 
    417     if (progress.isCanceled()) System.exit(0); 
    418  
    419     decayRend = new DefaultRendererJ3D(); 
    420     decayRef = new DataReferenceImpl("decay"); 
    421     decayPlot.addReferences(decayRend, decayRef); 
    422     if (adjustPeaks) { 
    423       fitRend = new DefaultRendererJ3D(); 
    424       fitRef = new DataReferenceImpl("fit"); 
    425       decayPlot.addReferences(fitRend, fitRef, new ConstantMap[] { 
    426         new ConstantMap(1.0, Display.Red), 
    427         new ConstantMap(1.0, Display.Green), 
    428         new ConstantMap(1.0, Display.Blue) 
     286 
     287      // read pixel data 
     288      progress.setNote("Reading data"); 
     289      DataInputStream fin = new DataInputStream(new FileInputStream(file)); 
     290      fin.skipBytes(offset); // skip to data 
     291      byte[] data = new byte[2 * channels * height * width * timeBins]; 
     292      int blockSize = 65536; 
     293      for (int off=0; off<data.length; off+=blockSize) { 
     294        int len = data.length - off; 
     295        if (len > blockSize) len = blockSize; 
     296        fin.readFully(data, off, len); 
     297        setProgress(progress, (int) (700L * 
     298          (off + blockSize) / data.length)); // estimate: 0% -> 70% 
     299        if (progress.isCanceled()) System.exit(0); 
     300      } 
     301      fin.close(); 
     302 
     303      // create types 
     304      progress.setNote("Creating types"); 
     305      RealType xType = RealType.getRealType("element"); 
     306      RealType yType = RealType.getRealType("line"); 
     307      ScaledUnit ns = new ScaledUnit(1e-9, SI.second, "ns"); 
     308      ScaledUnit nm = new ScaledUnit(1e-9, SI.meter, "nm"); 
     309      bcUnits = new Unit[] {ns, nm}; 
     310      bType = RealType.getRealType("bin", ns); 
     311      cType = RealType.getRealType("channel", nm); 
     312      RealType vType = RealType.getRealType("count"); 
     313      RealTupleType xy = new RealTupleType(xType, yType); 
     314      FunctionType xyvFunc = new FunctionType(xy, vType); 
     315      Integer2DSet xySet = new Integer2DSet(xy, width, height); 
     316      FunctionType cxyvFunc = new FunctionType(cType, xyvFunc); 
     317      Linear1DSet cSet = new Linear1DSet(cType, 
     318        minWave, maxWave, channels, null, new Unit[] {nm}, null); 
     319      bc = new RealTupleType(bType, cType); 
     320      RealType vType2 = RealType.getRealType("tau"); 
     321      RealTupleType vv = new RealTupleType(vType, vType2); 
     322      bcvFunc = new FunctionType(bc, vv); 
     323      RealType vTypeFit = RealType.getRealType("value_fit"); 
     324      bcvFuncFit = new FunctionType(bc, vTypeFit); 
     325      RealType vTypeRes = RealType.getRealType("value_res"); 
     326      bcvFuncRes = new FunctionType(bc, vTypeRes); 
     327      setProgress(progress, 710); // estimate: 71% 
     328      if (progress.isCanceled()) System.exit(0); 
     329 
     330      // plot intensity data in 2D display 
     331      progress.setNote("Building displays"); 
     332      iPlot = new DisplayImplJ3D("intensity", new TwoDDisplayRendererJ3D()); 
     333      iPlot.getMouseBehavior().getMouseHelper().setFunctionMap(new int[][][] { 
     334        {{MouseHelper.DIRECT, MouseHelper.NONE}, // L, shift-L 
     335         {MouseHelper.NONE, MouseHelper.NONE}}, // ctrl-L, ctrl-shift-L 
     336        {{MouseHelper.CURSOR_TRANSLATE, MouseHelper.CURSOR_ZOOM}, // M, shift-M 
     337         {MouseHelper.CURSOR_ROTATE, MouseHelper.NONE}}, // ctrl-M, ctrl-shift-M 
     338        {{MouseHelper.ROTATE, MouseHelper.ZOOM}, // R, shift-R 
     339         {MouseHelper.TRANSLATE, MouseHelper.NONE}}, // ctrl-R, ctrl-shift-R 
    429340      }); 
    430       fitRend.toggle(false); 
    431       resRend = new DefaultRendererJ3D(); 
    432       resRef = new DataReferenceImpl("residuals"); 
    433       decayPlot.addReferences(resRend, resRef); 
    434       resRend.toggle(false); 
    435     } 
    436     setProgress(progress, 770); // estimate: 77% 
    437     if (progress.isCanceled()) System.exit(0); 
    438  
    439     xMap.setRange(0, timeRange); 
    440     yMap.setRange(minWave, maxWave); 
    441     AxisScale xScale = xMap.getAxisScale(); 
    442     Font font = Font.decode("serif 24"); 
    443     xScale.setFont(font); 
    444     xScale.setTitle("Time (ns)"); 
    445     xScale.setSnapToBox(true); 
    446     AxisScale yScale = yMap.getAxisScale(); 
    447     yScale.setFont(font); 
    448     yScale.setTitle("Wavelength (nm)"); 
    449     yScale.setSide(AxisScale.SECONDARY); 
    450     yScale.setSnapToBox(true); 
    451     AxisScale zScale = zMap.getAxisScale(); 
    452     zScale.setFont(font); 
    453     zScale.setTitle("Count"); 
    454     zScale.setSnapToBox(true); // workaround for weird axis spacing issue 
    455     zMapFit.getAxisScale().setVisible(false); 
    456     zMapRes.getAxisScale().setVisible(false); 
    457     GraphicsModeControl gmc = decayPlot.getGraphicsModeControl(); 
    458     gmc.setScaleEnable(true); 
    459     gmc.setTextureEnable(false); 
    460     ProjectionControl pc = decayPlot.getProjectionControl(); 
    461     pc.setMatrix(channels > 1 ? MATRIX_3D : MATRIX_2D); 
    462     pc.setAspectCartesian( 
    463       new double[] {2, 1, 1}); 
    464     setProgress(progress, 780); // estimate: 78% 
    465     if (progress.isCanceled()) System.exit(0); 
    466  
    467     // convert byte data to unsigned shorts 
    468     progress.setNote("Constructing images"); 
    469     values = new int[channels][height][width][timeBins]; 
    470     float[][][] pix = new float[channels][1][width * height]; 
    471     FieldImpl field = new FieldImpl(cxyvFunc, cSet); 
    472     maxIntensity = new int[channels]; 
    473     for (int c=0; c<channels; c++) { 
    474       int oc = timeBins * width * height * c; 
     341      iPlot.enableEvent(DisplayEvent.MOUSE_DRAGGED); 
     342      iPlot.addDisplayListener(this); 
     343      setProgress(progress, 720); // estimate: 72% 
     344      if (progress.isCanceled()) System.exit(0); 
     345 
     346      iPlot.addMap(new ScalarMap(xType, Display.XAxis)); 
     347      iPlot.addMap(new ScalarMap(yType, Display.YAxis)); 
     348      intensityMap = new ScalarMap(vType, Display.RGB); 
     349      iPlot.addMap(intensityMap); 
     350      iPlot.addMap(new ScalarMap(cType, Display.Animation)); 
     351      DataReferenceImpl intensityRef = new DataReferenceImpl("intensity"); 
     352      iPlot.addReference(intensityRef); 
     353      setProgress(progress, 730); // estimate: 73% 
     354      if (progress.isCanceled()) System.exit(0); 
     355 
     356      // set up curve manipulation renderer in 2D display 
     357      roiGrid = new float[2][width * height]; 
     358      roiMask = new boolean[height][width]; 
    475359      for (int h=0; h<height; h++) { 
    476         int oh = timeBins * width * h; 
    477360        for (int w=0; w<width; w++) { 
    478           int ow = timeBins * w; 
    479           int sum = 0; 
    480           for (int t=0; t<timeBins; t++) { 
    481             int ndx = 2 * (oc + oh + ow + t); 
    482             int val = DataTools.bytesToInt(data, ndx, 2, true); 
    483             if (val > maxIntensity[c]) maxIntensity[c] = val; 
    484             values[c][h][w][t] = val; 
    485             sum += val; 
     361          int ndx = h * width + w; 
     362          roiGrid[0][ndx] = w; 
     363          roiGrid[1][ndx] = h; 
     364          roiMask[h][w] = true; 
     365        } 
     366      } 
     367      final DataReferenceImpl curveRef = new DataReferenceImpl("curve"); 
     368      UnionSet dummyCurve = new UnionSet(xy, new Gridded2DSet[] { 
     369        new Gridded2DSet(xy, new float[][] {{0}, {0}}, 1) 
     370      }); 
     371      curveRef.setData(dummyCurve); 
     372      CurveManipulationRendererJ3D curve = 
     373        new CurveManipulationRendererJ3D(0, 0, true); 
     374      iPlot.addReferences(curve, curveRef); 
     375      CellImpl cell = new CellImpl() { 
     376        public void doAction() throws VisADException, RemoteException { 
     377          // save latest drawn curve 
     378          curveSet = (UnionSet) curveRef.getData(); 
     379        } 
     380      }; 
     381      cell.addReference(curveRef); 
     382      roiRef = new DataReferenceImpl("roi"); 
     383      roiRef.setData(new Real(0)); // dummy 
     384      iPlot.addReference(roiRef, new ConstantMap[] { 
     385        new ConstantMap(0, Display.Blue), 
     386        new ConstantMap(0.1, Display.Alpha) 
     387      }); 
     388      setProgress(progress, 740); // estimate: 74% 
     389      if (progress.isCanceled()) System.exit(0); 
     390 
     391      ac = (AnimationControl) iPlot.getControl(AnimationControl.class); 
     392      iPlot.getProjectionControl().setMatrix( 
     393        iPlot.make_matrix(0, 0, 0, 0.85, 0, 0, 0)); 
     394 
     395      setProgress(progress, 750); // estimate: 75% 
     396      if (progress.isCanceled()) System.exit(0); 
     397 
     398      // plot decay curves in 3D display 
     399      decayPlot = channels > 1 ? new DisplayImplJ3D("decay") : 
     400        new DisplayImplJ3D("decay", new TwoDDisplayRendererJ3D()); 
     401      ScalarMap xMap = new ScalarMap(bType, Display.XAxis); 
     402      ScalarMap yMap = new ScalarMap(cType, Display.YAxis); 
     403      DisplayRealType heightAxis = channels > 1 ? Display.ZAxis : Display.YAxis; 
     404      zMap = new ScalarMap(vType, heightAxis); 
     405      zMapFit = new ScalarMap(vTypeFit, heightAxis); 
     406      zMapRes = new ScalarMap(vTypeRes, heightAxis); 
     407      vMap = new ScalarMap(vType2, Display.RGB); 
     408      //vMapFit = new ScalarMap(vTypeFit, Display.RGB); 
     409      vMapRes = new ScalarMap(vTypeRes, Display.RGB); 
     410      decayPlot.addMap(xMap); 
     411      if (channels > 1) decayPlot.addMap(yMap); 
     412      decayPlot.addMap(zMap); 
     413      decayPlot.addMap(zMapFit); 
     414      decayPlot.addMap(zMapRes); 
     415      decayPlot.addMap(vMap); 
     416      //decayPlot.addMap(vMapFit); 
     417      decayPlot.addMap(vMapRes); 
     418      setProgress(progress, 760); // estimate: 76% 
     419      if (progress.isCanceled()) System.exit(0); 
     420 
     421      decayRend = new DefaultRendererJ3D(); 
     422      decayRef = new DataReferenceImpl("decay"); 
     423      decayPlot.addReferences(decayRend, decayRef); 
     424      if (adjustPeaks) { 
     425        fitRend = new DefaultRendererJ3D(); 
     426        fitRef = new DataReferenceImpl("fit"); 
     427        decayPlot.addReferences(fitRend, fitRef, new ConstantMap[] { 
     428          new ConstantMap(1.0, Display.Red), 
     429          new ConstantMap(1.0, Display.Green), 
     430          new ConstantMap(1.0, Display.Blue) 
     431        }); 
     432        fitRend.toggle(false); 
     433        resRend = new DefaultRendererJ3D(); 
     434        resRef = new DataReferenceImpl("residuals"); 
     435        decayPlot.addReferences(resRend, resRef); 
     436        resRend.toggle(false); 
     437      } 
     438      setProgress(progress, 770); // estimate: 77% 
     439      if (progress.isCanceled()) System.exit(0); 
     440 
     441      xMap.setRange(0, timeRange); 
     442      yMap.setRange(minWave, maxWave); 
     443      AxisScale xScale = xMap.getAxisScale(); 
     444      Font font = Font.decode("serif 24"); 
     445      xScale.setFont(font); 
     446      xScale.setTitle("Time (ns)"); 
     447      xScale.setSnapToBox(true); 
     448      AxisScale yScale = yMap.getAxisScale(); 
     449      yScale.setFont(font); 
     450      yScale.setTitle("Wavelength (nm)"); 
     451      yScale.setSide(AxisScale.SECONDARY); 
     452      yScale.setSnapToBox(true); 
     453      AxisScale zScale = zMap.getAxisScale(); 
     454      zScale.setFont(font); 
     455      zScale.setTitle("Count"); 
     456      zScale.setSnapToBox(true); // workaround for weird axis spacing issue 
     457      zMapFit.getAxisScale().setVisible(false); 
     458      zMapRes.getAxisScale().setVisible(false); 
     459      GraphicsModeControl gmc = decayPlot.getGraphicsModeControl(); 
     460      gmc.setScaleEnable(true); 
     461      gmc.setTextureEnable(false); 
     462      ProjectionControl pc = decayPlot.getProjectionControl(); 
     463      pc.setMatrix(channels > 1 ? MATRIX_3D : MATRIX_2D); 
     464      pc.setAspectCartesian( 
     465        new double[] {2, 1, 1}); 
     466      setProgress(progress, 780); // estimate: 78% 
     467      if (progress.isCanceled()) System.exit(0); 
     468 
     469      // convert byte data to unsigned shorts 
     470      progress.setNote("Constructing images"); 
     471      values = new int[channels][height][width][timeBins]; 
     472      float[][][] pix = new float[channels][1][width * height]; 
     473      FieldImpl field = new FieldImpl(cxyvFunc, cSet); 
     474      maxIntensity = new int[channels]; 
     475      for (int c=0; c<channels; c++) { 
     476        int oc = timeBins * width * height * c; 
     477        for (int h=0; h<height; h++) { 
     478          int oh = timeBins * width * h; 
     479          for (int w=0; w<width; w++) { 
     480            int ow = timeBins * w; 
     481            int sum = 0; 
     482            for (int t=0; t<timeBins; t++) { 
     483              int ndx = 2 * (oc + oh + ow + t); 
     484              int val = DataTools.bytesToInt(data, ndx, 2, true); 
     485              if (val > maxIntensity[c]) maxIntensity[c] = val; 
     486              values[c][h][w][t] = val; 
     487              sum += val; 
     488            } 
     489            pix[c][0][width * h + w] = sum; 
    486490          } 
    487           pix[c][0][width * h + w] = sum; 
    488         } 
    489         setProgress(progress, 780 + 140 * 
    490           (height * c + h + 1) / (channels * height)); // estimate: 78% -> 92% 
    491         if (progress.isCanceled()) System.exit(0); 
    492       } 
    493       FlatField ff = new FlatField(xyvFunc, xySet); 
    494       ff.setSamples(pix[c], false); 
    495       field.setSample(c, ff); 
    496     } 
    497  
    498     // compute channel with brightest intensity 
    499     int maxChan = 0; 
    500     int max = 0; 
    501     for (int c=0; c<channels; c++) { 
    502       if (maxIntensity[c] > max) { 
    503         max = maxIntensity[c]; 
    504         maxChan = c; 
    505       } 
    506     } 
    507  
    508     // adjust peaks 
    509     if (adjustPeaks) { 
    510       progress.setNote("Adjusting peaks"); 
    511       int[] peaks = new int[channels]; 
     491          setProgress(progress, 780 + 140 * 
     492            (height * c + h + 1) / (channels * height)); // estimate: 78% -> 92% 
     493          if (progress.isCanceled()) System.exit(0); 
     494        } 
     495        FlatField ff = new FlatField(xyvFunc, xySet); 
     496        ff.setSamples(pix[c], false); 
     497        field.setSample(c, ff); 
     498      } 
     499 
     500      // compute channel with brightest intensity 
     501      maxChan = 0; 
     502      int max = 0; 
    512503      for (int c=0; c<channels; c++) { 
    513         int[] sum = new int[timeBins]; 
    514         for (int h=0; h<height; h++) { 
    515           for (int w=0; w<width; w++) { 
    516             for (int t=0; t<timeBins; t++) sum[t] += values[c][h][w][t]; 
    517           } 
    518         } 
    519         int peak = 0, ndx = 0; 
    520         for (int t=0; t<timeBins; t++) { 
    521           if (peak <= sum[t]) { 
    522             peak = sum[t]; 
    523             ndx = t; 
    524           } 
    525           else if (t > timeBins / 3) break; // HACK - too early to give up 
    526         } 
    527         peaks[c] = ndx; 
    528         setProgress(progress, 920 + 20 * 
    529           (c + 1) / channels); // estimate: 92% -> 94% 
    530         if (progress.isCanceled()) System.exit(0); 
    531       } 
    532       maxPeak = 0; 
    533       for (int c=0; c<channels; c++) { 
    534         if (maxPeak < peaks[c]) maxPeak = peaks[c]; 
    535       } 
    536       log("Aligning peaks to tmax = " + maxPeak); 
    537       for (int c=0; c<channels; c++) { 
    538         int shift = maxPeak - peaks[c]; 
    539         if (shift > 0) { 
     504        if (maxIntensity[c] > max) { 
     505          max = maxIntensity[c]; 
     506          maxChan = c; 
     507        } 
     508      } 
     509 
     510      // adjust peaks 
     511      if (adjustPeaks) { 
     512        progress.setNote("Adjusting peaks"); 
     513        int[] peaks = new int[channels]; 
     514        for (int c=0; c<channels; c++) { 
     515          int[] sum = new int[timeBins]; 
    540516          for (int h=0; h<height; h++) { 
    541517            for (int w=0; w<width; w++) { 
    542               for (int t=timeBins-1; t>=shift; t--) { 
    543                 values[c][h][w][t] = values[c][h][w][t - shift]; 
    544               } 
    545               for (int t=shift-1; t>=0; t--) values[c][h][w][t] = 0; 
     518              for (int t=0; t<timeBins; t++) sum[t] += values[c][h][w][t]; 
    546519            } 
    547520          } 
    548           log("\tChannel #" + (c + 1) + ": tmax = " + peaks[c] + 
    549             " (shifting by " + shift + ")"); 
    550         } 
    551         setProgress(progress, 940 + 20 * 
    552           (c + 1) / channels); // estimate: 94% -> 96% 
    553         if (progress.isCanceled()) System.exit(0); 
    554       } 
    555  
    556       // add yellow line to indicate adjusted peak position 
    557       lineRend = new DefaultRendererJ3D(); 
    558       DataReferenceImpl peakRef = new DataReferenceImpl("peaks"); 
    559       float peakTime = (float) (maxPeak * timeRange / timeBins); 
    560       peakRef.setData(new Gridded2DSet(bc, 
    561         new float[][] {{peakTime, peakTime}, {minWave, maxWave}}, 2)); 
    562       decayPlot.addReferences(lineRend, peakRef, new ConstantMap[] { 
    563         new ConstantMap(-1, Display.ZAxis), 
    564         new ConstantMap(0, Display.Blue), 
    565         //new ConstantMap(2, Display.LineWidth) 
    566       }); 
    567     } 
    568  
    569     // construct 2D pane 
    570     progress.setNote("Creating plots"); 
    571     JFrame masterWindow = new JFrame("Slim Plotter - " + file.getName()); 
    572     masterWindow.addWindowListener(this); 
    573     JPanel masterPane = new JPanel(); 
    574     masterPane.setLayout(new BorderLayout()); 
    575     masterWindow.setContentPane(masterPane); 
    576     JPanel intensityPane = new JPanel(); 
    577     intensityPane.setLayout(new BoxLayout(intensityPane, BoxLayout.Y_AXIS)); 
    578     JPanel iPlotPane = new JPanel() { 
    579       private int height = 380; 
    580       public Dimension getMinimumSize() { 
    581         Dimension min = super.getMinimumSize(); 
    582         return new Dimension(min.width, height); 
    583       } 
    584       public Dimension getPreferredSize() { 
    585         Dimension pref = super.getPreferredSize(); 
    586         return new Dimension(pref.width, height); 
    587       } 
    588       public Dimension getMaximumSize() { 
    589         Dimension max = super.getMaximumSize(); 
    590         return new Dimension(max.width, height); 
    591       } 
    592     }; 
    593     iPlotPane.setLayout(new BorderLayout()); 
    594     iPlotPane.add(iPlot.getComponent(), BorderLayout.CENTER); 
    595     intensityPane.add(iPlotPane); 
    596  
    597     setProgress(progress, 970); // estimate: 97% 
    598     if (progress.isCanceled()) System.exit(0); 
    599  
    600     JPanel sliderPane = new JPanel(); 
    601     sliderPane.setLayout(new BoxLayout(sliderPane, BoxLayout.X_AXIS)); 
    602     intensityPane.add(sliderPane); 
    603     cSlider = new JSlider(1, channels, 1); 
    604     cSlider.setToolTipText( 
    605       "Selects the channel to display in the 2D intensity plot above"); 
    606     cSlider.setSnapToTicks(true); 
    607     cSlider.setMajorTickSpacing(channels / 4); 
    608     cSlider.setMinorTickSpacing(1); 
    609     cSlider.setPaintTicks(true); 
    610     cSlider.addChangeListener(this); 
    611     cSlider.setBorder(new EmptyBorder(8, 5, 8, 5)); 
    612     cSlider.setEnabled(channels > 1); 
    613     sliderPane.add(cSlider); 
    614     cToggle = new JCheckBox("", true); 
    615     cToggle.setToolTipText( 
    616       "Toggles the selected channel's visibility in the 3D data plot"); 
    617     cToggle.addActionListener(this); 
    618     cToggle.setEnabled(channels > 1); 
    619     sliderPane.add(cToggle); 
    620  
    621     JPanel minMaxPane = new JPanel(); 
    622     minMaxPane.setLayout(new BoxLayout(minMaxPane, BoxLayout.X_AXIS)); 
    623     intensityPane.add(minMaxPane); 
    624  
    625     JPanel minPane = new JPanel(); 
    626     minPane.setLayout(new BoxLayout(minPane, BoxLayout.Y_AXIS)); 
    627     minMaxPane.add(minPane); 
    628     minLabel = new JLabel("min=0"); 
    629     minLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT); 
    630     minPane.add(minLabel); 
    631     minSlider = new JSlider(0, max, 0); 
    632     minSlider.setToolTipText("<html>" + 
    633       "Adjusts intensity plot's minimum color value.<br>" + 
    634       "Anything less than this value appears black.</html>"); 
    635     minSlider.setMajorTickSpacing(max); 
    636     int minor = max / 16; 
    637     if (minor < 1) minor = 1; 
    638     minSlider.setMinorTickSpacing(minor); 
    639     minSlider.setPaintTicks(true); 
    640     minSlider.addChangeListener(this); 
    641     minSlider.setBorder(new EmptyBorder(0, 5, 8, 5)); 
    642     minPane.add(minSlider); 
    643  
    644     JPanel maxPane = new JPanel(); 
    645     maxPane.setLayout(new BoxLayout(maxPane, BoxLayout.Y_AXIS)); 
    646     minMaxPane.add(maxPane); 
    647     maxLabel = new JLabel("max=" + max); 
    648     maxLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT); 
    649     maxPane.add(maxLabel); 
    650     maxSlider = new JSlider(0, max, max); 
    651     maxSlider.setToolTipText("<html>" + 
    652       "Adjusts intensity plot's maximum color value.<br>" + 
    653       "Anything greater than this value appears white.</html>"); 
    654     maxSlider.setMajorTickSpacing(max); 
    655     maxSlider.setMinorTickSpacing(minor); 
    656     maxSlider.setPaintTicks(true); 
    657     maxSlider.addChangeListener(this); 
    658     maxSlider.setBorder(new EmptyBorder(0, 5, 8, 5)); 
    659     maxPane.add(maxSlider); 
    660  
    661     intensityRef.setData(field); 
    662     ColorControl cc = (ColorControl) iPlot.getControl(ColorControl.class); 
    663     cc.setTable(ColorControl.initTableGreyWedge(new float[3][256])); 
    664  
    665     setProgress(progress, 980); // estimate: 98% 
    666     if (progress.isCanceled()) System.exit(0); 
    667  
    668     // construct 3D pane 
    669     JPanel decayPane = new JPanel(); 
    670     decayPane.setLayout(new BorderLayout()); 
    671     decayPane.add(decayPlot.getComponent(), BorderLayout.CENTER); 
    672  
    673     decayLabel = new JLabel("Decay curve for all pixels"); 
    674     decayLabel.setToolTipText( 
    675       "Displays information about the selected region of interest"); 
    676     decayPane.add(decayLabel, BorderLayout.NORTH); 
    677  
    678     ColorMapWidget colorWidget = new ColorMapWidget(vMap); 
    679     Dimension prefSize = colorWidget.getPreferredSize(); 
    680     colorWidget.setPreferredSize(new Dimension(prefSize.width, 0)); 
    681  
    682     showData = new JCheckBox("Data", true); 
    683     showData.setToolTipText("Toggles visibility of raw data"); 
    684     showData.addActionListener(this); 
    685     showScale = new JCheckBox("Scale", true); 
    686     showScale.setToolTipText("Toggles visibility of scale bars"); 
    687     showScale.addActionListener(this); 
    688     showBox = new JCheckBox("Box", true); 
    689     showBox.setToolTipText("Toggles visibility of bounding box"); 
    690     showBox.addActionListener(this); 
    691     showLine = new JCheckBox("Line", adjustPeaks); 
    692     showLine.setToolTipText( 
    693       "Toggles visibility of aligned peaks indicator line"); 
    694     showLine.setEnabled(adjustPeaks); 
    695     showLine.addActionListener(this); 
    696     showFit = new JCheckBox("Fit", false); 
    697     showFit.setToolTipText("Toggles visibility of fitted curves"); 
    698     showFit.setEnabled(adjustPeaks); 
    699     showFit.addActionListener(this); 
    700     showResiduals = new JCheckBox("Residuals", false); 
    701     showResiduals.setToolTipText( 
    702       "Toggles visibility of fitted curve residuals"); 
    703     showResiduals.setEnabled(adjustPeaks); 
    704     showResiduals.addActionListener(this); 
    705  
    706     linear = new JRadioButton("Linear", true); 
    707     linear.setToolTipText("Plots 3D data with a linear scale"); 
    708     log = new JRadioButton("Log", false); 
    709     log.setToolTipText("Plots 3D data with a logarithmic scale"); 
    710     perspective = new JRadioButton("Perspective", true); 
    711     perspective.setToolTipText( 
    712       "Displays 3D plot with a perspective projection"); 
    713     perspective.setEnabled(channels > 1); 
    714     parallel = new JRadioButton("Parallel", false); 
    715     parallel.setToolTipText( 
    716       "Displays 3D plot with a parallel (orthographic) projection"); 
    717     parallel.setEnabled(channels > 1); 
    718     dataSurface = new JRadioButton("Surface", channels > 1); 
    719     dataSurface.setToolTipText("Displays raw data as a 2D surface"); 
    720     dataSurface.setEnabled(channels > 1); 
    721     dataLines = new JRadioButton("Lines", channels == 1); 
    722     dataLines.setToolTipText("Displays raw data as a series of lines"); 
    723     dataLines.setEnabled(channels > 1); 
    724     fitSurface = new JRadioButton("Surface", false); 
    725     fitSurface.setToolTipText("Displays fitted curves as a 2D surface"); 
    726     fitSurface.setEnabled(adjustPeaks && channels > 1); 
    727     fitLines = new JRadioButton("Lines", true); 
    728     fitLines.setToolTipText("Displays fitted curves as a series of lines"); 
    729     fitLines.setEnabled(adjustPeaks && channels > 1); 
    730     resSurface = new JRadioButton("Surface", false); 
    731     resSurface.setToolTipText( 
    732       "Displays fitted curve residuals as a 2D surface"); 
    733     resSurface.setEnabled(adjustPeaks && channels > 1); 
    734     resLines = new JRadioButton("Lines", true); 
    735     resLines.setToolTipText( 
    736       "Displays fitted curve residuals as a series of lines"); 
    737     resLines.setEnabled(adjustPeaks && channels > 1); 
    738     colorHeight = new JRadioButton("Counts", true); 
    739     colorHeight.setToolTipText( 
    740       "Colorizes data according to the height (histogram count)"); 
    741     colorHeight.setEnabled(adjustPeaks && channels > 1); 
    742     colorTau = new JRadioButton("Lifetimes", false); 
    743     colorTau.setToolTipText( 
    744       "Colorizes data according to aggregate lifetime value"); 
    745     colorTau.setEnabled(adjustPeaks && channels > 1); 
    746  
    747     zOverride = new JCheckBox("", false); 
    748     zOverride.setToolTipText("Toggles manual override of Z axis scale (Count)"); 
    749     zOverride.addActionListener(this); 
    750     zScaleValue = new JTextField(9); 
    751     zScaleValue.setToolTipText("Overridden Z axis scale value"); 
    752     zScaleValue.setEnabled(false); 
    753     zScaleValue.getDocument().addDocumentListener(this); 
    754  
    755     exportData = new JButton("Export"); 
    756     exportData.setToolTipText( 
    757       "Exports the selected ROI's raw data to a text file"); 
    758     exportData.addActionListener(this); 
    759  
    760     numCurves = new JSpinner(new SpinnerNumberModel(1, 1, 9, 1)); 
    761     numCurves.setToolTipText("Number of components in exponential fit"); 
    762     numCurves.setMaximumSize(numCurves.getPreferredSize()); 
    763     numCurves.addChangeListener(this); 
    764  
    765     setProgress(progress, 990); // estimate: 99% 
    766     if (progress.isCanceled()) System.exit(0); 
    767  
    768     JPanel showPanel = new JPanel(); 
    769     showPanel.setBorder(new TitledBorder("Show")); 
    770     showPanel.setLayout(new BoxLayout(showPanel, BoxLayout.Y_AXIS)); 
    771     showPanel.add(showData); 
    772     showPanel.add(showScale); 
    773     showPanel.add(showBox); 
    774     showPanel.add(showLine); 
    775     showPanel.add(showFit); 
    776     showPanel.add(showResiduals); 
    777  
    778     JPanel scalePanel = new JPanel(); 
    779     scalePanel.setBorder(new TitledBorder("Z Scale Override")); 
    780     scalePanel.setLayout(new BoxLayout(scalePanel, BoxLayout.X_AXIS)); 
    781     scalePanel.add(zOverride); 
    782     scalePanel.add(zScaleValue); 
    783  
    784     JPanel colorPanel = new JPanel(); 
    785     colorPanel.setBorder(new TitledBorder("Color Mapping")); 
    786     colorPanel.setLayout(new BorderLayout()); 
    787     colorPanel.add(colorWidget); 
    788  
    789     JPanel miscRow1 = new JPanel(); 
    790     miscRow1.setLayout(new BoxLayout(miscRow1, BoxLayout.X_AXIS)); 
    791     miscRow1.add(makeRadioPanel("Scale", linear, log)); 
    792     miscRow1.add(makeRadioPanel("Projection", perspective, parallel)); 
    793     miscRow1.add(makeRadioPanel("Data", dataSurface, dataLines)); 
    794  
    795     JPanel miscRow2 = new JPanel(); 
    796     miscRow2.setLayout(new BoxLayout(miscRow2, BoxLayout.X_AXIS)); 
    797     miscRow2.add(makeRadioPanel("Fit", fitSurface, fitLines)); 
    798     miscRow2.add(makeRadioPanel("Residuals", resSurface, resLines)); 
    799     miscRow2.add(makeRadioPanel("Colors", colorHeight, colorTau)); 
    800  
    801     JPanel miscRow3 = new JPanel(); 
    802     miscRow3.setLayout(new BoxLayout(miscRow3, BoxLayout.X_AXIS)); 
    803     miscRow3.add(scalePanel); 
    804     miscRow3.add(Box.createHorizontalStrut(5)); 
    805     miscRow3.add(exportData); 
    806     //miscRow3.add(numCurves); 
    807  
    808     JPanel miscPanel = new JPanel(); 
    809     miscPanel.setLayout(new BoxLayout(miscPanel, BoxLayout.Y_AXIS)); 
    810     miscPanel.add(miscRow1); 
    811     miscPanel.add(miscRow2); 
    812     miscPanel.add(miscRow3); 
    813  
    814     JPanel options = new JPanel(); 
    815     options.setBorder(new EmptyBorder(8, 5, 8, 5)); 
    816     options.setLayout(new BoxLayout(options, BoxLayout.X_AXIS)); 
    817     options.add(colorPanel); 
    818     options.add(showPanel); 
    819     options.add(miscPanel); 
    820     decayPane.add(options, BorderLayout.SOUTH); 
    821     masterPane.add(decayPane, BorderLayout.CENTER); 
    822  
    823     JPanel rightPanel = new JPanel() { 
    824       public Dimension getMaximumSize() { 
    825         Dimension pref = getPreferredSize(); 
    826         Dimension max = super.getMaximumSize(); 
    827         return new Dimension(pref.width, max.height); 
    828       } 
    829     }; 
    830     rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS)); 
    831     rightPanel.add(intensityPane); 
    832     rightPanel.add(console.getWindow().getContentPane()); 
    833     BreakawayPanel breakawayPanel = new BreakawayPanel(masterPane, 
    834       "Intensity Data - " + file.getName(), false); 
    835     breakawayPanel.setEdge(BorderLayout.EAST); 
    836     breakawayPanel.setUpEnabled(false); 
    837     breakawayPanel.setDownEnabled(false); 
    838     breakawayPanel.setContentPane(rightPanel); 
    839  
    840     setProgress(progress, 999); // estimate: 99.9% 
    841     if (progress.isCanceled()) System.exit(0); 
    842  
    843     // show window on screen 
    844     masterWindow.pack(); 
    845     Dimension size = masterWindow.getSize(); 
    846     Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); 
    847     masterWindow.setLocation((screen.width - size.width) / 2, 
    848       (screen.height - size.height) / 2); 
    849     masterWindow.setVisible(true); 
     521          int peak = 0, ndx = 0; 
     522          for (int t=0; t<timeBins; t++) { 
     523            if (peak <= sum[t]) { 
     524              peak = sum[t]; 
     525              ndx = t; 
     526            } 
     527            else if (t > timeBins / 3) break; // HACK - too early to give up 
     528          } 
     529          peaks[c] = ndx; 
     530          setProgress(progress, 920 + 20 * 
     531            (c + 1) / channels); // estimate: 92% -> 94% 
     532          if (progress.isCanceled()) System.exit(0); 
     533        } 
     534        maxPeak = 0; 
     535        for (int c=0; c<channels; c++) { 
     536          if (maxPeak < peaks[c]) maxPeak = peaks[c]; 
     537        } 
     538        log("Aligning peaks to tmax = " + maxPeak); 
     539        for (int c=0; c<channels; c++) { 
     540          int shift = maxPeak - peaks[c]; 
     541          if (shift > 0) { 
     542            for (int h=0; h<height; h++) { 
     543              for (int w=0; w<width; w++) { 
     544                for (int t=timeBins-1; t>=shift; t--) { 
     545                  values[c][h][w][t] = values[c][h][w][t - shift]; 
     546                } 
     547                for (int t=shift-1; t>=0; t--) values[c][h][w][t] = 0; 
     548              } 
     549            } 
     550            log("\tChannel #" + (c + 1) + ": tmax = " + peaks[c] + 
     551              " (shifting by " + shift + ")"); 
     552          } 
     553          setProgress(progress, 940 + 20 * 
     554            (c + 1) / channels); // estimate: 94% -> 96% 
     555          if (progress.isCanceled()) System.exit(0); 
     556        } 
     557 
     558        // add yellow line to indicate adjusted peak position 
     559        lineRend = new DefaultRendererJ3D(); 
     560        DataReferenceImpl peakRef = new DataReferenceImpl("peaks"); 
     561        float peakTime = (float) (maxPeak * timeRange / timeBins); 
     562        peakRef.setData(new Gridded2DSet(bc, 
     563          new float[][] {{peakTime, peakTime}, {minWave, maxWave}}, 2)); 
     564        decayPlot.addReferences(lineRend, peakRef, new ConstantMap[] { 
     565          new ConstantMap(-1, Display.ZAxis), 
     566          new ConstantMap(0, Display.Blue), 
     567          //new ConstantMap(2, Display.LineWidth) 
     568        }); 
     569      } 
     570 
     571      // construct 2D pane 
     572      progress.setNote("Creating plots"); 
     573      JFrame masterWindow = new JFrame("Slim Plotter - " + file.getName()); 
     574      masterWindow.addWindowListener(this); 
     575      JPanel masterPane = new JPanel(); 
     576      masterPane.setLayout(new BorderLayout()); 
     577      masterWindow.setContentPane(masterPane); 
     578      JPanel intensityPane = new JPanel(); 
     579      intensityPane.setLayout(new BoxLayout(intensityPane, BoxLayout.Y_AXIS)); 
     580      JPanel iPlotPane = new JPanel() { 
     581        private int height = 380; 
     582        public Dimension getMinimumSize() { 
     583          Dimension min = super.getMinimumSize(); 
     584          return new Dimension(min.width, height); 
     585        } 
     586        public Dimension getPreferredSize() { 
     587          Dimension pref = super.getPreferredSize(); 
     588          return new Dimension(pref.width, height); 
     589        } 
     590        public Dimension getMaximumSize() { 
     591          Dimension max = super.getMaximumSize(); 
     592          return new Dimension(max.width, height); 
     593        } 
     594      }; 
     595      iPlotPane.setLayout(new BorderLayout()); 
     596      iPlotPane.add(iPlot.getComponent(), BorderLayout.CENTER); 
     597      intensityPane.add(iPlotPane); 
     598 
     599      setProgress(progress, 970); // estimate: 97% 
     600      if (progress.isCanceled()) System.exit(0); 
     601 
     602      JPanel sliderPane = new JPanel(); 
     603      sliderPane.setLayout(new BoxLayout(sliderPane, BoxLayout.X_AXIS)); 
     604      intensityPane.add(sliderPane); 
     605      cSlider = new JSlider(1, channels, 1); 
     606      cSlider.setToolTipText( 
     607        "Selects the channel to display in the 2D intensity plot above"); 
     608      cSlider.setSnapToTicks(true); 
     609      cSlider.setMajorTickSpacing(channels / 4); 
     610      cSlider.setMinorTickSpacing(1); 
     611      cSlider.setPaintTicks(true); 
     612      cSlider.addChangeListener(this); 
     613      cSlider.setBorder(new EmptyBorder(8, 5, 8, 5)); 
     614      cSlider.setEnabled(channels > 1); 
     615      sliderPane.add(cSlider); 
     616      cToggle = new JCheckBox("", true); 
     617      cToggle.setToolTipText( 
     618        "Toggles the selected channel's visibility in the 3D data plot"); 
     619      cToggle.addActionListener(this); 
     620      cToggle.setEnabled(channels > 1); 
     621      sliderPane.add(cToggle); 
     622 
     623      JPanel minMaxPane = new JPanel(); 
     624      minMaxPane.setLayout(new BoxLayout(minMaxPane, BoxLayout.X_AXIS)); 
     625      intensityPane.add(minMaxPane); 
     626 
     627      JPanel minPane = new JPanel(); 
     628      minPane.setLayout(new BoxLayout(minPane, BoxLayout.Y_AXIS)); 
     629      minMaxPane.add(minPane); 
     630      minLabel = new JLabel("min=0"); 
     631      minLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT); 
     632      minPane.add(minLabel); 
     633      minSlider = new JSlider(0, max, 0); 
     634      minSlider.setToolTipText("<html>" + 
     635        "Adjusts intensity plot's minimum color value.<br>" + 
     636        "Anything less than this value appears black.</html>"); 
     637      minSlider.setMajorTickSpacing(max); 
     638      int minor = max / 16; 
     639      if (minor < 1) minor = 1; 
     640      minSlider.setMinorTickSpacing(minor); 
     641      minSlider.setPaintTicks(true); 
     642      minSlider.addChangeListener(this); 
     643      minSlider.setBorder(new EmptyBorder(0, 5, 8, 5)); 
     644      minPane.add(minSlider); 
     645 
     646      JPanel maxPane = new JPanel(); 
     647      maxPane.setLayout(new BoxLayout(maxPane, BoxLayout.Y_AXIS)); 
     648      minMaxPane.add(maxPane); 
     649      maxLabel = new JLabel("max=" + max); 
     650      maxLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT); 
     651      maxPane.add(maxLabel); 
     652      maxSlider = new JSlider(0, max, max); 
     653      maxSlider.setToolTipText("<html>" + 
     654        "Adjusts intensity plot's maximum color value.<br>" + 
     655        "Anything greater than this value appears white.</html>"); 
     656      maxSlider.setMajorTickSpacing(max); 
     657      maxSlider.setMinorTickSpacing(minor); 
     658      maxSlider.setPaintTicks(true); 
     659      maxSlider.addChangeListener(this); 
     660      maxSlider.setBorder(new EmptyBorder(0, 5, 8, 5)); 
     661      maxPane.add(maxSlider); 
     662 
     663      intensityRef.setData(field); 
     664      ColorControl cc = (ColorControl) iPlot.getControl(ColorControl.class); 
     665      cc.setTable(ColorControl.initTableGreyWedge(new float[3][256])); 
     666 
     667      setProgress(progress, 980); // estimate: 98% 
     668      if (progress.isCanceled()) System.exit(0); 
     669 
     670      // construct 3D pane 
     671      JPanel decayPane = new JPanel(); 
     672      decayPane.setLayout(new BorderLayout()); 
     673      decayPane.add(decayPlot.getComponent(), BorderLayout.CENTER); 
     674 
     675      decayLabel = new JLabel("Decay curve for all pixels"); 
     676      decayLabel.setToolTipText( 
     677        "Displays information about the selected region of interest"); 
     678      decayPane.add(decayLabel, BorderLayout.NORTH); 
     679 
     680      ColorMapWidget colorWidget = new ColorMapWidget(vMap); 
     681      Dimension prefSize = colorWidget.getPreferredSize(); 
     682      colorWidget.setPreferredSize(new Dimension(prefSize.width, 0)); 
     683 
     684      showData = new JCheckBox("Data", true); 
     685      showData.setToolTipText("Toggles visibility of raw data"); 
     686      showData.addActionListener(this); 
     687      showScale = new JCheckBox("Scale", true); 
     688      showScale.setToolTipText("Toggles visibility of scale bars"); 
     689      showScale.addActionListener(this); 
     690      showBox = new JCheckBox("Box", true); 
     691      showBox.setToolTipText("Toggles visibility of bounding box"); 
     692      showBox.addActionListener(this); 
     693      showLine = new JCheckBox("Line", adjustPeaks); 
     694      showLine.setToolTipText( 
     695        "Toggles visibility of aligned peaks indicator line"); 
     696      showLine.setEnabled(adjustPeaks); 
     697      showLine.addActionListener(this); 
     698      showFit = new JCheckBox("Fit", false); 
     699      showFit.setToolTipText("Toggles visibility of fitted curves"); 
     700      showFit.setEnabled(adjustPeaks); 
     701      showFit.addActionListener(this); 
     702      showResiduals = new JCheckBox("Residuals", false); 
     703      showResiduals.setToolTipText( 
     704        "Toggles visibility of fitted curve residuals"); 
     705      showResiduals.setEnabled(adjustPeaks); 
     706      showResiduals.addActionListener(this); 
     707 
     708      linear = new JRadioButton("Linear", true); 
     709      linear.setToolTipText("Plots 3D data with a linear scale"); 
     710      log = new JRadioButton("Log", false); 
     711      log.setToolTipText("Plots 3D data with a logarithmic scale"); 
     712      perspective = new JRadioButton("Perspective", true); 
     713      perspective.setToolTipText( 
     714        "Displays 3D plot with a perspective projection"); 
     715      perspective.setEnabled(channels > 1); 
     716      parallel = new JRadioButton("Parallel", false); 
     717      parallel.setToolTipText( 
     718        "Displays 3D plot with a parallel (orthographic) projection"); 
     719      parallel.setEnabled(channels > 1); 
     720      dataSurface = new JRadioButton("Surface", channels > 1); 
     721      dataSurface.setToolTipText("Displays raw data as a 2D surface"); 
     722      dataSurface.setEnabled(channels > 1); 
     723      dataLines = new JRadioButton("Lines", channels == 1); 
     724      dataLines.setToolTipText("Displays raw data as a series of lines"); 
     725      dataLines.setEnabled(channels > 1); 
     726      fitSurface = new JRadioButton("Surface", false); 
     727      fitSurface.setToolTipText("Displays fitted curves as a 2D surface"); 
     728      fitSurface.setEnabled(adjustPeaks && channels > 1); 
     729      fitLines = new JRadioButton("Lines", true); 
     730      fitLines.setToolTipText("Displays fitted curves as a series of lines"); 
     731      fitLines.setEnabled(adjustPeaks && channels > 1); 
     732      resSurface = new JRadioButton("Surface", false); 
     733      resSurface.setToolTipText( 
     734        "Displays fitted curve residuals as a 2D surface"); 
     735      resSurface.setEnabled(adjustPeaks && channels > 1); 
     736      resLines = new JRadioButton("Lines", true); 
     737      resLines.setToolTipText( 
     738        "Displays fitted curve residuals as a series of lines"); 
     739      resLines.setEnabled(adjustPeaks && channels > 1); 
     740      colorHeight = new JRadioButton("Counts", true); 
     741      colorHeight.setToolTipText( 
     742        "Colorizes data according to the height (histogram count)"); 
     743      colorHeight.setEnabled(adjustPeaks && channels > 1); 
     744      colorTau = new JRadioButton("Lifetimes", false); 
     745      colorTau.setToolTipText( 
     746        "Colorizes data according to aggregate lifetime value"); 
     747      colorTau.setEnabled(adjustPeaks && channels > 1); 
     748 
     749      zOverride = new JCheckBox("", false); 
     750      zOverride.setToolTipText( 
     751        "Toggles manual override of Z axis scale (Count)"); 
     752      zOverride.addActionListener(this); 
     753      zScaleValue = new JTextField(9); 
     754      zScaleValue.setToolTipText("Overridden Z axis scale value"); 
     755      zScaleValue.setEnabled(false); 
     756      zScaleValue.getDocument().addDocumentListener(this); 
     757 
     758      exportData = new JButton("Export"); 
     759      exportData.setToolTipText( 
     760        "Exports the selected ROI's raw data to a text file"); 
     761      exportData.addActionListener(this); 
     762 
     763      numCurves = new JSpinner(new SpinnerNumberModel(1, 1, 9, 1)); 
     764      numCurves.setToolTipText("Number of components in exponential fit"); 
     765      numCurves.setMaximumSize(numCurves.getPreferredSize()); 
     766      numCurves.addChangeListener(this); 
     767 
     768      setProgress(progress, 990); // estimate: 99% 
     769      if (progress.isCanceled()) System.exit(0); 
     770 
     771      JPanel showPanel = new JPanel(); 
     772      showPanel.setBorder(new TitledBorder("Show")); 
     773      showPanel.setLayout(new BoxLayout(showPanel, BoxLayout.Y_AXIS)); 
     774      showPanel.add(showData); 
     775      showPanel.add(showScale); 
     776      showPanel.add(showBox); 
     777      showPanel.add(showLine); 
     778      showPanel.add(showFit); 
     779      showPanel.add(showResiduals); 
     780 
     781      JPanel scalePanel = new JPanel(); 
     782      scalePanel.setBorder(new TitledBorder("Z Scale Override")); 
     783      scalePanel.setLayout(new BoxLayout(scalePanel, BoxLayout.X_AXIS)); 
     784      scalePanel.add(zOverride); 
     785      scalePanel.add(zScaleValue); 
     786 
     787      JPanel colorPanel = new JPanel(); 
     788      colorPanel.setBorder(new TitledBorder("Color Mapping")); 
     789      colorPanel.setLayout(new BorderLayout()); 
     790      colorPanel.add(colorWidget); 
     791 
     792      JPanel miscRow1 = new JPanel(); 
     793      miscRow1.setLayout(new BoxLayout(miscRow1, BoxLayout.X_AXIS)); 
     794      miscRow1.add(makeRadioPanel("Scale", linear, log)); 
     795      miscRow1.add(makeRadioPanel("Projection", perspective, parallel)); 
     796      miscRow1.add(makeRadioPanel("Data", dataSurface, dataLines)); 
     797 
     798      JPanel miscRow2 = new JPanel(); 
     799      miscRow2.setLayout(new BoxLayout(miscRow2, BoxLayout.X_AXIS)); 
     800      miscRow2.add(makeRadioPanel("Fit", fitSurface, fitLines)); 
     801      miscRow2.add(makeRadioPanel("Residuals", resSurface, resLines)); 
     802      miscRow2.add(makeRadioPanel("Colors", colorHeight, colorTau)); 
     803 
     804      JPanel miscRow3 = new JPanel(); 
     805      miscRow3.setLayout(new BoxLayout(miscRow3, BoxLayout.X_AXIS)); 
     806      miscRow3.add(scalePanel); 
     807      miscRow3.add(Box.createHorizontalStrut(5)); 
     808      miscRow3.add(exportData); 
     809      //miscRow3.add(numCurves); 
     810 
     811      JPanel miscPanel = new JPanel(); 
     812      miscPanel.setLayout(new BoxLayout(miscPanel, BoxLayout.Y_AXIS)); 
     813      miscPanel.add(miscRow1); 
     814      miscPanel.add(miscRow2); 
     815      miscPanel.add(miscRow3); 
     816 
     817      JPanel options = new JPanel(); 
     818      options.setBorder(new EmptyBorder(8, 5, 8, 5)); 
     819      options.setLayout(new BoxLayout(options, BoxLayout.X_AXIS)); 
     820      options.add(colorPanel); 
     821      options.add(showPanel); 
     822      options.add(miscPanel); 
     823      decayPane.add(options, BorderLayout.SOUTH); 
     824      masterPane.add(decayPane, BorderLayout.CENTER); 
     825 
     826      JPanel rightPanel = new JPanel() { 
     827        public Dimension getMaximumSize() { 
     828          Dimension pref = getPreferredSize(); 
     829          Dimension max = super.getMaximumSize(); 
     830          return new Dimension(pref.width, max.height); 
     831        } 
     832      }; 
     833      rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS)); 
     834      rightPanel.add(intensityPane); 
     835      rightPanel.add(console.getWindow().getContentPane()); 
     836      BreakawayPanel breakawayPanel = new BreakawayPanel(masterPane, 
     837        "Intensity Data - " + file.getName(), false); 
     838      breakawayPanel.setEdge(BorderLayout.EAST); 
     839      breakawayPanel.setUpEnabled(false); 
     840      breakawayPanel.setDownEnabled(false); 
     841      breakawayPanel.setContentPane(rightPanel); 
     842 
     843      setProgress(progress, 999); // estimate: 99.9% 
     844      if (progress.isCanceled()) System.exit(0); 
     845 
     846      // show window on screen 
     847      masterWindow.pack(); 
     848      Dimension size = masterWindow.getSize(); 
     849      Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); 
     850      masterWindow.setLocation((screen.width - size.width) / 2, 
     851        (screen.height - size.height) / 2); 
     852      masterWindow.setVisible(true); 
     853    } 
     854    catch (Throwable t) { 
     855      // display stack trace to the user 
     856      ByteArrayOutputStream out = new ByteArrayOutputStream(); 
     857      t.printStackTrace(new PrintStream(out)); 
     858      String stackTrace = new String(out.toByteArray()); 
     859      JOptionPane.showMessageDialog(null, 
     860        "Sorry, Slim Plotter encountered a problem loading your data:\n" + 
     861        stackTrace, "Slim Plotter", JOptionPane.ERROR_MESSAGE); 
     862      System.exit(4); 
     863    } 
     864 
    850865    setProgress(progress, 1000); 
    851866    progress.close(); 
     867 
    852868    plotData(true, true, true); 
    853869 
     
    9931009        JOptionPane.showMessageDialog(exportData, 
    9941010          "There was a problem writing the file: " + exc.getMessage(), 
    995           "SlimPlotter", JOptionPane.ERROR_MESSAGE); 
     1011          "Slim Plotter", JOptionPane.ERROR_MESSAGE); 
    9961012      } 
    9971013    } 
     
    10981114          JOptionPane.showMessageDialog(iPlot.getComponent(), 
    10991115            "Please draw a curve that does not intersect itself.", 
    1100             "SlimPlotter", JOptionPane.ERROR_MESSAGE); 
     1116            "Slim Plotter", JOptionPane.ERROR_MESSAGE); 
    11011117        } 
    11021118        else exc.printStackTrace(); 
     
    11761192        if (numExp == 1) { 
    11771193          params[0] = maxVal; 
    1178           params[1] = 1; 
     1194          params[1] = picoToBins(1000); 
    11791195          params[2] = 0; 
    11801196        } 
    11811197        else if (numExp == 2) { 
    11821198          params[0] = maxVal / 2; 
    1183           params[1] = 0.8f; 
     1199          params[1] = picoToBins(800); 
    11841200          params[2] = 0; 
    11851201          params[0] = maxVal / 2; 
    1186           params[1] = 2; 
     1202          params[1] = picoToBins(2000); 
    11871203          params[2] = 0; 
    11881204        } 
     
    11911207        //  int e = 3 * i; 
    11921208        //  params[e] = (numExp - i) * maxVal / (numExp + 1); 
    1193         //  params[e + 1] = 1; 
     1209        //  params[e + 1] = picoToBins(1000 * (i + 1)); 
    11941210        //  params[e + 2] = 0; 
    11951211        //} 
    11961212        int num = timeBins - maxPeak; 
    11971213 
    1198         // HACK - cut off last 1.5 ns from lifetime histogram, 
     1214        // HACK - cut off last 1500 ps from lifetime histogram, 
    11991215        // to improve accuracy of fit. 
    12001216        if (cutEnd) { 
    1201           int cutBins = (int) (1.5f * timeBins / timeRange); 
     1217          int cutBins = (int) picoToBins(1500); 
    12021218          if (num > cutBins + 5) num -= cutBins; 
    12031219        } 
     
    12251241            int e = 3 * i; 
    12261242            log("\t\ta" + i + "=" + lma.parameters[e]); 
    1227             tau[c][i] = (float) (1 / lma.parameters[e + 1]); 
    1228             log("\t\t" + TAU + i + "=" + tau[c][i]); 
     1243            tau[c][i] = binsToPico((float) (1 / lma.parameters[e + 1])); 
     1244            log("\t\t" + TAU + i + "=" + tau[c][i] + " ps"); 
    12291245            log("\t\tc" + i + "=" + lma.parameters[e + 2]); 
    12301246          } 
     
    13811397  // -- Helper methods -- 
    13821398 
     1399  /** Converts value in picoseconds to histogram bins. */ 
     1400  private float picoToBins(float pico) { 
     1401    return timeBins * pico / timeRange / 1000; 
     1402  } 
     1403 
     1404  /** Converts value in histogram bins to picoseconds. */ 
     1405  private float binsToPico(float bins) { 
     1406    return 1000 * timeRange * bins / timeBins; 
     1407  } 
     1408 
    13831409  private JPanel makeRadioPanel(String title, 
    13841410    JRadioButton b1, JRadioButton b2) 
Note: See TracChangeset for help on using the changeset viewer.