package hep.aida.ref;
import hep.aida.IAxis;
import hep.aida.IHistogram;
import hep.aida.IHistogram1D;
import hep.aida.IHistogram2D;
/**
Abstract base class extracting and implementing most of the redundancy of the interface.
@author Wolfgang Hoschek, Tony Johnson, and others.
@version 1.0, 23/03/2000
*/
abstract class AbstractHistogram2D extends Histogram implements IHistogram2D
{
protected IAxis xAxis, yAxis;
AbstractHistogram2D(String title)
{
super(title);
}
public int allEntries()
{
int n = 0;
for (int i=xAxis.bins(); --i >= -2;)
for (int j=yAxis.bins(); --j >= -2;)
{
n += binEntries(i,j);
}
return n;
}
public int binEntriesX(int indexX)
{
return projectionX().binEntries(indexX);
}
public int binEntriesY(int indexY)
{
return projectionY().binEntries(indexY);
}
public double binHeightX(int indexX)
{
return projectionX().binHeight(indexX);
}
public double binHeightY(int indexY)
{
return projectionY().binHeight(indexY);
}
public int dimensions()
{
return 2;
}
public int entries()
{
int n = 0;
for (int i=0; i<xAxis.bins(); i++)
for (int j=0; j<yAxis.bins(); j++)
{
n += binEntries(i,j);
}
return n;
}
public int extraEntries()
{
return allEntries() - entries();
}
public void fill(double x, double y)
{
fill(x,y,1);
}
/**
* The precise meaning of the arguments to the public slice
* methods is somewhat ambiguous, so we define this internal
* slice method and clearly specify its arguments.
* <p>
* <b>Note 0</b>indexY1 and indexY2 use our INTERNAL bin numbering scheme
* <b>Note 1</b>The slice is done between indexY1 and indexY2 INCLUSIVE
* <b>Note 2</b>indexY1 and indexY2 may include the use of under and over flow bins
* <b>Note 3</b>There is no note 3 (yet)
*/
protected abstract IHistogram1D internalSliceX(String title, int indexY1, int indexY2);
/**
* The precise meaning of the arguments to the public slice
* methods is somewhat ambiguous, so we define this internal
* slice method and clearly specify its arguments.
* <p>
* <b>Note 0</b>indexX1 and indexX2 use our INTERNAL bin numbering scheme
* <b>Note 1</b>The slice is done between indexX1 and indexX2 INCLUSIVE
* <b>Note 2</b>indexX1 and indexX2 may include the use of under and over flow bins
* <b>Note 3</b>There is no note 3 (yet)
*/
protected abstract IHistogram1D internalSliceY(String title, int indexX1, int indexX2);
/**
* Package private method to map from the external representation of bin
* number to our internal representation of bin number
*/
int mapX(int index)
{
int bins = xAxis.bins() + 2;
if (index >= bins) throw new IllegalArgumentException("bin="+index);
if (index >= 0) return index+1;
if (index == IHistogram.UNDERFLOW) return 0;
if (index == IHistogram.OVERFLOW) return bins-1;
throw new IllegalArgumentException("bin="+index);
}
/**
* Package private method to map from the external representation of bin
* number to our internal representation of bin number
*/
int mapY(int index)
{
int bins = yAxis.bins() + 2;
if (index >= bins) throw new IllegalArgumentException("bin="+index);
if (index >= 0) return index+1;
if (index == IHistogram.UNDERFLOW) return 0;
if (index == IHistogram.OVERFLOW) return bins-1;
throw new IllegalArgumentException("bin="+index);
}
public int[] minMaxBins()
{
double minValue = Double.MAX_VALUE;
double maxValue = Double.MIN_VALUE;
int minBinX = -1;
int minBinY = -1;
int maxBinX = -1;
int maxBinY = -1;
for (int i=xAxis.bins(); --i >= 0; ) {
for (int j=yAxis.bins(); --j >= 0; ) {
double value = binHeight(i,j);
if (value < minValue) {
minValue = value;
minBinX = i;
minBinY = j;
}
if (value > maxValue) {
maxValue = value;
maxBinX = i;
maxBinY = j;
}
}
}
int[] result = {minBinX,minBinY, maxBinX,maxBinY};
return result;
}
public IHistogram1D projectionX()
{
String newTitle = title() + " (projectionX)";
//return internalSliceX(newTitle,yAxis.under,yAxis.over);
return internalSliceX(newTitle,mapY(IHistogram.UNDERFLOW),mapY(IHistogram.OVERFLOW));
}
public IHistogram1D projectionY()
{
String newTitle = title() + " (projectionY)";
//return internalSliceY(newTitle,xAxis.under,xAxis.over);
return internalSliceY(newTitle,mapX(IHistogram.UNDERFLOW),mapX(IHistogram.OVERFLOW));
}
public IHistogram1D sliceX(int indexY)
{
//int start = yAxis.map(indexY);
int start = mapY(indexY);
String newTitle = title() + " (sliceX ["+indexY+"])";
return internalSliceX(newTitle,start,start);
}
public IHistogram1D sliceX(int indexY1, int indexY2)
{
//int start = yAxis.map(indexY1);
//int stop = yAxis.map(indexY2);
int start = mapY(indexY1);
int stop = mapY(indexY2);
String newTitle = title() + " (sliceX ["+indexY1+":"+indexY2+"])";
return internalSliceX(newTitle,start,stop);
}
public IHistogram1D sliceY(int indexX)
{
//int start = xAxis.map(indexX);
int start = mapX(indexX);
String newTitle = title() + " (sliceY ["+indexX+"])";
return internalSliceY(newTitle,start,start);
}
public IHistogram1D sliceY(int indexX1, int indexX2)
{
//int start = xAxis.map(indexX1);
//int stop = xAxis.map(indexX2);
int start = mapX(indexX1);
int stop = mapX(indexX2);
String newTitle = title() + " (slicey ["+indexX1+":"+indexX2+"])";
return internalSliceY(newTitle,start,stop);
}
public double sumAllBinHeights()
{
double n = 0;
for (int i=xAxis.bins(); --i >= -2;)
for (int j=yAxis.bins(); --j >= -2;)
{
n += binHeight(i,j);
}
return n;
}
public double sumBinHeights()
{
double n = 0;
for (int i=0; i<xAxis.bins(); i++)
for (int j=0; j<yAxis.bins(); j++)
{
n += binHeight(i,j);
}
return n;
}
public double sumExtraBinHeights()
{
return sumAllBinHeights() - sumBinHeights();
}
public IAxis xAxis()
{
return xAxis;
}
public IAxis yAxis()
{
return yAxis;
}
}