Commit in GeomConverter/src/org/lcsim/geometry/segmentation on MAIN
NonprojectiveCylinder.java+174-241.6 -> 1.7
Implement getNeighbourIDs() and other convenience methods

GeomConverter/src/org/lcsim/geometry/segmentation
NonprojectiveCylinder.java 1.6 -> 1.7
diff -u -r1.6 -r1.7
--- NonprojectiveCylinder.java	28 Jun 2005 23:15:05 -0000	1.6
+++ NonprojectiveCylinder.java	5 Jul 2005 06:48:57 -0000	1.7
@@ -19,6 +19,8 @@
 import org.lcsim.geometry.util.IDDescriptor;
 import org.lcsim.geometry.util.IDEncoder;
 import org.lcsim.geometry.subdetector.CylindricalCalorimeter;
+import org.lcsim.geometry.layer.Layer;
+import org.lcsim.geometry.layer.LayerStack;
 
 /**
  * @author jeremym
@@ -74,14 +76,6 @@
 	return gridSizeZ;
     }
 
-    public double getZMin() {
-	return ((CylindricalCalorimeter)detector).getZMin();
-    }
-
-    public double getZMax() {
-	return ((CylindricalCalorimeter)detector).getZMax();
-    }
-
     public double getPhi()
     {
         return (((double)getValue(phiIndex)) + 0.5) * computeDeltaPhiForLayer();
@@ -152,44 +146,200 @@
     public long[] getNeighbourIDs(int layerRange, int zRange, int phiRange)
     {
       encoder.setValues(values);
+//       int klay = decoder.getValue("layer");
+//       int kz   = decoder.getValue("z");
+//       int kphi = decoder.getValue("phi");
+//       System.out.println("NeighborID: ref="+klay+" "+kz+" "+kphi+" (hex "
+// 			 +Long.toHexString(encoder.getID())+")");
 
       int nMax = (2*layerRange + 1)*(2*zRange + 1)*(2*phiRange + 1) - 1;
       long[] result = new long[nMax];
       
+      // theta and phi are used to find central neighbors in other layers
+      double theta = getTheta();
+      double phi = getPhi();
+
       int zBins = (int)Math.floor( (getZMax()-getZMin()) / getGridSizeZ() );
-      System.out.println("In z: zmin="+getZMin()+", zmax="+getZMax()
-			 +", gridZ= "+getGridSizeZ()+", zBins="+zBins);
 
       int size = 0;
-      for (int i=-layerRange;i<=layerRange;i++) {
-	int l = values[layerIndex] + i;
+      for (int i=-layerRange; i<=layerRange; ++i) {
+	int ilay = values[layerIndex] + i;
+
+	if (ilay<0 || ilay>=detector.getLayerCount()) continue;
+	encoder.setValue(layerIndex,ilay);
+
+	double dphi = this.computeDeltaPhiForLayer(ilay);
+	int phiBins =  (int)Math.floor(2*Math.PI / dphi);
 
-	if (l<0 || l>=detector.getLayerCount()) continue;
-	encoder.setValue(layerIndex,l);
+	double cylR = getRadiusSensitiveMid( ilay );
+	double x = cylR * Math.cos(phi);
+	double y = cylR * Math.sin(phi);
+	double z = cylR / Math.tan(theta);
+// 	System.out.println("layer "+ilay+", cylR="+cylR
+// 			   +", theta="+theta+", phi="+phi
+// 			   +", rvec=( "+x+", "+y+", "+z+")");
+
+	long id = this.findCellContainingXYZ(x,y,z);
+	if(id==0) continue;
+
+	// save indices in a new array, as values[] keeps the original ref
+	decoder.setID(id);
+	int[] tmpval = new int[ values.length ];
+        decoder.getValues(tmpval);
 
-	double dphi = this.computeDeltaPhiForLayer(i);
-	int phiBins =  (int)Math.floor(2*Math.PI / dphi) ;
-	for (int j=-zRange;j<=zRange;j++) {
-          int t = values[zIndex] + j;
+	for (int j=-zRange; j<=zRange; ++j) {
+          int iz = tmpval[zIndex] + j;
 
-	  if (t<0 || t>=zBins) continue;
-	  encoder.setValue(zIndex,t);
+	  if (iz<-zBins/2 || iz>=zBins/2) continue;
+	  encoder.setValue(zIndex,iz);
 
-	  for (int k=-phiRange;k<=phiRange;k++) {
+	  for (int k=-phiRange; k<=phiRange; ++k) {
+	    // skip reference cell
 	    if (i==0 && j==0 && k==0) continue;
 
-	    int p = values[phiIndex] + k;
-	    if (p<0 || p>=phiBins) continue;
+	    int iphi = tmpval[phiIndex] + k;
+	    if(iphi<0) iphi += phiBins;
+	    if(iphi>=phiBins) iphi -= phiBins;
+	    if (iphi<0 || iphi>=phiBins) continue; 
 
-	    result[size++] = encoder.setValue(phiIndex,p);
+// 	    System.out.println("Adding neighbor: "+ilay+" "+iz+" "+iphi);
+	    result[size++] = encoder.setValue(phiIndex,iphi);
 	  }
 	}
       }
       if(size < result.length) {
+	int klay = decoder.getValue("layer");
+	int kz   = decoder.getValue("z");
+	int kphi = decoder.getValue("phi");
+// 	System.out.println("Neighbors="+size+"/"+result.length
+// 			   +", ref="+klay+" "+kz+" "+kphi);
+
 	long[] temp = new long[size];
 	System.arraycopy(result,0,temp,0,size);
 	result = temp;
       }
       return result;
     }
+
+    // Not for public use, but this is needed to calculate positions
+    // and number of cells, etc.
+    private double getZMin() {
+	return ((CylindricalCalorimeter)detector).getZMin();
+    }
+
+    private double getZMax() {
+	return ((CylindricalCalorimeter)detector).getZMax();
+    }
+
+    private double getRMin() {
+	return ((CylindricalCalorimeter)detector).getInnerRadius();
+    }
+
+    private double getRMax() {
+	return ((CylindricalCalorimeter)detector).getOuterRadius();
+    }
+
+    /**
+     * Return the cell which contains a given point (x,y,z), or null.
+     * Side effect: encoder will be reset to the ID returned by this method.
+     *
+     * @param x,y,z cartesian coordinates of the point
+     * @return ID of cell containing the point (maybe either in
+     * absorber or live material)
+     */
+    public long findCellContainingXYZ(double x, double y, double z) {
+	// validate point
+	if(z<getZMin()) {
+	    System.out.println("find: fail z<zmin: z="+z);
+	    return 0;
+	}
+	if(z>getZMax()) {
+	    System.out.println("find: fail z>zmax: z="+z);
+	    return 0;
+	}
+	double rho = Math.sqrt(x*x+y*y);
+	if(rho<getRMin()) {
+	    System.out.println("find: fail rho<Rmin: rho="+rho);
+	    return 0;
+	}
+	if(rho>getRMax()) {
+	    System.out.println("find: fail rho>Rmax: rho="+rho);
+	    return 0;
+	}
+
+	// ok, point is valid, so a valid ID should be returned
+	int ilay = getLayerBin(rho);
+	int iz = getZBin(z);
+
+	double phi = Math.atan2( y, x );
+	if(phi<0) phi += 2*Math.PI;
+	int iphi = getPhiBin(ilay,phi);
+
+	encoder.setValue("layer",ilay);
+	encoder.setValue(zIndex,iz);
+	encoder.setValue(phiIndex,iphi);
+
+	return encoder.getID();
+    }
+
+    public int getLayerBin(double r) {
+	// In order to be general, we should not assume that all
+	// layers have the same thickness.  Therefore, one has to
+	// guess the starting layer (based on average thickness), and
+	// then navigate trhough layers until one finds the right one
+	double depth = r - getRMin();
+	double mean_t = (getRMax()-getRMin()) / detector.getLayerCount();
+
+	int ilay = (int)Math.floor( depth / mean_t );
+	LayerStack stack = detector.getLayers();
+	Layer layer = stack.getLayer(ilay);
+	double depHi = stack.getThicknessToLayerBack(ilay);
+	double depLo = depHi - layer.getTotalThickness();
+	for(;;) {
+	  if( depth>depLo && depth<=depHi ) return ilay;
+	  if( depth<=depLo ) {
+	      --ilay;
+	      depHi = depLo;
+	      layer = stack.getLayer(ilay);
+	      depLo -= layer.getTotalThickness();
+	  }
+	  if( depth>depHi ) {
+	      ++ilay;
+	      depLo = depHi;
+	      layer = stack.getLayer(ilay);
+	      depHi += layer.getTotalThickness();
+	  }
+	}
+    }
+
+    public int getPhiBin(int ilay, double phi) {
+      // phic is phi at center of cells with iphi=0
+      double deltaPhi = this.computeDeltaPhiForLayer(ilay);
+      double phic = deltaPhi / 2;
+      int iphi = (int)Math.floor((phi-phic)/deltaPhi + 0.5);
+      return iphi;
+    }
+
+    public int getZBin(double z) {
+      // zc is z at center of cells with iz=0
+      int numz = (int)Math.floor((getZMax()-getZMin()) / gridSizeZ);
+      double zc = 0;  // for odd numz
+      if( numz%2 == 0 ) zc = gridSizeZ / 2;
+      int iz = (int)Math.floor((z-zc)/gridSizeZ + 0.5);
+      return iz;
+    }
+
+    /**
+     * Returns cylindrical radius to center of sensitive slice of any layer
+     * @param layer layer index
+     */
+    private double getRadiusSensitiveMid(int ilay) {
+	LayerStack stack = detector.getLayers();
+	Layer layer = stack.getLayer(ilay);
+
+	double preLayers = 0;
+	if(ilay>0) preLayers = stack.getSectionThickness(0,ilay-1);
+
+	return this.getRMin() + preLayers + layer.getThicknessToSensitiveMid();
+    }
 }
CVSspam 0.2.8