9 added files
java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/ColorScale.java (rev 0)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/ColorScale.java 2014-01-28 22:47:39 UTC (rev 122)
@@ -0,0 +1,182 @@
+package org.hps.monitoring.ecal;
+
+import java.awt.Color;
+
+/**
+ * The abstract class <code>ColorScale</code> contains shared methods for all
+ * types of color scalers.
+ *
+ * @author Kyle McCarty
+ **/
+public abstract class ColorScale {
+ // Indicates if linear or logairthmic scaling should be used.
+ protected boolean linear = true;
+ // The minimum value for color scaling.
+ protected double min = 0;
+ // The maximum value for color scaling.
+ protected double max = 1;
+ // A scale variable used for mapping logarithmic values.
+ protected double scale = 1.0;
+ // An efficiency variable used for logarithmic mapping.
+ protected double lMin = 0.0;
+ // An efficiency variable used for logarithmic mapping.
+ protected double lMax = 1.0;
+
+ /**
+ * <b>setMinimum</b><br/>
+ * <br/>
+ * <code>public void <b>setMinimum</b>(double minimum)</code><br/>
+ * <br/>
+ * Sets the value under which no color scaling will be performed.
+ *
+ * @param minimum
+ * - The lowest value for which color scaling will be performed.
+ **/
+ public void setMinimum(double minimum) {
+ min = minimum;
+ revalidate();
+ }
+
+ /**
+ * <b>setMaximum</b><br/>
+ * <br/>
+ * <code>public void <b>setMaximum</b>(double maximum)</code><br/>
+ * <br/>
+ * Sets the value over which no color scaling will be performed.
+ *
+ * @param maximum
+ * - The highest value for which color scaling will be performed.
+ **/
+ public void setMaximum(double maximum) {
+ max = maximum;
+ revalidate();
+ }
+
+ /**
+ * <b>getMinimum</b><br/>
+ * <br/>
+ * <code>public double <b>getMinimum</b>()</code><br/>
+ * <br/>
+ * Gets the lowest value for which color scaling is performed.
+ *
+ * @return Returns the minimum value for color scaling as a
+ * <code>double</code>.
+ **/
+ public double getMinimum() {
+ return min;
+ }
+
+ /**
+ * <b>getMaximum</b><br/>
+ * <br/>
+ * <code>public double <b>getMaximum</b>()</code><br/>
+ * <br/>
+ * Gets the highest value for which color scaling is performed.
+ *
+ * @return Returns the maximum value for color scaling as a
+ * <code>double</code>.
+ **/
+ public double getMaximum() {
+ return max;
+ }
+
+ /**
+ * <b>setScalingLinear</b><br/>
+ * <br/>
+ * <code>public void <b>setScalingLinear</b>()</code><br/>
+ * <br/>
+ * Sets the scaling behavior to linear.
+ **/
+ public void setScalingLinear() {
+ linear = true;
+ revalidate();
+ }
+
+ /**
+ * <b>isLinearScale</b><br/>
+ * <br/>
+ * <code>public boolean <b>isLinearScale</b>()</code><br/>
+ * <br/>
+ * Indicates whether this color mapping is linear or not.
+ *
+ * @return Returns <code>true</code> if this is a linear mapping and
+ * <code>false</code> otherwise.
+ **/
+ public boolean isLinearScale() {
+ return linear;
+ }
+
+ /**
+ * <b>isLogarithmicScale</b><br/>
+ * <br/>
+ * <code>public boolean <b>isLogarithmicScale</b>()</code><br/>
+ * <br/>
+ * Indicates whether this color mapping is logarithmic or not.
+ *
+ * @return Returns <code>true</code> if this is a logarithmic mapping and
+ * <code>false</code> if it is not.
+ **/
+ public boolean isLogairthmicScale() {
+ return !linear;
+ }
+
+ /**
+ * <b>setScalingLogarithmic</b><br/>
+ * <br/>
+ * <code>public void <b>setScalingLogarithmic</b>()</code><br/>
+ * <br/>
+ * Sets the scaling behavior to logarithmic.
+ **/
+ public void setScalingLogarithmic() {
+ linear = false;
+ revalidate();
+ }
+
+ /**
+ * <b>getColor</b><br/>
+ * <br/>
+ * <code>public Color <b>getColor</b>(double value)</code><br/>
+ * <br/>
+ * Determines the color representing the indicated value.
+ *
+ * @param value
+ * - The value to relate to a color.
+ * @return Returns a <code>Color</code> object associated with the argument
+ * value.
+ **/
+ public abstract Color getColor(double value);
+
+ /**
+ * <b>revalidate</b><br/>
+ * <br/>
+ * <code>protected void <b>revalidate</b>()</code><br/>
+ * <br/>
+ * Makes any necessary changes whenever a critical value is changed.
+ **/
+ protected void revalidate() {
+ // Ensure that the minimum is not zero in the case of log scaling.
+ if (!linear && min == 0) {
+ if (max < 0.01) {
+ min = max / 100.0;
+ } else {
+ min = 0.01;
+ }
+ }
+
+ // We only need to revalidate if we are using a logarithmic scale.
+ if (!linear) {
+ // Determine the scaling variable for logarithmic results.
+ double temp = min;
+ int steps = 0;
+ while (temp < 1) {
+ temp = temp * 10;
+ steps++;
+ }
+ scale = Math.pow(10, steps);
+
+ // Revalidate the logarithmic variables.
+ lMax = Math.log10(scale * max);
+ lMin = Math.log10(scale * min);
+ }
+ }
+}
java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/Datum.java (rev 0)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/Datum.java 2014-01-28 22:47:39 UTC (rev 122)
@@ -0,0 +1,110 @@
+package org.hps.monitoring.ecal;
+
+import java.awt.Point;
+
+/**
+ * The <code>Datum</code> class contains a point representing a crystal in the
+ * calorimeter display panel.
+ *
+ * @author Kyle McCarty
+ **/
+public class Datum {
+ // The coordinate on the calorimeter panel.
+ protected Point loc;
+
+ /**
+ * <b>Datum</b><br/>
+ * <br/>
+ * <code>public <b>Datum</b>()</code><br/>
+ * <br/>
+ * Initializes an empty <code>Datum</code>. Note that it will have an
+ * invalid coordinate.
+ **/
+ public Datum() {
+ this(-1, -1);
+ }
+
+ /**
+ * <b>Datum</b><br/>
+ * <br/>
+ * <code>public <b>Datum</b>(int x, int y)</code><br/>
+ * <br/>
+ * Initializes a new <code>Datum</code> at the indicated coordinate.
+ *
+ * @param x
+ * - The x-coordinate of the object.
+ * @param y
+ * - The y-coordinate of the object.
+ **/
+ public Datum(int x, int y) {
+ loc = new Point(x, y);
+ }
+
+ /**
+ * <b>getX</b><br/>
+ * <br/>
+ * <code>public int <b>getX</b>()</code><br/>
+ * <br/>
+ * Indicates the x-coordinate of the object.
+ *
+ * @return Returns the x-cooridinate as an <code>int</code>.
+ **/
+ public int getX() {
+ return loc.x;
+ }
+
+ /**
+ * <b>getY</b><br/>
+ * <br/>
+ * <code>public int <b>getY</b>()</code><br/>
+ * <br/>
+ * Indicates the y-coordinate of the object.
+ *
+ * @return Returns the y-coordiate as an <code>int</code>.
+ **/
+ public int getY() {
+ return loc.y;
+ }
+
+ /**
+ * <b>getLocation</b><br/>
+ * <br/>
+ * <code>public Point <b>getLocation</b>()</code><br/>
+ * <br/>
+ * Indicates the location of the object.
+ *
+ * @return Returns the object's location as a <code>Point
+ * </code> object.
+ **/
+ public Point getLocation() {
+ return loc;
+ }
+
+ /**
+ * <b>setX</b><br/>
+ * <br/>
+ * <code>public void <b>setX</b>(int x)</code><br/>
+ * <br/>
+ * Sets the object's x-coordinate.
+ *
+ * @param x
+ * - The new x-coordinate.
+ **/
+ public void setX(int x) {
+ loc.x = x;
+ }
+
+ /**
+ * <b>setY</b><br/>
+ * <br/>
+ * <code>public void <b>setY</b>(int y)</code><br/>
+ * <br/>
+ * Sets the obejct's y-coordinate.
+ *
+ * @param y
+ * - The new y-coordinate.
+ **/
+ public void setY(int y) {
+ loc.y = y;
+ }
+}
java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/EcalHit.java (rev 0)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/EcalHit.java 2014-01-28 22:47:39 UTC (rev 122)
@@ -0,0 +1,56 @@
+package org.hps.monitoring.ecal;
+
+/**
+ * The class <code>EcalHit</code> is an extension of <code>Datum
+ * </code> that stores an energy.
+ **/
+public final class EcalHit extends Datum {
+ // The (raw) energy of this hit.
+ private double energy = 0.0;
+
+ /**
+ * <b>EcalHit</b><br/>
+ * <br/>
+ * <code>public <b>EcalHit</b>(int x, int y, double energy)</code><br/>
+ * <br/>
+ * Initializes a calorimeter hit object.
+ *
+ * @param x
+ * - The x-coordinate of the hit.
+ * @param y
+ * - The y-coordinate of the hit.
+ * @param energy
+ * - The raw energy of the hit.
+ **/
+ public EcalHit(int x, int y, double energy) {
+ super(x, y);
+ this.energy = energy;
+ }
+
+ /**
+ * <b>getEnergy</b><br/>
+ * <br/>
+ * <code>public double <b>getEnergy</b>()</code><br/>
+ * <br/>
+ * Indicates the raw energy of this ht.
+ *
+ * @return Returns the raw energy as a <code>double</code>.
+ **/
+ public double getEnergy() {
+ return energy;
+ }
+
+ /**
+ * <b>setEnergy</b><br/>
+ * <br/>
+ * <code>public void <b>setEnergy</b>(double energy)</code><br/>
+ * <br/>
+ * Sets the energy of the hit to the indicated value.
+ *
+ * @param energy
+ * - The new energy of the hit.
+ **/
+ public void setEnergy(double energy) {
+ this.energy = energy;
+ }
+}
java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/EcalPanel.java (rev 0)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/EcalPanel.java 2014-01-28 22:47:39 UTC (rev 122)
@@ -0,0 +1,574 @@
+package org.hps.monitoring.ecal;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.geom.Line2D;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+import javax.swing.JPanel;
+
+/**
+ * The class <code>EcalPanel</code> handles the rendering of the calorimeter
+ * crystals as well as mapping colors to their values, rendering a color scale,
+ * and marking cluster crystals.
+ *
+ * @author Kyle McCarty
+ **/
+public class EcalPanel extends JPanel {
+ // Java-suggested variable.
+ private static final long serialVersionUID = 6292751227464151897L;
+ // The color used for rendering seed hits.
+ private Color clusterColor = Color.GREEN;
+ // The color-mapping scale used by to color calorimeter crystals.
+ private MultiGradientScale scale = MultiGradientScale.makeRainbowScale(0.0,
+ 1.0);
+ // The number of boxes in the x-direction.
+ private int xBoxes = 1;
+ // The number of boxes in the y-direction.
+ private int yBoxes = 1;
+ // The width of the scale.
+ private int scaleWidth = 75;
+ // Whether the scale has changed or not since its last rendering.
+ private boolean scaleChanged = true;
+ // Stores which calorimeter crystals are disabled.
+ private boolean[][] disabled;
+ // Stores the energies in each calorimeter crystal.
+ private double[][] hit;
+ // Stores whether a crystal is the location of a seed hit.
+ private boolean[][] cluster;
+ // Stores whether a crystal has changed.
+ private boolean changed[][];
+ // Stores whether the panel size has chaged.
+ private boolean sizeChanged = true;
+ // The panel on which the scale is rendered.
+ ScalePanel scalePanel = new ScalePanel();
+
+ // Efficiency variables for crystal placement.
+ int boxWidth = 0;
+ int widthRem = 0;
+ int boxHeight = 0;
+ int heightRem = 0;
+
+ /**
+ * <b>EcalPanel</b><br/>
+ * <br/>
+ * Initializes the calorimeter panel.
+ *
+ * @param numXBoxes
+ * - The number of crystals in the x-direction.
+ * @param numYBoxes
+ * - The number of crystals in the y-direction.
+ **/
+ public EcalPanel(int numXBoxes, int numYBoxes) {
+ // Initialize the base component.
+ super();
+
+ // Set the number of calorimeter crystals.
+ xBoxes = numXBoxes;
+ yBoxes = numYBoxes;
+
+ // Initialize the arrays.
+ disabled = new boolean[xBoxes][yBoxes];
+ hit = new double[xBoxes][yBoxes];
+ cluster = new boolean[xBoxes][yBoxes];
+ changed = new boolean[xBoxes][yBoxes];
+
+ // Add the scale panel.
+ setLayout(null);
+ add(scalePanel);
+ sizeChanged = true;
+ scaleChanged = true;
+ }
+
+ /**
+ * <b>setCrystalEnabled</b><br/>
+ * <br/>
+ * <code>public void <b>setCrystalEnabled</b>(int xIndex, int yIndex, boolean active)</code>
+ * <br/>
+ * <br/>
+ * Sets whether the indicated crystal is enabled or not. Invalid indices
+ * will be ignored.
+ *
+ * @param xIndex
+ * - The x-coordinate of the crystal.
+ * @param yIndex
+ * - The y-coordinate of the crystal.
+ * @param active
+ * - This should be <code>true</code> if the crystal is active
+ * and <code>false</code> if it is not.
+ * @throws IndexOutOfBoundsException
+ * Occurs when the given xy crystal coordinate does not point to
+ * a crystal.
+ **/
+ public void setCrystalEnabled(int xIndex, int yIndex, boolean active)
+ throws IndexOutOfBoundsException {
+ if (xIndex >= 0 && xIndex < xBoxes && yIndex >= 0 && yIndex < yBoxes) {
+ disabled[xIndex][yIndex] = !active;
+ changed[xIndex][yIndex] = true;
+ } else {
+ throw new IndexOutOfBoundsException(String.format(
+ "Invalid crystal address (%2d, %2d).", xIndex, yIndex));
+ }
+ }
+
+ /**
+ * <b>addCrystalEnergy</b><br/>
+ * <br/>
+ * <code>public void <b>addCrystalEnergy</b>(int xIndex, int yIndex, double energy)</code>
+ * <br/>
+ * <br/>
+ * Adds the indicated quantity of energy to the crystal at the given
+ * coordinates.
+ *
+ * @param xIndex
+ * - The x-coordinate of the crystal.
+ * @param yIndex
+ * - The y-coordinate of the crystal.
+ * @param energy
+ * - The energy to add.
+ * @throws IndexOutOfBoundsException
+ * Occurs when the given xy crystal coordinate does not point to
+ * a crystal.
+ **/
+ public void addCrystalEnergy(int xIndex, int yIndex, double energy)
+ throws IndexOutOfBoundsException {
+ if (xIndex >= 0 && xIndex < xBoxes && yIndex >= 0 && yIndex < yBoxes) {
+ this.hit[xIndex][yIndex] += energy;
+ changed[xIndex][yIndex] = true;
+ } else {
+ throw new IndexOutOfBoundsException(String.format(
+ "Invalid crystal address (%2d, %2d).", xIndex, yIndex));
+ }
+ }
+
+ /**
+ * <b>setCrystalCluster</b>
+ * <code>public void <b>setCrystalCluster</b>(int xIndex, int yIndex, boolean cluster)</code>
+ * <br/>
+ * <br/>
+ * Sets whether a crystal is also the location of a seed hit.
+ *
+ * @param xIndex
+ * - The x-coordinate of the crystal.
+ * @param yIndex
+ * - The y-coordinate of the crystal.
+ * @param cluster
+ * - This should be <code>true</code> if there is a seed hit and
+ * <code>false</code> if there is not.
+ * @throws IndexOutOfBoundsException
+ * Occurs when the given xy crystal coordinate does not point to
+ * a crystal.
+ **/
+ public void setCrystalCluster(int xIndex, int yIndex, boolean cluster)
+ throws IndexOutOfBoundsException {
+ if (xIndex >= 0 && xIndex < xBoxes && yIndex >= 0 && yIndex < yBoxes) {
+ this.cluster[xIndex][yIndex] = cluster;
+ changed[xIndex][yIndex] = true;
+ } else {
+ throw new IndexOutOfBoundsException(String.format(
+ "Invalid crystal address (%2d, %2d).", xIndex, yIndex));
+ }
+ }
+
+ /**
+ * <b>clearCrystals</b><br/>
+ * <br/>
+ * <code>public void <b>clearCrystals</b>()</code><br/>
+ * <br/>
+ * Sets all crystal energies to zero and removes all clusters. This <b>does
+ * not</b> enable any disabled crystals.
+ **/
+ public void clearCrystals() {
+ for (int x = 0; x < xBoxes; x++) {
+ for (int y = 0; y < yBoxes; y++) {
+ if (hit[x][y] != 0.0) {
+ hit[x][y] = 0.0;
+ changed[x][y] = true;
+ }
+ if (cluster[x][y]) {
+ cluster[x][y] = false;
+ changed[x][y] = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * <b>setClusterColor</b><br/>
+ * <br/>
+ * <code>public void <b>setClusterColor</b>(Color c)</code><br/>
+ * <br/>
+ * Sets the color of the seed hit marker.
+ *
+ * @param c
+ * - The color to be used for seed hit markers. A value of
+ * <code>null</code> will result in seed hit markers being the
+ * inverse color of the crystal in which they appear.
+ **/
+ public void setClusterColor(Color c) {
+ clusterColor = c;
+ }
+
+ /**
+ * <b>setMinimum</b><br/>
+ * <br>
+ * <code>public void <b>setMinimum</b>(double minimum)</code><br/>
+ * <br/>
+ * Sets the minimum value of the color mapping scale. Energies below this
+ * value will all be the same minimum color.
+ *
+ * @param minimum
+ * - The minimum energy to be mapped.
+ **/
+ public void setMinimum(double minimum) {
+ scale.setMinimum(minimum);
+ scaleChanged = true;
+ }
+
+ /**
+ * <b>setMaximum</b><br/>
+ * <br/>
+ * <code>public void <b>setMaximum</b>(double maximum)</code><br/>
+ * <br/>
+ * Sets the maximum value of the color mapping scale. Energies above this
+ * value will all be the same maximum color.
+ *
+ * @param maximum
+ * - The maximum energy to be mapped.
+ **/
+ public void setMaximum(double maximum) {
+ scale.setMaximum(maximum);
+ scaleChanged = true;
+ }
+
+ /**
+ * <b>setScalingLinear</b><br/>
+ * <br/>
+ * <code>public void <b>setScalingLinear</b>()<br/><br/>
+ * Sets the color mapping scale behavior to linear mapping.
+ **/
+ public void setScalingLinear() {
+ scale.setScalingLinear();
+ scaleChanged = true;
+ }
+
+ /**
+ * <b>setScalingLogarithmic</b><br/>
+ * <br/>
+ * <code>public void <b>setScalingLogarithmic</b></code><br/>
+ * <br/>
+ * Sets the color mapping scale behavior to logarithmic mapping.
+ **/
+ public void setScalingLogarithmic() {
+ scale.setScalingLogarithmic();
+ scaleChanged = true;
+ }
+
+ /**
+ * <b>setScaleEnabled</b><br/>
+ * <br/>
+ * <code>public void <b>setScaleEnabled</b>(boolean enabled)</code><br/>
+ * <br/>
+ * Sets whether the scale should be visible or not.
+ *
+ * @param enabled
+ * - <code>true</code> indicates that the scale should be visible
+ * and <code>false</code> that it should be hidden.
+ **/
+ public void setScaleEnabled(boolean enabled) {
+ if (scalePanel.isVisible() != enabled) {
+ scalePanel.setVisible(enabled);
+ scaleChanged = true;
+ sizeChanged = true;
+ }
+ }
+
+ /**
+ * <b>redraw</b><br/>
+ * <br/>
+ * <code>public void <b>redraw</b>()</code> Re-renders the calorimeter
+ * panel.
+ **/
+ public void redraw() {
+ super.repaint();
+ }
+
+ public void setSize(Dimension d) {
+ setSize(d.width, d.height);
+ }
+
+ public void setSize(int width, int height) {
+ super.setSize(width, height);
+ scalePanel.setLocation(width - scaleWidth, 0);
+ scalePanel.setSize(scaleWidth, height);
+ sizeChanged = true;
+ }
+
+ protected void paintComponent(Graphics g) {
+ if (sizeChanged) {
+ // Determine the width and heights of the calorimeter crystals.
+ int width;
+ if (scalePanel.isVisible()) {
+ width = getWidth() - scaleWidth;
+ } else {
+ width = getWidth();
+ }
+ int height = getHeight();
+
+ boxWidth = width / xBoxes;
+ widthRem = width % xBoxes;
+ boxHeight = height / yBoxes;
+ heightRem = height % yBoxes;
+ }
+ int heightRemReset = heightRem;
+ int widthRemReset = widthRem;
+
+ // Start drawing the calorimeter crystals. To avoid having empty
+ // space, we distribute the extra widthRem pixels to the boxes at
+ // a rate of one pixel for box until we run out. We do the same thing
+ // for the heightRem.
+ int curX = 0;
+ int curY = 0;
+ for (int x = 0; x < xBoxes; x++) {
+ // Determine if this column should use an extra pixel.
+ int tw = boxWidth;
+ if (widthRem != 0) {
+ tw++;
+ widthRem--;
+ }
+ for (int y = 0; y < yBoxes; y++) {
+ // Determine if this row should use an extra pixel.
+ int th = boxHeight;
+ if (heightRem != 0) {
+ th++;
+ heightRem--;
+ }
+
+ if (sizeChanged || scaleChanged || changed[x][y]) {
+ // Determine the appropriate color for the box.
+ Color crystalColor;
+ if (disabled[x][y]) {
+ crystalColor = Color.BLACK;
+ } else {
+ crystalColor = scale.getColor(hit[x][y]);
+ }
+ g.setColor(crystalColor);
+
+ // Draw the box.
+ g.fillRect(curX, curY, tw, th);
+ g.setColor(Color.BLACK);
+ g.drawRect(curX, curY, tw, th);
+
+ // If there is a cluster, draw an x.
+ if (cluster[x][y]) {
+ // Get the correct coordinates.
+ double ltw = (0.3 * tw) / 2;
+ double lth = (0.5 * th) / 2;
+ double[] lx = { curX + ltw, curX + tw - ltw };
+ double[] ly = { curY + lth, curY + th - lth };
+
+ // Get the appropriate cluster color.
+ Color c;
+ if (clusterColor == null) {
+ int red = Math.abs(255 - crystalColor.getRed());
+ int blue = Math.abs(255 - crystalColor.getBlue());
+ int green = Math.abs(255 - crystalColor.getGreen());
+ c = new Color(red, green, blue);
+ } else {
+ c = clusterColor;
+ }
+
+ // Draw an x on the cluster crystal.
+ Graphics2D g2 = (Graphics2D) g;
+ g2.setColor(c);
+ // g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ // RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setStroke(new BasicStroke(2));
+ g2.draw(new Line2D.Double(lx[0], ly[0], lx[1], ly[1]));
+ g2.draw(new Line2D.Double(lx[0], ly[1], lx[1], ly[0]));
+ // g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ // RenderingHints.VALUE_ANTIALIAS_OFF);
+ }
+
+ // Note that this crystals has been updated.
+ changed[x][y] = false;
+ }
+
+ // Increment the current y position.
+ curY += th;
+ }
+
+ // Increment the current x position.
+ curX += tw;
+
+ // Reset the current y position and heightRem.
+ curY = 0;
+ heightRem = heightRemReset;
+ }
+
+ // If the scale has changed, redraw the scale panel as well.
+ if (scaleChanged && scalePanel.isVisible()) {
+ scalePanel.redraw();
+ }
+
+ // Indicate that the any size changes have been handled.
+ scaleChanged = false;
+ sizeChanged = false;
+
+ // Reset the height and width remainder variables.
+ heightRem = heightRemReset;
+ widthRem = widthRemReset;
+ }
+
+ /**
+ * The local class <b>ScalePanel</b> renders the scale for the calorimeter
+ * color map.
+ **/
+ private class ScalePanel extends JPanel {
+ /**
+ * <b>redraw</b><br/>
+ * <br/>
+ * <code>public void <b>redraw</b>()</code><br/>
+ * <br/>
+ * Orders the scale to re-render itself.
+ **/
+ public void redraw() {
+ super.repaint();
+ }
+
+ protected void paintComponent(Graphics g) {
+ // Set the text region width.
+ int textWidth = 45;
+ boolean useText;
+
+ // Store height and width.
+ int height = getHeight();
+ int width;
+ if (getWidth() > textWidth) {
+ width = getWidth() - textWidth;
+ useText = true;
+ } else {
+ width = getWidth();
+ useText = false;
+ }
+
+ // Define the step size for the scale. This will differ depending
+ // on whether we employ a linear or logarithmic scale.
+ double step;
+ double curValue;
+ boolean linear = scale.isLinearScale();
+ if (linear) {
+ step = (scale.getMaximum() - scale.getMinimum()) / height;
+ curValue = scale.getMinimum();
+ } else {
+ double max = Math.log10(scale.getMaximum());
+ double min = Math.log10(scale.getMinimum());
+ step = (max - min) / height;
+ curValue = min;
+ }
+
+ // Color the text area.
+ g.setColor(Color.BLACK);
+ g.drawRect(0, 0, width, height);
+ g.drawRect(1, 1, width - 1, height - 1);
+ g.fillRect(width, 0, textWidth, height);
+
+ // Render the scale.
+ int sy = height;
+ int[] sx = { 0, width };
+ for (int i = 0; i <= height; i++) {
+ // Get the appropriate value for the current pixel.
+ double scaledValue;
+ if (linear) {
+ scaledValue = curValue;
+ } else {
+ scaledValue = Math.pow(10, curValue);
+ }
+ g.setColor(scale.getColor(scaledValue));
+
+ // Draw a line.
+ g.drawLine(sx[0], sy, sx[1], sy);
+
+ // Update the spacing variables.
+ curValue += step;
+ sy--;
+ }
+
+ // Generate the scale text.
+ if (useText) {
+ // Determine the spacing of the text.
+ FontMetrics fm = g.getFontMetrics(g.getFont());
+ int fontHeight = fm.getHeight();
+ double fStep = (height - 2.0 * fontHeight) / fontHeight;
+ double halfStep = fStep / 2.0;
+
+ // Get the scaling value.
+ double fScale;
+ double fMin;
+ if (linear) {
+ fScale = scale.getMaximum() - scale.getMinimum();
+ fMin = scale.getMinimum();
+ } else {
+ fScale = Math.log10(scale.getMaximum())
+ - Math.log10(scale.getMinimum());
+ fMin = Math.log10(scale.getMinimum());
+ }
+
+ // Populate the first and last values.
+ NumberFormat nf = new DecimalFormat("0.#E0");
+ g.setColor(Color.WHITE);
+ g.drawString(nf.format(scale.getMaximum()), width + 5,
+ fontHeight);
+ g.drawString(nf.format(scale.getMinimum()), width + 5,
+ height - 3);
+
+ // Calculate text placement variables.
+ double heightAvailable = height - 2.0 * fontHeight;
+ double heightDefault = heightAvailable / (1.5 * fontHeight);
+ int num = (int) Math.floor(heightAvailable / heightDefault);
+ double heightRemainder = heightAvailable
+ - (num * heightDefault);
+ double heightExtra = heightRemainder / num;
+ double lSpacing = heightDefault + heightExtra;
+ double lHalfSpacing = lSpacing / 2.0;
+ int lHeight = fontHeight + 3;
+ int[] lX = { width - 4, width, width + 5 };
+ int lShift = (int) (fontHeight * 0.25 + lHalfSpacing);
+ double lTemp = 0.0;
+
+ // Calculate value conversion variables.
+ double lMin = scale.getMinimum();
+ double lScale;
+ if (linear) {
+ lMin = scale.getMinimum();
+ lScale = scale.getMaximum() - scale.getMinimum();
+ } else {
+ double min = Math.log10(scale.getMinimum());
+ double max = Math.log10(scale.getMaximum());
+ lMin = min;
+ lScale = max - min;
+ }
+
+ // Write the labels.
+ for (int i = 0; i < num; i++) {
+ g.setColor(Color.BLACK);
+ int h = (int) (lHeight + lHalfSpacing);
+ g.drawLine(lX[0], h, lX[1], h);
+ g.setColor(Color.WHITE);
+ double lVal = lMin + (1.0 - ((double) h / height)) * lScale;
+ if (!linear) {
+ lVal = Math.pow(10, lVal);
+ }
+ g.drawString(nf.format(lVal), lX[2], lHeight + lShift);
+ lTemp += lSpacing;
+ lHeight = (int) (fontHeight + lTemp);
+ }
+ }
+ }
+ }
+}
java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/EventManager.java (rev 0)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/EventManager.java 2014-01-28 22:47:39 UTC (rev 122)
@@ -0,0 +1,152 @@
+package org.hps.monitoring.ecal;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+/**
+ * The class <code>EventManager</code> handles loading hits and clusters from a
+ * text file to populate the calorimeter panel.
+ *
+ * @author Kyle McCarty
+ **/
+public class EventManager {
+ // File readers for reading the input.
+ private FileReader fr;
+ private BufferedReader reader;
+ // List for storing the hits from the current event.
+ private ArrayList<EcalHit> hitList = new ArrayList<EcalHit>();
+ // List for storing the clusters from the current hit.
+ private ArrayList<Datum> clusterList = new ArrayList<Datum>();
+ // Whether the event manager has an open file.
+ private boolean open = true;
+
+ /**
+ * <b>EventManager</b><br/>
+ * <br/>
+ * <code>public <b>EventManager</b>(String filename)</code><br/>
+ * <br/>
+ * Initializes an event manager that will read from the indicated file.
+ *
+ * @param filename
+ * - The path to the file containing hit information.
+ **/
+ public EventManager(String filename) throws IOException {
+ fr = new FileReader(filename);
+ reader = new BufferedReader(fr);
+ }
+
+ /**
+ * <b>readEvent</b><br/>
+ * <br/>
+ * <code>public boolean <b>readEvent</b>()</code><br/>
+ * <br/>
+ * Populates the event manager with hits and clusters from the next event.
+ *
+ * @return Returns <code>true</code> if an event was read and
+ * <code>false</code> if it was not.
+ **/
+ public boolean readEvent() throws IOException {
+ // We can only read of the reader is open.
+ if (!open) {
+ return false;
+ }
+
+ // Clear the data lists.
+ hitList.clear();
+ clusterList.clear();
+
+ // Store the current line.
+ String curLine = reader.readLine();
+
+ // Keep sorting until we hit a null or an event header.
+ while (curLine != null && curLine.compareTo("Event") != 0) {
+ curLine = reader.readLine();
+ }
+
+ // If we hit a null, we are at the end of the file.
+ if (curLine == null) {
+ return false;
+ }
+
+ // Otherwise, we have read an event header and must populate
+ // the data lists.
+ curLine = reader.readLine();
+ while (curLine != null && curLine.compareTo("Event") != 0) {
+ // Break apart the line.
+ StringTokenizer st = new StringTokenizer(curLine);
+ String name = st.nextToken();
+ int ix = Integer.parseInt(st.nextToken());
+ int iy = Integer.parseInt(st.nextToken());
+
+ // Convert it to an object.
+ if (name.compareTo("Cluster") == 0) {
+ clusterList.add(new Datum(ix, iy));
+ } else if (name.compareTo("EcalHit") == 0) {
+ double energy = Double.parseDouble(st.nextToken());
+ hitList.add(new EcalHit(ix, iy, energy));
+ }
+
+ // Get the next line.
+ curLine = reader.readLine();
+ }
+
+ // Indicate that an event was processed.
+ return true;
+ }
+
+ /**
+ * <b>close</b><br/>
+ * <br/>
+ * <code>public void <b>close</b>()</code><br/>
+ * <br/>
+ * Closes the event manager. Once this is performed, no additional events
+ * may be read.
+ *
+ * @throws IOException
+ * Occurs if there is an error closing the file stream.
+ **/
+ public void close() throws IOException {
+ reader.close();
+ fr.close();
+ open = false;
+ }
+
+ /**
+ * <b>getHits</b><br/>
+ * <br/>
+ * <code>public ArrayList<EcalHit> <b>getHits</b>()</code><br/>
+ * <br/>
+ * Allows access to the current event's list of hits.
+ *
+ * @return Returns the current hits as an <code>ArrayList
+ * </code> object.
+ **/
+ public ArrayList<EcalHit> getHits() {
+ if (!open) {
+ return null;
+ } else {
+ return hitList;
+ }
+ }
+
+ /**
+ * <b>getClusters</b><br/>
+ * <br/>
+ * <code>public ArrayList<Datum> <b>getClusters</b></code><br/>
+ * <br/>
+ * Allows access to the current event's list of clusters.
+ *
+ * @return Returns the current clusters as an <code>ArrayList
+ * </code> object.
+ **/
+ public ArrayList<Datum> getClusters() {
+ if (!open) {
+ return null;
+ } else {
+ return clusterList;
+ }
+ }
+}
java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/GradientScale.java (rev 0)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/GradientScale.java 2014-01-28 22:47:39 UTC (rev 122)
@@ -0,0 +1,147 @@
+package org.hps.monitoring.ecal;
+
+import java.awt.Color;
+
+/**
+ * The class <code>GradientScale</code> is an implementation of the abstract
+ * class <code>ColorScale</code> which represents a simple gradient from one
+ * color to another. It will map any argument value that exceeds its maximum
+ * value to the hot color and any argument value that is below its minimum value
+ * to its cold color. All other argument values will be mapped somewhere between
+ * the cold and hot colors using either a linear or logarithmic scale.
+ *
+ * @author Kyle McCarty
+ **/
+public final class GradientScale extends ColorScale {
+ // The color associated with the maximum value.
+ private Color hotColor = Color.WHITE;
+ // The color associated with the minimum value.
+ private Color coldColor = Color.BLACK;
+ // Efficiency variable holding the rgb difference between the two
+ // colors. This is used to prevent recalculation when mapping values.
+ private int[] drgb = { 255, 255, 255 };
+
+ /**
+ * <b>setHotColor</b><br/>
+ * <br/>
+ * <code>public void <b>setHotColor</b>(Color c)</code><br/>
+ * <br/>
+ * Sets the color associated with the maximum value.
+ *
+ * @param c
+ * - The new color to use.
+ **/
+ public void setHotColor(Color c) {
+ hotColor = c;
+ revalidateColor();
+ }
+
+ /**
+ * <b>setColdColor</b><br/>
+ * <br/>
+ * <code>public void <b>setColdColor</b>(Color c)</code><br/>
+ * <br/>
+ * Sets the color assocaited with the minimum value.
+ *
+ * @param c
+ * - The color to use.
+ **/
+ public void setColdColor(Color c) {
+ coldColor = c;
+ revalidateColor();
+ }
+
+ public Color getColor(double value) {
+ // If the value is less than the minimum, return the cold color.
+ if (value < min) {
+ return coldColor;
+ }
+
+ // If the value is greater than the maximum, return the hot color.
+ if (value > max) {
+ return hotColor;
+ }
+
+ // Otherwise, calculate how far along the gradient the value is.
+ double percent;
+ if (linear) {
+ percent = (value - min) / (max - min);
+ } else {
+ double lValue = Math.log10(scale * value);
+ percent = (lValue - lMin) / (lMax - lMin);
+ }
+
+ // Scale the color.
+ int dr = (int) Math.round(percent * drgb[0]);
+ int dg = (int) Math.round(percent * drgb[1]);
+ int db = (int) Math.round(percent * drgb[2]);
+
+ // Return the result.
+ return new Color(coldColor.getRed() + dr, coldColor.getGreen() + dg,
+ coldColor.getBlue() + db);
+ }
+
+ /**
+ * <b>revalidateColor</b><br/>
+ * <br/>
+ * <code>private void <b>revalidateColor</b>()</code><br/>
+ * <br/>
+ * Calculates the differences between the hot and cold colors and sets the
+ * class related class variables.
+ **/
+ private void revalidateColor() {
+ drgb[0] = hotColor.getRed() - coldColor.getRed();
+ drgb[1] = hotColor.getGreen() - coldColor.getGreen();
+ drgb[2] = hotColor.getBlue() - coldColor.getBlue();
+ }
+
+ /**
+ * <b>makeGreyScale</b><br/>
+ * <br/>
+ * <code>public static GradientScale <b>makeGreyScale</b>(double minimum, double maximum)</code>
+ * <br/>
+ * <br/>
+ * Creates a color scale that ranges from black (cold) to white (hot) with
+ * the indicated maximum and minimum.
+ *
+ * @param minimum
+ * - The lowest value for color scaling.
+ * @param maximum
+ * - The highest value for color scaling.
+ * @return Returns a <code>GradientScale</code> that maps to grey scale over
+ * the indicated range.
+ **/
+ public static GradientScale makeGreyScale(double minimum, double maximum) {
+ GradientScale gs = new GradientScale();
+ gs.setMinimum(minimum);
+ gs.setMaximum(maximum);
+
+ return gs;
+ }
+
+ /**
+ * <b>makeHeatScale</b><br/>
+ * <br>
+ * <code>public static GradientScale <b>makeHeatScale</b>(double minimum, double maximum)</code>
+ * <br/>
+ * <br/>
+ * Creates a color scale that ranges from black (cold) to red (hot) with the
+ * indicated maximum and minimum.
+ *
+ * @param minimum
+ * - The lowest value for color scaling.
+ * @param maximum
+ * - The highest value for color scaling.
+ * @return Returns a <code>GradientScale</code> that maps to a black- to-red
+ * gradient over the indicated range.
+ **/
+ public static GradientScale makeHeatScale(double minimum, double maximum) {
+ GradientScale hs = new GradientScale();
+ hs.setHotColor(Color.RED);
+ hs.setColdColor(Color.BLACK);
+ hs.setMinimum(minimum);
+ hs.setMaximum(maximum);
+
+ return hs;
+ }
+}
java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/Main.java (rev 0)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/Main.java 2014-01-28 22:47:39 UTC (rev 122)
@@ -0,0 +1,78 @@
+package org.hps.monitoring.ecal;
+
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Random;
+
+public class Main {
+ private static final Viewer window = new Viewer();
+
+ public static void main(String[] args) throws IOException {
+ // Get screen size of primary monitor
+ GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getDefaultScreenDevice();
+ int screenWidth = gd.getDisplayMode().getWidth();
+ int screenHeight = gd.getDisplayMode().getHeight();
+
+ // Set the viewer location and make it visible
+ window.setLocation((screenWidth - window.getPreferredSize().width) / 2,
+ (screenHeight - window.getPreferredSize().height) / 2);
+ window.setDataSource("cluster-hit.txt");
+ window.displayNextEvent();
+ window.setVisible(true);
+
+ // makeData();
+ }
+
+ static void makeData() {
+ // Generate a random test input file.
+ Random rng = new Random();
+ try {
+ // Make a file writer to write the results.
+ FileWriter writer = new FileWriter("cluster-hit.txt");
+
+ // Make 10 - 100 events.
+ int events = 10 + rng.nextInt(91);
+
+ // For each events, generate some data.
+ for (int e = 0; e < events; e++) {
+ // Write the event header.
+ writer.append("Event\n");
+
+ // Make 3 - 15 hits.
+ int hits = 3 + rng.nextInt(13);
+ for (int h = 0; h < hits; h++) {
+ // Write identifier.
+ writer.append("EcalHit\t");
+
+ // Make a random address.
+ // x = [0, 46); y = [0, 11)
+ int ix = rng.nextInt(46);
+ int iy = rng.nextInt(11);
+ writer.append(ix + "\t" + iy + "\n");
+ }
+
+ // Make 0 - 4 clusters.
+ int clusters = rng.nextInt(5);
+ for (int c = 0; c < clusters; c++) {
+ // Write identifier.
+ writer.append("Cluster\t");
+
+ // Make a random address.
+ // x = [0, 46); y = [0, 11)
+ int ix = rng.nextInt(46);
+ int iy = rng.nextInt(11);
+ writer.append(ix + "\t" + iy + "\n");
+ }
+ }
+
+ // Close the writer.
+ writer.close();
+ } catch (IOException e) {
+ System.err.println(e.getStackTrace());
+ System.exit(1);
+ }
+ }
+}
java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/MultiGradientScale.java (rev 0)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/MultiGradientScale.java 2014-01-28 22:47:39 UTC (rev 122)
@@ -0,0 +1,172 @@
+package org.hps.monitoring.ecal;
+
+import java.awt.Color;
+import java.util.ArrayList;
+
+/**
+ * The class <code>MultiGradientScale</code> is an implementation of
+ * <code>ColorScale</code> that maps values to a color over several different
+ * individual <code>GradientScale</code> objects to allow for multi-color
+ * mapping.
+ *
+ * @author Kyle McCarty
+ **/
+public final class MultiGradientScale extends ColorScale {
+ // Stores the colors in the map.
+ private ArrayList<Color> colorList = new ArrayList<Color>();
+ // Stores the component mapping scales.
+ private ArrayList<GradientScale> scaleList = new ArrayList<GradientScale>();
+
+ /**
+ * <b>addColor</b><br/>
+ * <br/>
+ * <code>public void <b>addColor</b>(Color c)</code><br/>
+ * <br/>
+ * Adds a new color to the mapping scale. The first color will be the
+ * coldest with subsequent colors being more and more hot.
+ *
+ * @param c
+ * - The color to add.
+ **/
+ public void addColor(Color c) {
+ colorList.add(c);
+ revalidate();
+ }
+
+ /**
+ * <b>removeColor</b><br/>
+ * <br/>
+ * <code>public boolean <b>removeColor</b>(int colorIndex)</code><br/>
+ * <br/>
+ * Removes the nth color from the mapping scale.
+ *
+ * @param colorIndex
+ * - The index of the color to be removed.
+ * @return Returns <code>true</code> if the color was removed and
+ * <code>false</code> if it was not.
+ **/
+ public boolean removeColor(int colorIndex) {
+ // Only remove the value if the index is valid.
+ if (colorIndex >= 0 && colorIndex < colorList.size()) {
+ colorList.remove(colorIndex);
+ revalidate();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public Color getColor(double value) {
+ // Get the number of colors and scales.
+ int colors = colorList.size();
+ int scales = scaleList.size();
+
+ // If there are no colors or scales, give black.
+ if (colors == 0 && scales == 0) {
+ return Color.BLACK;
+ }
+
+ // If there are no scales, but there is a color, give that.
+ if (scales == 0 && colors == 1) {
+ return colorList.get(0);
+ }
+
+ // Scale the value if logarithmic.
+ double sValue;
+ if (linear) {
+ sValue = value;
+ } else {
+ sValue = Math.log10(scale * value);
+ }
+
+ // Otherwise, determine which scale should get the value.
+ for (GradientScale s : scaleList) {
+ if (sValue < s.getMaximum()) {
+ return s.getColor(sValue);
+ }
+ }
+
+ // If it didn'tappear in the list, it is the hottest color.
+ return colorList.get(colors - 1);
+ }
+
+ protected void revalidate() {
+ // Handle the default logarithmic revalidation.
+ super.revalidate();
+
+ // Redistribute the lists.
+ scaleList.clear();
+
+ // We need at least colors to make a scale - otherwise, the
+ // special cases handle the color.
+ int colors = colorList.size();
+ if (colors < 2) {
+ return;
+ }
+
+ // Otherwise, define the list variables.
+ double sStep;
+ double sMin;
+ if (linear) {
+ sStep = (max - min) / (colors - 1);
+ sMin = min;
+ } else {
+ sStep = (lMax - lMin) / (colors - 1);
+ sMin = lMin;
+ }
+ double sMax = sMin + sStep;
+
+ // Generate a list of scales.
+ for (int i = 0; i < (colors - 1); i++) {
+ // Make and add a scale.
+ GradientScale s = new GradientScale();
+ s.setMinimum(sMin);
+ s.setMaximum(sMax);
+ s.setColdColor(colorList.get(i));
+ s.setHotColor(colorList.get(i + 1));
+ scaleList.add(s);
+
+ // Update the min/max.
+ sMin = sMax;
+ sMax += sStep;
+ }
+ }
+
+ /**
+ * <b>makeRainboowScale</b><br/>
+ * <br/>
+ * <code>public static <b>makeRainbowScale</b>(double minimum, double maximum)</code>
+ * <br/>
+ * <br>
+ * Creates a <code>MultiGradientScale</code> that maps values from purple,
+ * to blue, to cyan, to green, to yellow, and to red at the hottest.
+ *
+ * @param minimum
+ * - The lowet mapped value.
+ * @param maximum
+ * - The highest mapped value.
+ * @return Returns the rainbow color mapping scale.
+ **/
+ public static MultiGradientScale makeRainbowScale(double minimum,
+ double maximum) {
+ int str = 165;
+ Color purple = new Color(55, 0, 55);
+ Color blue = new Color(0, 0, str);
+ Color cyan = new Color(0, str, str);
+ Color green = new Color(0, str, 0);
+ Color yellow = new Color(str, str, 0);
+ Color red = new Color(str, 0, 0);
+
+ MultiGradientScale mgs = new MultiGradientScale();
+ mgs.addColor(purple);
+ mgs.addColor(blue);
+ mgs.addColor(cyan);
+ mgs.addColor(green);
+ mgs.addColor(yellow);
+ mgs.addColor(red);
+ mgs.setMinimum(minimum);
+ mgs.setMaximum(maximum);
+
+ return mgs;
+ }
+}
java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/Viewer.java (rev 0)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/ecal/Viewer.java 2014-01-28 22:47:39 UTC (rev 122)
@@ -0,0 +1,223 @@
+package org.hps.monitoring.ecal;
+
+import java.awt.Dimension;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.io.IOException;
+
+import javax.swing.JFrame;
+
+/**
+ * The class <code>Viewer</code> handles initialization of the calorimeter panel
+ * with the proper settings, provides a window for it to live in, and feeds it
+ * events.
+ *
+ * @author Kyle McCarty
+ **/
+public class Viewer extends JFrame {
+ // Java-suggested variable.
+ private static final long serialVersionUID = -2022819652687941812L;
+ // The calorimeter panel.
+ private static final EcalPanel ecalPanel = new EcalPanel(46, 11);
+ // The event data reader.
+ private EventManager em = null;
+
+ /**
+ * <b>Viewer</b><br/>
+ * <br/>
+ * <code>public <b>Viewer</b>()</code><br/>
+ * <br/>
+ * Initializes the viewer window and calorimeter panel.
+ **/
+ public Viewer() {
+ // Initialize the viewer window
+ super();
+ setTitle("HPS Ecal Cluster Viewer");
+ setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+ setPreferredSize(new Dimension(1060, 600));
+ setMinimumSize(new Dimension(1060, 400));
+ setLayout(null);
+
+ // Set the scaling settings.
+ ecalPanel.setMinimum(0.001);
+ ecalPanel.setMaximum(3000);
+ ecalPanel.setScalingLogarithmic();
+
+ // Disable the crystals in the ecal panel along the beam gap.
+ for (int i = -23; i < 24; i++) {
+ ecalPanel.setCrystalEnabled(getPanelX(i), 5, false);
+ if (i > -11 && i < -1) {
+ ecalPanel.setCrystalEnabled(getPanelX(i), 4, false);
+ ecalPanel.setCrystalEnabled(getPanelX(i), 6, false);
+ }
+ }
+
+ // Make a key listener to change events.
+ addKeyListener(new EcalListener());
+
+ // Add the ecal pane
+ add(ecalPanel);
+
+ // Add a listener to update everything when the window changes size
+ addComponentListener(new ResizeListener());
+ }
+
+ public void setSize(int width, int height) {
+ super.setSize(width, height);
+ resize();
+ }
+
+ public void setSize(Dimension d) {
+ setSize(d.width, d.height);
+ }
+
+ /**
+ * <b>setDataSouce</b><br/>
+ * <br/>
+ * <code>public void <b>setDataSource</b>(String filepath)</code><br/>
+ * <br/>
+ * Sets the viewer to read from the indicated data source.
+ *
+ * @param filepath
+ * - The full path to the desired data file.
+ * @throws IOException
+ * Occurs when there is an error opening the data file.
+ **/
+ public void setDataSource(String filepath) throws IOException {
+ em = new EventManager(filepath);
+ }
+
+ /**
+ * <b>displayNextEvent</b><br/>
+ * <br/>
+ * <code>public void <b>displayNextEvent</b>()</code><br/>
+ * <br/>
+ * Feeds the calorimeter panel the data from the next event.
+ *
+ * @throws IOException
+ * Occurs when there is an issue with reading the data file.
+ **/
+ public void displayNextEvent() throws IOException {
+ // Clear the ecal panel.
+ ecalPanel.clearCrystals();
+
+ // If there is no data source, we can not do anything.
+ if (em == null) {
+ return;
+ }
+
+ // Otherwise, get the next event.
+ em.readEvent();
+
+ // Display it.
+ for (EcalHit h : em.getHits()) {
+ int ix = getPanelX(h.getX());
+ int iy = getPanelY(h.getY());
+ ecalPanel.addCrystalEnergy(ix, iy, h.getEnergy());
+ }
+ for (Datum d : em.getClusters()) {
+ int ix = getPanelX(d.getX());
+ int iy = getPanelY(d.getY());
+ ecalPanel.setCrystalCluster(ix, iy, true);
+ }
+
+ // Redraw the ecal panel.
+ ecalPanel.redraw();
+ }
+
+ /**
+ * <b>resize</b><br/>
+ * <br/>
+ * <code>private void <b>resize</b>()</code><br/>
+ * <br/>
+ * Handles proper resizing of the window and its components.
+ **/
+ private void resize() {
+ // Size and position the calorimeter display
+ ecalPanel.setLocation(0, 0);
+ ecalPanel.setSize(getContentPane().getSize());
+ }
+
+ /**
+ * <b>getPanelX</b><br/>
+ * <br/>
+ * <code>private int <b>getPanelX</b>(int ecalX)</code><br/>
+ * <br/>
+ * Converts the lcsim x-coordinate to the calorimeter panel's coordinate
+ * system.
+ *
+ * @param ecalX
+ * - An lcsim calorimeter x-coordinate.
+ * @return Returns the x-coordinate in the calorimeter panel's coordinate
+ * system as an <code>int</code>.
+ **/
+ private int getPanelX(int ecalX) {
+ if (ecalX <= 0) {
+ return ecalX + 23;
+ } else {
+ return ecalX + 22;
+ }
+ }
+
+ /**
+ * <b>getPanelY</b><br/>
+ * <br/>
+ * <code>private int <b>getPanelY</b>(int ecalY)</code><br/>
+ * <br/>
+ * Converts the lcsim y-coordinate to the calorimeter panel's coordinate
+ * system.
+ *
+ * @param ecalY
+ * - An lcsim calorimeter y-coordinate.
+ * @return Returns the y-coordinate in the calorimeter panel's coordinate
+ * system as an <code>int</code>.
+ **/
+ private int getPanelY(int ecalY) {
+ return 5 - ecalY;
+ }
+
+ /**
+ * The <code>EcalListener</code> class binds the enter key to the
+ * <code>displayNextEvent</code> method.
+ **/
+ private class EcalListener implements KeyListener {
+ public void keyPressed(KeyEvent e) {
+ }
+
+ public void keyReleased(KeyEvent e) {
+ // If enter was pressed, go to the next event.
+ if (e.getKeyCode() == 10) {
+ try {
+ displayNextEvent();
+ } catch (IOException ex) {
+ System.err.println(ex.getMessage());
+ System.exit(1);
+ }
+ }
+ }
+
+ public void keyTyped(KeyEvent e) {
+ }
+ }
+
+ /**
+ * The <code>ResizeListener</code> class ensures that the components remain
+ * at the correct size and location when the window is resized.
+ **/
+ private class ResizeListener implements ComponentListener {
+ public void componentResized(ComponentEvent e) {
+ resize();
+ }
+
+ public void componentHidden(ComponentEvent e) {
+ }
+
+ public void componentMoved(ComponentEvent e) {
+ }
+
+ public void componentShown(ComponentEvent e) {
+ }
+ }
+}
SVNspam 0.1