package jas.hist;
import jas.plot.ColorMap;
import jas.plot.ColorMapAxis;
import jas.plot.CoordinateTransformation;
import jas.plot.DataAreaLayout;
import jas.plot.DateCoordinateTransformation;
import jas.plot.DoubleCoordinateTransformation;
import jas.plot.MutableLegendEntry;
import jas.plot.Overlay;
import jas.plot.OverlayContainer;
import jas.plot.PlotGraphics;
import jas.plot.Transformation;
import jas.plot.java2.PlotGraphics12;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.util.Observable;
import java.util.Observer;
class TwoDOverlay implements Overlay, MutableLegendEntry, Observer
{
protected OverlayContainer container;
private Color color;
private JASHist2DHistogramData parent;
private double[][] data;
private double binHeightFixed;
private double binWidthFixed;
private double xHigh;
private double xLow;
private double yHigh;
private double yLow;
private double zlogmin;
private double zmax;
private double zmin;
private int xBins;
private int yBins;
private ColorMapAxis colorMapAxis;
private ColorMap colorMap;
private boolean isColorMapAxisAdded = false;
double cx;
double cy;
double cw;
double ch;
int c_mode, s_mode;
TwoDOverlay(JASHist2DHistogramData parent)
{
this.color = Color.black;
this.parent = parent;
parent.style.addObserver(this);
colorMap = new ColorMap(parent.style);
colorMapAxis = new ColorMapAxis(colorMap);
styleChanged(parent.style);
}
private void styleChanged(JASHist2DHistogramStyle style) {
s_mode = style.getHistStyle();
c_mode = style.getColorMapScheme();
if ( s_mode != 0 && s_mode!= 1 ) {
if ( ! isColorMapAxisAdded )
parent.parent.da.add(colorMapAxis,DataAreaLayout.Y_AXIS_RIGHT);
isColorMapAxisAdded = true;
} else if ( isColorMapAxisAdded ) {
parent.parent.da.remove(colorMapAxis);
isColorMapAxisAdded = false;
}
}
public void update(Observable o, Object arg) {
styleChanged((JASHist2DHistogramStyle) o);
}
public void setTitle(String newTitle)
{
parent.setLegendText(newTitle);
}
public String getTitle()
{
return parent.getLegendText();
}
public void containerNotify(OverlayContainer c)
{
this.container = c;
}
// Use local coordinates here
boolean isInClip(Transformation xt, Transformation yt, double Lx1, double Ly1, double Lx2, double Ly2) {
double Gx1 = xt.convert(Lx1);
double Gy1 = yt.convert(Ly1);
double Gx2 = xt.convert(Lx2);
double Gy2 = yt.convert(Ly2);
if (Gx2 < Gx1)
{ double xTmp = Gx1; Gx1 = Gx2; Gx2 = xTmp; }
if (Gy2 < Gy1)
{ double yTmp = Gy1; Gy1 = Gy2; Gy2 = yTmp; }
double Gw = Gx2 - Gx1 + 5.;
double Gh = Gy2 - Gy1 + 5.;
boolean ok = false;
double dGx = cx + (cw - Gx2 - Gx1)*0.5;
double dGy = cy + (ch - Gy2 - Gy1)*0.5;
double dGw = (cw + Gw)*0.5;
double dGh = (ch + Gh)*0.5;
if (Math.abs(dGx) <= dGw && Math.abs(dGy) <= dGh) ok = true;
//System.out.println("\t\tIntersects="+ok+", dx="+dGx+", dGy="+dGy+", dGw="+Gw+", dGh="+Gh);
//System.out.println("\t\t\t\t x1="+ Lx1+", x2="+ Lx2+", y1="+ Ly1+", y2="+ Ly2);
//System.out.println("\t\t\t\tGx1="+Gx1+", Gx2="+Gx2+", Gy1="+Gy1+", Gy2="+Gy2);
return ok;
}
public void paint(PlotGraphics g, boolean isPrinting)
{
//Disable antialiasing for 2D plots. The original rendering hints are set back
//at the end of the paint method.
RenderingHints oldRh = null;
if ( g instanceof PlotGraphics12 ) {
oldRh = ((PlotGraphics12)g).graphics().getRenderingHints();
RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
((PlotGraphics12)g).graphics().setRenderingHints(rh);
}
boolean doClipCheck = true;
Rectangle rect = g.getClipBounds();
if (rect == null) {
doClipCheck = false;
} else {
cx = (double) rect.x;
cy = (double) rect.y;
cw = (double) rect.width;
ch = (double) rect.height;
}
/////////Begin Test Area////////
s_mode = parent.style.getHistStyle();
c_mode = parent.style.getColorMapScheme();
boolean log = parent.style.getLogZ();
boolean uoState = false; //parent.style.getShowOverFlow();
boolean showZeroHeightBins = parent.style.getShowZeroHeightBins();
//boolean showGrid = true;
/////////End Test Area/////////
if (data == null)
{
return;
}
final int x_bins = xBins;
final int y_bins = yBins;
CoordinateTransformation xp = container.getXTransformation();
final CoordinateTransformation yp = container.getYTransformation();
if (xp instanceof DateCoordinateTransformation)
{
xp = new DateTransformationConverter((DateCoordinateTransformation) xp);
}
if (xp instanceof DoubleCoordinateTransformation && yp instanceof DoubleCoordinateTransformation) {
double[] binXEdges = null;
double[] binYEdges = null;
if (parent.getDataSource() instanceof Rebinnable2DVariableHistogramData) {
binXEdges = ((Rebinnable2DVariableHistogramData) parent.getDataSource()).getXBinEdges();
binYEdges = ((Rebinnable2DVariableHistogramData) parent.getDataSource()).getYBinEdges();
}
final DoubleCoordinateTransformation xt = (DoubleCoordinateTransformation) xp;
final DoubleCoordinateTransformation yt = (DoubleCoordinateTransformation) yp;
g.setTransformation(xt, yt);
//////Set Background/////
if ((s_mode == 0) || (s_mode == 1)) //Box/Ellipse Selected
{
g.setColor(Color.white);
}
else
{
/*
if (c_mode == 0)
{ //Warm selected
g.setColor(Color.red);
}
else if ((c_mode == 1) || (c_mode == 3))
{ //Cool/Rainbow Selected
//g.setColor(Color.black);
}
else if ((c_mode == 2) || (c_mode == 4))
{ //Thermal/GrayScale Selected
g.setColor(Color.blue);
}
else if (c_mode == 5)
{ //SelectRange Selected
g.setColor(parent.style.getStartDataColor());
}
else
{
// Do something here...
}
g.fillRect(xLow, yHigh, xHigh, yLow);
*/
}
////////// Show overflow and underflow bins /////////
// FIXME: Does not seem right
if (((s_mode == 0) || (s_mode == 1)) && (uoState == true)) {
g.setColor(Color.black);
g.drawLine(xt.convert(xLow + binWidthFixed), yt.convert(yLow), xt.convert(xLow + binWidthFixed), yt.convert(yHigh));
g.drawLine(xt.convert(xHigh - binWidthFixed), yt.convert(yLow), xt.convert(xHigh - binWidthFixed), yt.convert(yHigh));
g.drawLine(xt.convert(xLow), yt.convert(yLow + binHeightFixed), xt.convert(xHigh), yt.convert(yLow +binHeightFixed));
g.drawLine(xt.convert(xLow), yt.convert(yHigh - binHeightFixed), xt.convert(xHigh), yt.convert(yHigh- binHeightFixed));
}
//////////Grid Lines on the Pane/////////
/*
if ( ((s_mode == 0) || (s_mode == 1)) && showGrid ) {
g.setColor(Color.black);
double yGrid = yLow;
double xGrid = xLow;
for (int j = 0; j < y_bins; j++) {
double binHeight = (binYEdges == null) ? binWidthFixed : binYEdges[j+1] - binYEdges[j];
yGrid += binHeight;
g.drawLine(xt.convert(xLow), yt.convert(yGrid), xt.convert(xHigh), yt.convert(yGrid));
}
for (int i = 0; i < x_bins; i++) {
double binWidth = (binXEdges == null) ? binWidthFixed : binXEdges[i+1] - binXEdges[i];
xGrid += binWidth;
g.drawLine(xt.convert(xGrid), yt.convert(yLow), xt.convert(xGrid), yt.convert(yHigh));
}
}
*/
///////End Set Background////
// make sure that zero is included in the Z axis range
double dispZmin = zmin;
double dispZmax = zmax;
if (log)
{
dispZmin = Math.log(zlogmin);
dispZmax = Math.log(zmax);
}
else
{
if ((dispZmin > 0) && (dispZmax > 0))
{
dispZmin = 0;
}
if ((dispZmin < 0) && (dispZmax < 0))
{
dispZmax = 0;
}
}
double zrange = dispZmax - dispZmin;
if (zrange > 0)
{
double binHeight = binHeightFixed;
double binWidth = binWidthFixed;
g.setColor(parent.style.getShapeColor());
double y = yLow;
for (int j = 0; j < y_bins; j++)
{
if (binYEdges != null) binHeight = binYEdges[j+1] - binYEdges[j];
y += binHeight/2;
double x = xLow;
for (int i = 0; i < x_bins; i++)
{
if (binXEdges != null) binWidth = binXEdges[i+1] - binXEdges[i];
x += binWidth/2;
double size = 0;
if ((s_mode == 0) || (s_mode == 1))
size = log ? Math.sqrt((Math.log(data[i][j]) - dispZmin) / zrange) : Math.sqrt((data[i][j] - dispZmin) / zrange);
else
size = 1.;
double xFact = (binWidth * size) / 2;
double yFact = (binHeight * size) / 2;
// We dont want anything to appear if size is exactly 0
if (size == 0)
{
x += binWidth/2;
continue;
}
double x1 = x - binWidth/2;
double y1 = y - binHeight/2;
double x2 = x + binWidth/2;
double y2 = y + binHeight/2;
if (doClipCheck && !isInClip(xt, yt, x1, y1, x2, y2)) { x += binWidth/2; continue; }
x1 = x - xFact;
y1 = y - yFact;
x2 = x + xFact;
y2 = y + yFact;
if (s_mode == 0)
{
g.drawRect(x1, y1, x2, y2);
}
else if (s_mode == 1)
{
g.drawOval(x1, y1, x2, y2);
}
else // Color Map mode (s_mode == 2)
{
double colorSize = log ? ((Math.log(data[i][j]) - dispZmin) / zrange) : ((data[i][j] - dispZmin) / zrange);
if ( (showZeroHeightBins || colorSize != 0) && colorSize != Double.NEGATIVE_INFINITY ) {
g.setColor(colorMap.getColor(colorSize));
g.fillRect(x1, y1, x2, y2);
}
}
x += binWidth/2;
}
y += binHeight/2;
}
}
else if (zrange == 0)
{
// empty histogram, so nothing to do
}
}
// else zrange < 0 (should not occur)
if ( oldRh != null )
((PlotGraphics12)g).graphics().setRenderingHints(oldRh);
}
//paint()
public void paintIcon(PlotGraphics g, int width, int height)
{
g.setColor(parent.style.getShapeColor());
g.fillRect(1, 1, width - 2, height - 2);
}
public boolean titleIsChanged()
{
return parent.isLegendChanged();
}
void setData(double[][] data, double xLow, double xHigh, double yLow, double yHigh, int xBins, int yBins)
{
this.data = data;
this.xBins = xBins;
this.yBins = yBins;
this.xLow = xLow;
this.xHigh = xHigh;
this.yLow = yLow;
this.yHigh = yHigh;
binWidthFixed = Math.abs(xHigh - xLow) / xBins;
binHeightFixed = Math.abs(yHigh - yLow) / yBins;
}
void setZMinMax(double zMin, double zMax, double zLogMin)
{
boolean log = parent.style.getLogZ();
this.zmin = zMin;
this.zlogmin = zLogMin;
this.zmax = zMax;
colorMapAxis.setZminZmax(zmin, zmax);
colorMapAxis.setLogarithmic(log);
}
}