Commit in lcsim/src/org/lcsim/contrib/onoprien/tracking on MAIN
ExampleDriver.java+8-31.4 -> 1.5
digitization/DigitizationDriver.java+2-21.2 -> 1.3
geom/SensorType.java+25-71.1 -> 1.2
geom/sensortype/Cylinder.java+82-261.2 -> 1.3
               /Rectangle.java+54-81.1 -> 1.2
               /Ring.java+12-41.1 -> 1.2
clustering/ClusteringDriver.java+123added 1.1
+306-50
1 added + 6 modified, total 7 files
Added clustering driver, SensorType extensions

lcsim/src/org/lcsim/contrib/onoprien/tracking
ExampleDriver.java 1.4 -> 1.5
diff -u -r1.4 -r1.5
--- ExampleDriver.java	10 May 2007 21:17:12 -0000	1.4
+++ ExampleDriver.java	20 May 2007 03:33:24 -0000	1.5
@@ -7,6 +7,7 @@
 import org.lcsim.recon.cat.util.Const;
 import org.lcsim.util.Driver;
 
+import org.lcsim.contrib.onoprien.tracking.clustering.ClusteringDriver;
 import org.lcsim.contrib.onoprien.tracking.digitization.DigitizationDriver;
 import org.lcsim.contrib.onoprien.tracking.digitization.Digitizer;
 import org.lcsim.contrib.onoprien.tracking.digitization.digitizers.DigitizerSmear;
@@ -20,7 +21,7 @@
 /**
  *
  * @author D.Onoprienko
- * @version $Id: ExampleDriver.java,v 1.4 2007/05/10 21:17:12 onoprien Exp $
+ * @version $Id: ExampleDriver.java,v 1.5 2007/05/20 03:33:24 onoprien Exp $
  */
 public class ExampleDriver extends Driver {
   
@@ -65,9 +66,13 @@
     DigitizationDriver digitizationDriver = new DigitizationDriver(digitizer);
     digitizationDriver.setOutputCollection("DigiHits");
     add(digitizationDriver);
-
+    
+    ClusteringDriver clusteringDriver = new ClusteringDriver();
+    clusteringDriver.set("INPUT_MAP_NAME","DigiHits");
+    clusteringDriver.set("OUTPUT_MAP_NAME","ClusterData");
+    add(clusteringDriver);
   }
-  
+
   public void process(EventHeader event) {
     super.process(event);
     

lcsim/src/org/lcsim/contrib/onoprien/tracking/digitization
DigitizationDriver.java 1.2 -> 1.3
diff -u -r1.2 -r1.3
--- DigitizationDriver.java	10 May 2007 21:13:42 -0000	1.2
+++ DigitizationDriver.java	20 May 2007 03:33:24 -0000	1.3
@@ -33,7 +33,7 @@
  * in the constructor.
  *
  * @author D.Onoprienko
- * @version $Id: DigitizationDriver.java,v 1.2 2007/05/10 21:13:42 onoprien Exp $
+ * @version $Id: DigitizationDriver.java,v 1.3 2007/05/20 03:33:24 onoprien Exp $
  */
 public class DigitizationDriver extends Driver {
   
@@ -191,7 +191,7 @@
           compHit.addHit(hit);
         } else {
           if (compHit == null) {
-            dList.add(previousHit);
+            if (previousHit != null) dList.add(previousHit);
           } else {
             compHit.trimToSize();
             dList.add(compHit);

lcsim/src/org/lcsim/contrib/onoprien/tracking/geom
SensorType.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- SensorType.java	7 May 2007 19:02:42 -0000	1.1
+++ SensorType.java	20 May 2007 03:33:24 -0000	1.2
@@ -1,5 +1,7 @@
 package org.lcsim.contrib.onoprien.tracking.geom;
 
+import java.util.List;
+
 import hep.physics.vec.Hep3Vector;
 
 /**
@@ -12,12 +14,9 @@
  * right-nahded system.
  *
  * @author D.Onoprienko
- * @version $Id: SensorType.java,v 1.1 2007/05/07 19:02:42 onoprien Exp $
+ * @version $Id: SensorType.java,v 1.2 2007/05/20 03:33:24 onoprien Exp $
  */
 public interface SensorType {
-  
-  /** Returns maximum channel ID on this sensor. */
-  public int getMaxChannelID();
 
   /**
    * Converts a point in local sensor coordinates to channel ID.
@@ -30,13 +29,27 @@
    */
   public Hep3Vector getChannelPosition(int channelID);
   
+  /** Returns maximum channel ID on this sensor. */
+  public int getMaxChannelID();
+  
+  /** Returns dimensions of a given channel along U, V, W. */
+  public Hep3Vector getChannelDimensions(int channelID);
+  
   /**
-   * Returns dimensions of a given channel along U, V, W.
+   * Returns the dimension of a measurement by this type of sensor
+   * (1 for strips, 2 for pixels, etc). Note that algorithms can ignore this method
+   * and use {@link #getChannelDimensions(int)} to decide how to treat measurements
+   * by the given sensor. However, {@link #getNeighbors(int)} should only look for 
+   * neighbors in <tt>U</tt> direction if this method returns <tt>1</tt>.
    */
-  public Hep3Vector getChannelDimensions(int channelID);
+  public int getHitDimension();
   
   /**
-   * Returns channel ID of a neighbor channel.
+   * Returns ID of a channel obtained by shifting the given channel by the given
+   * number of channels in the given direction along the local reference frame axis. 
+   * Returns <tt>-1</tt> if shifting puts the point outside of the sensor boundaries.
+   * Throws <tt>IllegalArgumentException</tt> if this type of sensor does not have a
+   * concept of a neighbor in the given direction. 
    *
    * @param channelID  ID of the original channel
    * @param shiftV     move in <tt>V</tt> direction by <tt>shiftV</tt> channels
@@ -44,4 +57,9 @@
    */
   public int getNeighbor(int channelID, int shiftU, int shiftV);
   
+  /**
+   * Returns array of IDs of all immediate neighbor channels.
+   */
+  public List<Integer> getNeighbors(int channelID);
+  
 }

lcsim/src/org/lcsim/contrib/onoprien/tracking/geom/sensortype
Cylinder.java 1.2 -> 1.3
diff -u -r1.2 -r1.3
--- Cylinder.java	10 May 2007 21:13:42 -0000	1.2
+++ Cylinder.java	20 May 2007 03:33:24 -0000	1.3
@@ -1,5 +1,8 @@
 package org.lcsim.contrib.onoprien.tracking.geom.sensortype;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import hep.physics.vec.BasicHep3Vector;
 import hep.physics.vec.Hep3Vector;
 
@@ -11,7 +14,7 @@
  * center of the cylinder.
  *
  * @author D.Onoprienko
- * @version $Id: Cylinder.java,v 1.2 2007/05/10 21:13:42 onoprien Exp $
+ * @version $Id: Cylinder.java,v 1.3 2007/05/20 03:33:24 onoprien Exp $
  */
 public class Cylinder implements SensorType {
   
@@ -36,8 +39,9 @@
     _radius = radius;
     _nDivV = nLength;
     _nDivU = nPhi;
-    _pitch = TWOPI/_nDivU;
-    _length = length/_nDivV;
+    _stripWidth = TWOPI/_nDivU;
+    _stripLength = length/_nDivV;
+    _hitDim = (_stripLength/_stripWidth < 4.) ? 2 : 1;
   }
   
   /**
@@ -58,8 +62,9 @@
     _radius = radius;
     _nDivV = nLength;
     _nDivU = (int) Math.round((TWOPI*radius)/stripPitch);
-    _pitch = TWOPI/_nDivU;
-    _length = length/_nDivV;
+    _stripWidth = TWOPI/_nDivU;
+    _stripLength = length/_nDivV;
+    _hitDim = (_stripLength/_stripWidth < 4.) ? 2 : 1;
   }
   
   /**
@@ -80,16 +85,21 @@
     _radius = radius;
     _nDivV = (int) Math.round(length/stripLength);
     _nDivU = (int) Math.round((TWOPI*radius)/stripPitch);
-    _pitch = TWOPI/_nDivU;
-    _length = length/_nDivV;
+    _stripWidth = TWOPI/_nDivU;
+    _stripLength = length/_nDivV;
+    _hitDim = (stripLength/stripPitch < 4.) ? 2 : 1;
   }
+
+// -- Setters :  ---------------------------------------------------------------
   
-// -----------------------------------------------------------------------------
-  
-  /** Returns maximum possible channel ID on this sensor. */
-  public int getMaxChannelID() {
-    return  _nDivU * _nDivV;
+  /**
+   * Set the dimension of a measurement by this type of sensor (1 for strips, 2 for pixels, etc).
+   */
+  public void setHitDimension(int dim) {
+    _hitDim = dim;
   }
+  
+// -----------------------------------------------------------------------------
 
   /**
    * Converts a point in local sensor coordinates to channel ID.
@@ -97,16 +107,14 @@
    */
   public int getChannelID(Hep3Vector point) {
     
-    //System.out.println("Point: phi "+ point.x() +" z "+ point.y() +" r "+ point.z());
-    
     if (Math.abs(point.z()-_radius) > _halfThick) return -1;
 
     double u = point.x();
     double v = point.y();
     if (u < 0. || u > TWOPI || Math.abs(v) > _halfLength) return -1;
     
-    int nU = (int) Math.floor(u/_pitch); if (nU == _nDivU) nU--;
-    int nV = (int) Math.floor((v+_halfLength)/_length); if (nV == _nDivV) nV--;
+    int nU = (int) Math.floor(u/_stripWidth); if (nU == _nDivU) nU--;
+    int nV = (int) Math.floor((v+_halfLength)/_stripLength); if (nV == _nDivV) nV--;
     return nV*_nDivU + nU + 1;
   }
   
@@ -115,17 +123,33 @@
    */
   public Hep3Vector getChannelPosition(int channelID) {
     int nU = --channelID % _nDivU;
-    int nV = channelID / _nDivV;
-    double u = (nU + .5) * _pitch;
-    double v = (nV + .5) * _length - _halfLength;
-    return new BasicHep3Vector(u,v,0.);
+    int nV = channelID / _nDivU;
+    double u = (nU + .5) * _stripWidth;
+    double v = (nV + .5) * _stripLength - _halfLength;
+    return new BasicHep3Vector(u,v,_radius);
+  }
+  
+  /** Returns maximum possible channel ID on this sensor. */
+  public int getMaxChannelID() {
+    return  _nDivU * _nDivV;
   }
   
   /**
    * Returns dimensions of the given channel along U, V, W.
    */
   public Hep3Vector getChannelDimensions(int channelID) {
-    return new BasicHep3Vector(_pitch, _length, 2.*_halfThick);
+    return new BasicHep3Vector(_stripWidth, _stripLength, 2.*_halfThick);
+  }
+  
+  /**
+   * Returns the dimension of a measurement by this type of sensor
+   * (1 for strips, 2 for pixels, etc). 
+   * By default, this method returns <tt>1</tt> if strip length is at least 4 times
+   * bigger than strip pitch. The return value can also be set explicitly through a call
+   * to {@link #setHitDimension(int)}.
+   */
+  public int getHitDimension() {
+    return _hitDim;
   }
   
   /**
@@ -138,25 +162,57 @@
    */
   public int getNeighbor(int channelID, int shiftU, int shiftV) {
     int nU = (--channelID % _nDivU) + shiftU;
-    int nV = (channelID / _nDivV) + shiftV;
-    if (nU < 0 || nV < 0 || nU >= _nDivU || nV >= _nDivV) {
+    if (nU < 0) {
+      nU += _nDivU;
+    } else if (nU >= _nDivU) {
+      nU -= _nDivU;
+    }
+    int nV = (channelID / _nDivU) + shiftV;
+    if (nV < 0 || nV >= _nDivV) {
       return -1;
     } else {
       return nV*_nDivU + nU + 1;
     }
   }
   
+  /** 
+   * Returns array of IDs of all immediate neighbor channels. 
+   * For strips ({@link #getHitDimension()} returns 1), this method looks for neighbors
+   * in U direction only. Therefore, each strip has 1 or 2 neighbors. For pixels
+   * ({@link #getHitDimension()} returns 2), up to 8 neighbors can be found.
+   */
+  public List<Integer> getNeighbors(int channelID) {
+    int nU = ((channelID -1) % _nDivU);
+    int nV = ((channelID -1) / _nDivU);
+    ArrayList<Integer> out = new ArrayList<Integer>(8);
+    if ((_hitDim == 2) && (nV > 0)) {
+      out.add((nU > 0) ? (channelID - _nDivU - 1) : (channelID - 1) );
+      out.add( channelID - _nDivU );
+      out.add( (nU < _nDivU - 1) ? (channelID - _nDivU + 1) : (channelID - 2*_nDivU + 1) );
+    }
+    out.add( (nU > 0) ? (channelID - 1) : (channelID - 1 + _nDivU) );
+    out.add( (nU < _nDivU - 1) ? (channelID +1) : (channelID - _nDivU + 1) );
+    if ((_hitDim == 2) && (nV < _nDivV-1)) {
+      out.add( (nU > 0) ? (channelID + _nDivU -1) : (channelID - 1 + 2*_nDivU) );
+      out.add(channelID + _nDivU);
+      out.add( (nU < _nDivU - 1) ? (channelID + _nDivU + 1) : (channelID + 1) );
+    }
+    return out;
+  }
+  
 // -- Private parts :  ---------------------------------------------------------
   
   protected double _halfLength;
   protected double _halfThick;
   protected double _radius;
   
-  protected double _pitch;
-  protected double _length;
+  protected double _stripWidth;
+  protected double _stripLength;
+  
+  protected int _hitDim;
   
   protected int _nDivU;
   protected int _nDivV;
   
-  protected final double TWOPI = 2.*Math.PI;
+  static final double TWOPI = 2.*Math.PI;
 }

lcsim/src/org/lcsim/contrib/onoprien/tracking/geom/sensortype
Rectangle.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- Rectangle.java	7 May 2007 19:02:42 -0000	1.1
+++ Rectangle.java	20 May 2007 03:33:24 -0000	1.2
@@ -1,5 +1,8 @@
 package org.lcsim.contrib.onoprien.tracking.geom.sensortype;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import hep.physics.vec.BasicHep3Vector;
 import hep.physics.vec.Hep3Vector;
 
@@ -10,7 +13,7 @@
  * The reference frame origin is at the center of the sensor.
  *
  * @author D.Onoprienko
- * @version $Id: Rectangle.java,v 1.1 2007/05/07 19:02:42 onoprien Exp $
+ * @version $Id: Rectangle.java,v 1.2 2007/05/20 03:33:24 onoprien Exp $
  */
 public class Rectangle implements SensorType {
   
@@ -37,14 +40,19 @@
     _nDivU = nWidth;
     _pitch = width/nWidth;
     _length = length/nLength;
+    _hitDim = (_length/_pitch < 4.) ? 2 : 1;
   }
+
+// -- Setters :  ---------------------------------------------------------------
   
-// -----------------------------------------------------------------------------
-  
-  /** Returns maximum possible channel ID on this sensor. */
-  public int getMaxChannelID() {
-    return  _nDivU * _nDivV;
+  /**
+   * Set the dimension of a measurement by this type of sensor (1 for strips, 2 for pixels, etc).
+   */
+  public void setHitDimension(int dim) {
+    _hitDim = dim;
   }
+    
+// -----------------------------------------------------------------------------
 
   /**
    * Converts a point in local sensor coordinates to channel ID.
@@ -68,11 +76,16 @@
    */
   public Hep3Vector getChannelPosition(int channelID) {
     int nU = --channelID % _nDivU;
-    int nV = channelID / _nDivV;
+    int nV = channelID / _nDivU;
     double u = (nU + .5) * _pitch - _halfWidth;
     double v = (nV + .5) * _length - _halfLength;
     return new BasicHep3Vector(u,v,0.);
   }
+
+  /** Returns maximum possible channel ID on this sensor. */
+  public int getMaxChannelID() {
+    return  _nDivU * _nDivV;
+  }
   
   /**
    * Returns dimensions of the given channel along U, V, W.
@@ -82,6 +95,17 @@
   }
   
   /**
+   * Returns the dimension of a measurement by this type of sensor
+   * (1 for strips, 2 for pixels, etc). 
+   * By default, this method returns <tt>1</tt> if strip length is at least 4 times
+   * bigger than strip pitch. Alternatively, the return value can be set explicitly
+   * through a call to {@link #setHitDimension(int)}.
+   */
+  public int getHitDimension() {
+    return _hitDim;
+  }
+  
+  /**
    * Returns channel ID of a neighbor channel.
    * Returns -1 if the channel defined by shifts does not exist on this sensor.
    *
@@ -91,7 +115,7 @@
    */
   public int getNeighbor(int channelID, int shiftU, int shiftV) {
     int nU = (--channelID % _nDivU) + shiftU;
-    int nV = (channelID / _nDivV) + shiftV;
+    int nV = (channelID / _nDivU) + shiftV;
     if (nU < 0 || nV < 0 || nU >= _nDivU || nV >= _nDivV) {
       return -1;
     } else {
@@ -99,6 +123,26 @@
     }
   }
   
+  /** Returns array of IDs of all immediate neighbor channels. */
+  public List<Integer> getNeighbors(int channelID) {
+    int nU = (channelID -1) % _nDivU;
+    int nV = (channelID -1) / _nDivU;
+    ArrayList<Integer> out = new ArrayList<Integer>(8);
+    if ((_hitDim == 2) && (nV > 0)) {
+      if (nU > 0) out.add(channelID - _nDivU - 1);
+      out.add( channelID - _nDivU );
+      if (nU < _nDivU - 1) out.add(channelID - _nDivU + 1);
+    }
+    if (nU > 0) out.add(channelID - 1);
+    if (nU < _nDivU - 1) out.add(channelID +1);
+    if ((_hitDim == 2) && (nV < _nDivV-1)) {
+      if (nU > 0) out.add(channelID + _nDivU -1);
+      out.add( channelID + _nDivU );
+      if (nU < _nDivU - 1) out.add(channelID + _nDivU + 1);
+    }
+    return out;
+  }
+  
 // -- Private parts :  ---------------------------------------------------------
   
   protected double _halfLength;
@@ -108,6 +152,8 @@
   protected double _pitch;
   protected double _length;
   
+  protected int _hitDim;
+  
   protected int _nDivU;
   protected int _nDivV;
 }

lcsim/src/org/lcsim/contrib/onoprien/tracking/geom/sensortype
Ring.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- Ring.java	7 May 2007 19:02:42 -0000	1.1
+++ Ring.java	20 May 2007 03:33:24 -0000	1.2
@@ -4,11 +4,17 @@
 import hep.physics.vec.Hep3Vector;
 
 /**
- * Class to represent a disk sensor tiled with strips.
+ * Class to represent a disk sensor divided into rectangular strips or pixels.
  * Reference frame origin is at the center of the disk. 
  *
+ * Note that {@link #getNeighbors(int)} method of an instance of this class can
+ * return non-existing channel IDs - for the sake of speed, no ckecking is done 
+ * to verify that returned IDs belong to channels inside the ring. 
+ * {@link #getChannelID(Hep3Vector)} method returns <tt>-1</tt> if and only if the 
+ * center of the rectangle (strip) to which the point belongs is ouside the ring.
+ *
  * @author D.Onoprienko
- * @version $Id: Ring.java,v 1.1 2007/05/07 19:02:42 onoprien Exp $
+ * @version $Id: Ring.java,v 1.2 2007/05/20 03:33:24 onoprien Exp $
  */
 public class Ring extends Rectangle {
   
@@ -37,6 +43,8 @@
     
     _pitch = pitch;
     _length = length;
+    
+    _hitDim = (_length/_pitch < 4.) ? 2 : 1;
   }
   
 // -----------------------------------------------------------------------------
@@ -73,7 +81,7 @@
    */
   public int getNeighbor(int channelID, int shiftU, int shiftV) {
     int nU = (--channelID % _nDivU) + shiftU;
-    int nV = (channelID / _nDivV) + shiftV;
+    int nV = (channelID / _nDivU) + shiftV;
     double r = Math.hypot((nU + .5) * _pitch - _halfWidth, (nV + .5) * _length - _halfLength);
     if (r < _rMin || r > _rMax) {
       return -1;
@@ -81,7 +89,7 @@
       return nV*_nDivU + nU + 1;
     }
   }
-  
+
 // -- Private parts :  ---------------------------------------------------------
   
   protected double _rMin;

lcsim/src/org/lcsim/contrib/onoprien/tracking/clustering
ClusteringDriver.java added at 1.1
diff -N ClusteringDriver.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ClusteringDriver.java	20 May 2007 03:33:25 -0000	1.1
@@ -0,0 +1,123 @@
+package org.lcsim.contrib.onoprien.tracking.clustering;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+import hep.physics.vec.Hep3Vector;
+import org.lcsim.event.EventHeader;
+import org.lcsim.recon.cat.util.Const;
+import org.lcsim.recon.cat.util.NoSuchParameterException;
+import org.lcsim.util.Driver;
+
+import org.lcsim.contrib.onoprien.tracking.geom.Sensor;
+import org.lcsim.contrib.onoprien.tracking.geom.SensorType;
+import org.lcsim.contrib.onoprien.tracking.hit.DigiTrackerHit;
+import org.lcsim.contrib.onoprien.tracking.hit.TrackerClusterData;
+import org.lcsim.contrib.onoprien.tracking.hit.TrackerHitMaker;
+import org.lcsim.contrib.onoprien.tracking.hit.base.TrackerClusterDataBasic;
+
+/**
+ * Driver that handles clustering of {@link DigiTrackerHit} objects.
+ * The driver fetches a map of digitized hits from the event, and 
+ * creates a map of clusters. 
+ *
+ * @author D.Onoprienko
+ * @version $Id: ClusteringDriver.java,v 1.1 2007/05/20 03:33:25 onoprien Exp $
+ */
+public class ClusteringDriver extends Driver {
+  
+// -- Constructors :  ----------------------------------------------------------
+  
+  public ClusteringDriver() {
+    _inMapName = "DigiTrackerHit";
+    _outMapName = "TrackerClusterData";
+  }
+  
+// -- Setters :  ---------------------------------------------------------------
+  
+  /** 
+   * Set any <tt>String</tt> parameter. 
+   * The following parameters can be set with this method:<br>
+   * <tt>"INPUT_MAP_NAME"</tt> - Name of input collection of digitized hits
+   *                 (type <tt>HashMap<Sensor, ArrayList<DigiTrackerHit>></tt>). 
+   *                 Default: "DigiTrackerHit".<br>
+   * <tt>"OUTPUT_MAP_NAME"</tt> - Name of ouitput collection of clusters
+   *             (type <tt>HashMap<Sensor, ArrayList<TrackerClusterData>></tt>). 
+   *             Default: "TrackerClusterData".<br>
+   * @param name   Name of parameter to be set. Case is ignored.
+   * @param value  Value to be assigned to the parameter.
+   * @throws NoSuchParameterException Thrown if the supplied parameter name is unknown.
+   *         Subclasses may catch this exception after a call to <tt>super.set()</tt>
+   *         and set their own parameters.
+   */
+  public void set(String name, String value) {
+    if (name.equalsIgnoreCase("INPUT_MAP_NAME")) {
+      _inMapName = value;
+    } else if (name.equalsIgnoreCase("OUTPUT_MAP_NAME")) {
+      _outMapName = value;
+    } else {
+      throw new NoSuchParameterException(name, this.getClass());
+    }
+  }
+  
+// -- Event processing :  ------------------------------------------------------
+  
+  public void process(EventHeader event) {
+    
+    super.process(event);
+    
+    HashMap<Sensor, ArrayList<DigiTrackerHit>> inMap = (HashMap<Sensor, ArrayList<DigiTrackerHit>>) event.get(_inMapName);
+    HashMap<Sensor, ArrayList<TrackerClusterData>> outMap = new HashMap<Sensor, ArrayList<TrackerClusterData>>();
+
+    for (Sensor sensor : inMap.keySet()) {
+      ArrayList<TrackerClusterData> clusterList = findClusters(sensor, inMap.get(sensor));
+      if ( ! clusterList.isEmpty()) outMap.put(sensor, clusterList);
+    }
+
+    event.put(_outMapName, outMap);
+  }
+
+  /**
+   * Returns a list of found clusters on the sensor.
+   * Default implementation uses simple nearest neighbor clustering.
+   */
+  public ArrayList<TrackerClusterData> findClusters(Sensor sensor, List<DigiTrackerHit> hits) {
+    SensorType senType = sensor.getType();
+      //System.out.println("size fo list given to findClusters "+hits.size());
+    LinkedList<DigiTrackerHit> hitList = (hits instanceof LinkedList) ? 
+           (LinkedList<DigiTrackerHit>) hits : new LinkedList<DigiTrackerHit>(hits);
+    ArrayList<TrackerClusterData> clusterList = new ArrayList<TrackerClusterData>();
+    while (! hitList.isEmpty()) {
+      ArrayList<DigiTrackerHit> hitsInCluster = new ArrayList<DigiTrackerHit>();
+      DigiTrackerHit seed = hitList.pop();
+      hitsInCluster.add(seed);
+      List<Integer> newChannels = senType.getNeighbors(seed.getChannel());
+      while (!newChannels.isEmpty()) {
+        List<Integer> oldChannels = newChannels;
+        newChannels = new ArrayList<Integer>(30);
+        ListIterator<DigiTrackerHit> it = hitList.listIterator();
+        while (it.hasNext()) {
+          DigiTrackerHit hit = it.next();
+          int channel = hit.getChannel();
+          if ( newChannels.contains(channel) ) {
+            hitsInCluster.add(hit);
+            newChannels.addAll(senType.getNeighbors(channel));
+            it.remove();
+          }
+        }
+      }
+      hitsInCluster.trimToSize();
+      clusterList.add(new TrackerClusterDataBasic(hitsInCluster,sensor));
+    }
+    clusterList.trimToSize();
+    return clusterList;
+  }
+
+// -- Private parts :  ---------------------------------------------------------
+  
+  protected String _inMapName;
+  protected String _outMapName;
+}
CVSspam 0.2.8