1021 lines
29 KiB
Java
1021 lines
29 KiB
Java
package density;
|
|
|
|
import java.awt.Canvas;
|
|
import java.awt.Color;
|
|
import java.awt.Dimension;
|
|
import java.awt.Font;
|
|
import java.awt.FontMetrics;
|
|
import java.awt.Graphics;
|
|
import java.awt.Graphics2D;
|
|
import java.awt.Rectangle;
|
|
import java.awt.image.BufferedImage;
|
|
import java.awt.image.DataBufferInt;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.text.DecimalFormat;
|
|
import java.text.NumberFormat;
|
|
|
|
import javax.imageio.ImageIO;
|
|
|
|
// Referenced classes of package density:
|
|
// GridDimension, LazyGrid, Grid, Utils,
|
|
// Sample
|
|
|
|
public class WorldImageProducer extends Canvas
|
|
{
|
|
|
|
public boolean gridnull = false;
|
|
public BufferedImage img;
|
|
public int scale;
|
|
public int mode;
|
|
public static final int LOG = 0;
|
|
public static final int PLAIN = 1;
|
|
public static final int CLASS = 2;
|
|
public int classColor[];
|
|
public String className[];
|
|
public Grid grid;
|
|
public boolean blackandwhite;
|
|
public boolean redandyellow;
|
|
public boolean dichromatic;
|
|
public Color dichromaticColors[];
|
|
public static boolean toggleSampleColor = true;
|
|
public int background;
|
|
public double breakpoint;
|
|
public int pixels[];
|
|
public int minx;
|
|
public int maxx;
|
|
public int miny;
|
|
public int maxy;
|
|
public Sample samples[];
|
|
public Sample testsamples[];
|
|
public boolean visible;
|
|
public boolean makeLegend;
|
|
public boolean makeTimeline=false;
|
|
|
|
public String initialTimeLabel;
|
|
public String timeLabel;
|
|
public int maxTimeIntervals;
|
|
public int timeIndex;
|
|
|
|
public static boolean setNumCategoriesByMax = false;
|
|
public static boolean makeNorth = false;
|
|
public static int defaultSampleRadius = 7;
|
|
public static int adjustSampleRadius = 0;
|
|
public static int numCategories = 14;
|
|
public static double categories[] = null;
|
|
public static int maxFracDigits = -1;
|
|
public static double divisor = 2D;
|
|
public double minval;
|
|
public double maxval;
|
|
public int xOffset;
|
|
public int yOffset;
|
|
public static double xline = -1D;
|
|
public static double yline = -1D;
|
|
public int linerow;
|
|
public int linecol;
|
|
public int white;
|
|
public int black;
|
|
public int sampleColor;
|
|
public int testSampleColor;
|
|
public int sampleRadius;
|
|
public double min;
|
|
public double max;
|
|
public int maxborder;
|
|
public int bdist[][];
|
|
public static boolean addTinyVals = true;
|
|
|
|
double aspect(int x1, int x2, int y1, int y2)
|
|
{
|
|
return (double)(y2 - y1) / (double)(x2 - x1);
|
|
}
|
|
|
|
void setZoom(int x1, int x2, int y1, int y2)
|
|
{
|
|
minx = x1 >= x2 ? x2 : x1;
|
|
maxx = x1 <= x2 ? x2 : x1;
|
|
miny = y1 >= y2 ? y2 : y1;
|
|
maxy = y1 <= y2 ? y2 : y1;
|
|
if(nozoom())
|
|
{
|
|
return;
|
|
}
|
|
double target = aspect(0, getCols(), 0, getRows());
|
|
if(aspect(minx, maxx, miny, maxy) < target)
|
|
{
|
|
maxy = miny + (int)(target * (double)(maxx - minx));
|
|
} else
|
|
{
|
|
maxx = minx + (int)((double)(maxy - miny) / target);
|
|
}
|
|
}
|
|
|
|
void zoomOut()
|
|
{
|
|
if(nozoom())
|
|
{
|
|
return;
|
|
}
|
|
if(minx == 0 && maxx == getCols() && miny == 0 && maxy == getRows())
|
|
{
|
|
return;
|
|
} else
|
|
{
|
|
minx = 0;
|
|
maxx = getCols();
|
|
miny = 0;
|
|
maxy = getRows();
|
|
makeImage();
|
|
return;
|
|
}
|
|
}
|
|
|
|
public void setClassNames(String s)
|
|
{
|
|
setClassNames(s.split(":"));
|
|
}
|
|
|
|
public void setClassNames(String s[])
|
|
{
|
|
className = s;
|
|
if(minval == -1D)
|
|
{
|
|
minval = 0.0D;
|
|
maxval = className.length - 1;
|
|
numCategories = className.length;
|
|
} else
|
|
{
|
|
numCategories = (int)((maxval - minval) + 1.0D);
|
|
}
|
|
mode = 1;
|
|
}
|
|
|
|
int[] stringToColors(String s)
|
|
{
|
|
String colors[] = s.split(" ");
|
|
int result[] = new int[colors.length];
|
|
for(int i = 0; i < colors.length; i++)
|
|
{
|
|
if(colors[i].indexOf("|") != -1)
|
|
{
|
|
String rgb[] = colors[i].split("\\|");
|
|
int rgbi[] = new int[3];
|
|
for(int j = 0; j < 3; j++)
|
|
{
|
|
rgbi[j] = Integer.parseInt(rgb[j]);
|
|
}
|
|
|
|
result[i] = (new Color(rgbi[0], rgbi[1], rgbi[2])).getRGB();
|
|
continue;
|
|
}
|
|
try
|
|
{
|
|
result[i] = Integer.decode(colors[i]).intValue();
|
|
continue;
|
|
}
|
|
catch(NumberFormatException e) { }
|
|
try
|
|
{
|
|
result[i] = ((Color)Class.forName("java.awt.Color").getField(colors[i]).get(null)).getRGB();
|
|
}
|
|
catch(Exception ee)
|
|
{
|
|
throw new NumberFormatException((new StringBuilder()).append("Invalid color: ").append(colors[i]).toString());
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public void setColorClasses(String s)
|
|
{
|
|
classColor = stringToColors(s);
|
|
mode = 2;
|
|
}
|
|
|
|
static void setCategories(String s)
|
|
{
|
|
String cats[] = s.split(" ");
|
|
categories = new double[cats.length];
|
|
for(int i = 0; i < cats.length; i++)
|
|
{
|
|
categories[i] = Double.parseDouble(cats[i]);
|
|
}
|
|
|
|
numCategories = cats.length;
|
|
}
|
|
|
|
void setline()
|
|
{
|
|
linerow = linecol = -1;
|
|
if(xline != -1D)
|
|
{
|
|
linerow = grid.getDimension().toRow(xline) * scale;
|
|
}
|
|
if(yline != -1D)
|
|
{
|
|
linecol = grid.getDimension().toCol(yline) * scale;
|
|
}
|
|
}
|
|
|
|
public void setMinval(double m)
|
|
{
|
|
minval = m;
|
|
}
|
|
|
|
public void setMaxval(double m)
|
|
{
|
|
maxval = m;
|
|
}
|
|
|
|
public void setMode(int i)
|
|
{
|
|
mode = i;
|
|
}
|
|
|
|
void setBreakpoint(double x)
|
|
{
|
|
breakpoint = x;
|
|
}
|
|
|
|
void setColorScheme(int i)
|
|
{
|
|
blackandwhite = i == 0;
|
|
}
|
|
|
|
public void setGrid(Grid grid, int minrows, int mincols)
|
|
{
|
|
this.grid = grid;
|
|
scale = 1;
|
|
double xscale = Math.floor((double)mincols / (double)getCols());
|
|
double yscale = Math.floor((double)minrows / (double)getRows());
|
|
scale = (int)(xscale >= yscale ? yscale : xscale);
|
|
if(scale < 1)
|
|
{
|
|
scale = 1;
|
|
}
|
|
img = new BufferedImage(getCols(), getRows(), 1);
|
|
pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
|
|
setZoom(-1, -1, -1, -1);
|
|
setline();
|
|
if(blackandwhite)
|
|
{
|
|
newborder();
|
|
}
|
|
}
|
|
|
|
void setSamples(Sample s[])
|
|
{
|
|
samples = s;
|
|
}
|
|
|
|
public void setTestSamples(Sample s[])
|
|
{
|
|
testsamples = s;
|
|
}
|
|
|
|
double max(double x, double y)
|
|
{
|
|
return x <= y ? y : x;
|
|
}
|
|
|
|
public void setTime(int maxTimeFrames, int timeFrame,String initialTimeLabel,String currentTimeLabel){
|
|
maxTimeIntervals=maxTimeFrames;
|
|
timeIndex=timeFrame;
|
|
this.initialTimeLabel=initialTimeLabel;
|
|
this.timeLabel=currentTimeLabel;
|
|
}
|
|
|
|
GridDimension viewDimension()
|
|
{
|
|
GridDimension dim = grid.getDimension();
|
|
double cs = dim.getcellsize() / (double)scale;
|
|
return new GridDimension(dim.getxllcorner() + max(minx, 0.0D) * cs, dim.getyllcorner() + (double)(maxy != -1 ? getRows() - maxy : 0) * cs, cs * (maxx != -1 ? (double)(maxx - minx) / (double)getCols() : 1.0D), getRows(), getCols());
|
|
}
|
|
|
|
int getRows()
|
|
{
|
|
if (grid!=null)
|
|
return scale * grid.getDimension().nrows;
|
|
else
|
|
return scale * 480;
|
|
}
|
|
|
|
int getCols()
|
|
{
|
|
if (grid!=null)
|
|
return scale * grid.getDimension().ncols;
|
|
else
|
|
return scale * 640;
|
|
}
|
|
|
|
boolean inBounds(int r, int c)
|
|
{
|
|
return r >= 0 && r < getRows() && c >= 0 && c < getCols();
|
|
}
|
|
|
|
public WorldImageProducer(Grid grid, int minrows, int mincols)
|
|
{
|
|
blackandwhite = false;
|
|
redandyellow = false;
|
|
dichromatic = false;
|
|
dichromaticColors = (new Color[] {
|
|
Color.red, Color.blue
|
|
});
|
|
breakpoint = -9999D;
|
|
minx = -1;
|
|
maxx = -1;
|
|
miny = -1;
|
|
maxy = -1;
|
|
samples = null;
|
|
testsamples = null;
|
|
visible = true;
|
|
makeLegend = true;
|
|
minval = -1D;
|
|
maxval = -1D;
|
|
xOffset = -1;
|
|
yOffset = -1;
|
|
white = -1;
|
|
black = Color.black.getRGB();
|
|
sampleColor = white;
|
|
testSampleColor = 0xff8a2be2;
|
|
sampleRadius = defaultSampleRadius;
|
|
min = 0.0D;
|
|
max = 0.0D;
|
|
maxborder = 5;
|
|
setGrid(grid, minrows, mincols);
|
|
}
|
|
|
|
public WorldImageProducer(Grid grid)
|
|
{
|
|
blackandwhite = false;
|
|
redandyellow = false;
|
|
dichromatic = false;
|
|
dichromaticColors = (new Color[] {
|
|
Color.red, Color.blue
|
|
});
|
|
breakpoint = -9999D;
|
|
minx = -1;
|
|
maxx = -1;
|
|
miny = -1;
|
|
maxy = -1;
|
|
samples = null;
|
|
testsamples = null;
|
|
visible = true;
|
|
makeLegend = true;
|
|
minval = -1D;
|
|
maxval = -1D;
|
|
xOffset = -1;
|
|
yOffset = -1;
|
|
white = -1;
|
|
black = Color.black.getRGB();
|
|
sampleColor = white;
|
|
testSampleColor = 0xff8a2be2;
|
|
sampleRadius = defaultSampleRadius;
|
|
min = 0.0D;
|
|
max = 0.0D;
|
|
maxborder = 5;
|
|
if (grid!=null){
|
|
setGrid(grid, 1200, 1600);
|
|
}
|
|
else
|
|
gridnull=true;
|
|
}
|
|
|
|
boolean nozoom()
|
|
{
|
|
return minx == -1 || maxx == -1 || miny == -1 || maxy == -1;
|
|
}
|
|
|
|
int windowx2imgx(int x)
|
|
{
|
|
return (int)(((double)getCols() / (double)getSize().width) * (double)x);
|
|
}
|
|
|
|
int windowy2imgy(int y)
|
|
{
|
|
return (int)(((double)getRows() / (double)getSize().height) * (double)y);
|
|
}
|
|
|
|
int gridrow(int r)
|
|
{
|
|
if(nozoom())
|
|
{
|
|
return r / scale;
|
|
} else
|
|
{
|
|
int rr = (int)((double)miny + ((double)r / (double)getRows()) * (double)(maxy - miny));
|
|
return rr / scale;
|
|
}
|
|
}
|
|
|
|
int gridcol(int c)
|
|
{
|
|
if(nozoom())
|
|
{
|
|
return c / scale;
|
|
} else
|
|
{
|
|
int cc = (int)((double)minx + ((double)c / (double)getCols()) * (double)(maxx - minx));
|
|
return cc / scale;
|
|
}
|
|
}
|
|
|
|
boolean hasData(int r, int c)
|
|
{
|
|
if (!gridnull)
|
|
return grid.hasData(gridrow(r), gridcol(c));
|
|
else
|
|
return false;
|
|
}
|
|
|
|
float eval(int r, int c)
|
|
{
|
|
return grid.eval(gridrow(r), gridcol(c));
|
|
}
|
|
|
|
public void makeImage()
|
|
{
|
|
boolean start = true;
|
|
background = redandyellow ? 0x8080ff : blackandwhite ? white : 0xff000000;
|
|
|
|
if(minval != -1D || maxval != -1D)
|
|
{
|
|
min = minval;
|
|
max = maxval;
|
|
} else
|
|
{
|
|
for(int i = 0; i < getRows(); i++)
|
|
{
|
|
for(int j = 0; j < getCols(); j++)
|
|
{
|
|
if(!hasData(i, j))
|
|
{
|
|
continue;
|
|
}
|
|
if(start)
|
|
{
|
|
min = max = eval(i, j);
|
|
start = false;
|
|
continue;
|
|
}
|
|
float val = eval(i, j);
|
|
if((double)val < min && (mode != 0 || val > 0.0F) || min <= 0.0D && mode == 0)
|
|
{
|
|
min = val;
|
|
}
|
|
if((double)val > max)
|
|
{
|
|
max = val;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if(grid instanceof LazyGrid)
|
|
{
|
|
try
|
|
{
|
|
((LazyGrid)grid).initialize();
|
|
}
|
|
catch(IOException e)
|
|
{
|
|
Utils.fatalException((new StringBuilder()).append("Error initializing file ").append(grid.name).toString(), null);
|
|
}
|
|
}
|
|
}
|
|
if(max == 100D && min >= 0.0D && min < 1.0000000000000001E-005D)
|
|
{
|
|
min = 1.0000000000000001E-005D;
|
|
}
|
|
if(max == 100D && min >= 0.0D && min < 0.001D && blackandwhite)
|
|
{
|
|
min = 0.01D;
|
|
}
|
|
if(min > 0.0D && max / min > 1000000000000000D)
|
|
{
|
|
min = max / 1000000000000000D;
|
|
}
|
|
if(min >= 0.0D && min <= 0.10000000000000001D && max >= 0.69999999999999996D && max <= 1.0D && mode != 0 && maxval == -1D)
|
|
{
|
|
min = 0.0D;
|
|
max = 1.0D;
|
|
numCategories = 11;
|
|
}
|
|
for(int i = 0; i < getRows(); i++)
|
|
{
|
|
Utils.reportProgress((double)(i * 100) / (double)getRows());
|
|
for(int j = 0; j < getCols(); j++)
|
|
{
|
|
pixels[i * getCols() + j] = i != linerow ? j != linecol ? hasData(i, j) ? showColor(eval(i, j), min, max) : !blackandwhite || !isborder(i, j) ? background : black : white : white;
|
|
if (pixels[i * getCols() + j] == black && !blackandwhite) //patch by Gianpaolo Coro to exclude black colors
|
|
pixels[i * getCols() + j] = Color.LIGHT_GRAY.getRGB();
|
|
}
|
|
|
|
}
|
|
|
|
int sr = sampleRadius;
|
|
int rr = getRows() * scale;
|
|
int cc = getCols() * scale;
|
|
if(scale > 1)
|
|
{
|
|
sr = (int)Math.ceil((double)sr / (double)scale);
|
|
}
|
|
if(rr < 900 && cc < 900 && sr * scale >= 5 && sr > 2)
|
|
{
|
|
sr -= 2;
|
|
}
|
|
if(rr < 600 && cc < 600 && sr * scale >= 5 && sr > 2)
|
|
{
|
|
sr -= 2;
|
|
}
|
|
if(rr < 300 && cc < 300 && sr * scale >= 5 && sr > 2)
|
|
{
|
|
sr -= 2;
|
|
}
|
|
if(rr > 2000 || cc > 2000)
|
|
{
|
|
sr += 1 / scale;
|
|
}
|
|
if(rr > 4000 || cc > 4000)
|
|
{
|
|
sr += 1 / scale;
|
|
}
|
|
sr += adjustSampleRadius;
|
|
if(samples != null)
|
|
{
|
|
showSamples(samples, sampleColor, sr);
|
|
}
|
|
if(testsamples != null)
|
|
{
|
|
showSamples(testsamples, testSampleColor, sr);
|
|
}
|
|
if(makeLegend)
|
|
{
|
|
makeLegend();
|
|
}
|
|
if(makeNorth)
|
|
{
|
|
makeNorth();
|
|
}
|
|
if(visible)
|
|
{
|
|
repaint();
|
|
}
|
|
if(makeTimeline)
|
|
makeTimeline(maxTimeIntervals,timeIndex,initialTimeLabel,timeLabel);
|
|
|
|
}
|
|
|
|
void newborder()
|
|
{
|
|
int nr = getRows();
|
|
int nc = getCols();
|
|
bdist = new int[nr][nc];
|
|
for(int i = 0; i < getRows(); i++)
|
|
{
|
|
for(int j = 0; j < getCols(); j++)
|
|
{
|
|
bdist[i][j] = hasData(i, j) ? 0 : 0x186a0;
|
|
}
|
|
|
|
}
|
|
|
|
for(int iter = 0; iter < maxborder; iter++)
|
|
{
|
|
for(int i = 0; i < nr; i++)
|
|
{
|
|
for(int j = 0; j < nc; j++)
|
|
{
|
|
for(int id = -1; id <= 1; id += 2)
|
|
{
|
|
for(int jd = -1; jd <= 1; jd += 2)
|
|
{
|
|
int ii = i + id;
|
|
int jj = j + jd;
|
|
if(ii >= 0 && jj >= 0 && ii < nr && jj < nc && bdist[ii][jj] < bdist[i][j] - 1)
|
|
{
|
|
bdist[i][j] = bdist[ii][jj] + 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
boolean isborder(int i, int j)
|
|
{
|
|
return bdist[i][j] < maxborder;
|
|
}
|
|
|
|
void showSamples(Sample samples[], int color, int sr)
|
|
{
|
|
GridDimension dim = viewDimension();
|
|
int under[] = null;
|
|
if(blackandwhite && toggleSampleColor)
|
|
{
|
|
under = (int[])(int[])pixels.clone();
|
|
}
|
|
for(int i = 0; i < samples.length; i++)
|
|
{
|
|
if (samples[i]==null)
|
|
continue;
|
|
int r = samples[i].getRow(dim);
|
|
int c = samples[i].getCol(dim);
|
|
int color2 = color;
|
|
if(blackandwhite && toggleSampleColor)
|
|
{
|
|
int cnt = 0;
|
|
int tot = 0;
|
|
for(int j = (-sr + 1) * scale; j < sr * scale; j++)
|
|
{
|
|
for(int k = (-sr + 1) * scale; k < sr * scale; k++)
|
|
{
|
|
if(inBounds(r + j, c + k))
|
|
{
|
|
cnt++;
|
|
tot += (new Color(under[(r + j) * getCols() + (c + k)])).getBlue();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if(cnt > 0 && tot / cnt > 128)
|
|
{
|
|
color2 = black;
|
|
}
|
|
} else
|
|
if(blackandwhite)
|
|
{
|
|
color2 = black;
|
|
}
|
|
for(int j = (-sr + 1) * scale; j < sr * scale; j++)
|
|
{
|
|
for(int k = (-sr + 1) * scale; k < sr * scale; k++)
|
|
{
|
|
if(inBounds(r + j, c + k))
|
|
{
|
|
pixels[(r + j) * getCols() + (c + k)] = color2;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void makeTimeline(int maxtimeframes, int timeidx, String initialTimeLabel, String timeLabel)
|
|
{
|
|
|
|
int num = timeidx+1;
|
|
int fontSize = getRows() <= 2000 && getCols() <= 2000 ? ((int) (getRows() <= 1000 && getCols() <= 1000 ? 11 : 18)) : 24;
|
|
|
|
Graphics2D image = (Graphics2D)img.getGraphics();
|
|
Font font = new Font("Dialog", 1, fontSize);
|
|
image.setFont(font);
|
|
FontMetrics fm = image.getFontMetrics(font);
|
|
// int height = fm.getHeight() + 2;
|
|
String labels[] = new String[timeidx+1];
|
|
labels[0] = initialTimeLabel;
|
|
labels[timeidx] = timeLabel;
|
|
int w = fm.stringWidth(labels[timeidx]);
|
|
int width = fm.getWidths()[0] + w;
|
|
int heigh = fm.getWidths()[0] ;
|
|
|
|
//computeOffsets(maxtimeframes + 6 + 2 * height, (timeidx+1 + 2) * height);
|
|
int y = getRows()-50;
|
|
int x0 = (getCols()/2)-(maxtimeframes/2);
|
|
for(int i = 0; i < num; i++)
|
|
{
|
|
//((num - i) + 1) * (height-yOffset);
|
|
image.setColor(Color.white);
|
|
int x = (i+1) + x0;
|
|
if (!initialTimeLabel.equals(timeLabel))
|
|
{
|
|
image.fill(new Rectangle(x, y, width, heigh));
|
|
image.setColor(Color.white);
|
|
}
|
|
String label = labels[i]==null?"":labels[i];
|
|
if (i==0)
|
|
image.drawString(label, (x-width/2), (y +heigh+ 15));
|
|
else
|
|
image.drawString(label, (x+width), (y +heigh+ 15));
|
|
}
|
|
|
|
}
|
|
|
|
void makeLegend()
|
|
{
|
|
int num = setNumCategoriesByMax ? (int)max + 1 : numCategories;
|
|
double vals[] = categories != null ? categories : new double[num];
|
|
int fontSize = getRows() <= 2000 && getCols() <= 2000 ? ((int) (getRows() <= 1000 && getCols() <= 1000 ? 11 : 18)) : 24;
|
|
if(categories == null)
|
|
{
|
|
if(mode == 0)
|
|
{
|
|
double x = max;
|
|
if(max > 50D && max <= 100D)
|
|
{
|
|
for(int i = 0; i < num; i++)
|
|
{
|
|
vals[i] = x;
|
|
x /= divisor;
|
|
}
|
|
|
|
if(addTinyVals)
|
|
{
|
|
vals[num - 3] = 0.01D;
|
|
vals[num - 2] = 0.001D;
|
|
vals[num - 1] = min <= 0.0001D ? min : 0.0001D;
|
|
} else
|
|
{
|
|
vals[num - 1] = 0.0D;
|
|
}
|
|
} else
|
|
{
|
|
double div = Math.exp(Math.log(min >= max / 1000000000000000D ? max / min : 1000000000000000D) / (double)(num - 1));
|
|
for(int i = 0; i < num; i++)
|
|
{
|
|
vals[i] = x;
|
|
x /= div;
|
|
}
|
|
|
|
}
|
|
} else
|
|
{
|
|
for(int i = 0; i < num; i++)
|
|
{
|
|
vals[i] = max - ((double)i * (max - min)) / (double)(num - 1);
|
|
}
|
|
|
|
if(vals[num - 1] < 0.01D && vals[num - 2] > 1.0D)
|
|
{
|
|
vals[num - 1] = 0.0D;
|
|
}
|
|
}
|
|
if(min == max)
|
|
{
|
|
num = 1;
|
|
vals = (new double[] {
|
|
min
|
|
});
|
|
}
|
|
}
|
|
Graphics2D g = (Graphics2D)img.getGraphics();
|
|
Font font = new Font("Dialog", 1, fontSize);
|
|
g.setFont(font);
|
|
FontMetrics fm = g.getFontMetrics(font);
|
|
int height = fm.getHeight() + 2;
|
|
NumberFormat nf = ((NumberFormat) (max > 1.0D || mode == 0 ? NumberFormat.getNumberInstance() : ((NumberFormat) (new DecimalFormat()))));
|
|
nf.setGroupingUsed(false);
|
|
String labels[] = new String[num];
|
|
int legendWidth = 0;
|
|
for(int i = 0; i < num; i++)
|
|
{
|
|
if(max < 0.5D || max < 2D && mode == 0)
|
|
{
|
|
((DecimalFormat)nf).applyPattern("0.#E0");
|
|
} else
|
|
{
|
|
nf.setMaximumFractionDigits(maxFracDigits == -1 ? ((int) (vals[i] < 1.0D ? ((int) (vals[i] < 0.01D ? ((int) (vals[i] < 0.001D ? ((int) (vals[i] <= 0.0001D ? ((int) (vals[i] >= 0.0D ? 5 : 1)) : 4)) : 3)) : 2)) : 1)) : maxFracDigits);
|
|
}
|
|
labels[i] = className != null && (double)className.length > vals[i] ? className[(int)vals[i]] : nf.format(vals[i]);
|
|
int w = fm.stringWidth(labels[i]);
|
|
if(w > legendWidth)
|
|
{
|
|
legendWidth = w;
|
|
}
|
|
}
|
|
|
|
computeOffsets(legendWidth + 6 + 2 * height, (num + 2) * height);
|
|
for(int i = 0; i < num; i++)
|
|
{
|
|
int y = getRows() - ((num - i) + 1) * height - yOffset;
|
|
g.setColor(new Color(showColor(vals[i], min, max)));
|
|
g.fill(new Rectangle(xOffset + 4, y, height, height));
|
|
g.setColor(blackandwhite ? Color.black : Color.white);
|
|
g.drawString(labels[i], xOffset + 6 + height, (y + height) - 2);
|
|
}
|
|
|
|
}
|
|
|
|
void computeOffsets(int w, int h)
|
|
{
|
|
xOffset = 0;
|
|
yOffset = 0;
|
|
int overlap = computeOverlap(0, 0, w, h);
|
|
if(overlap == 0)
|
|
{
|
|
return;
|
|
}
|
|
int overlap2 = computeOverlap(getCols() - w, 0, w, h);
|
|
if(overlap2 < overlap)
|
|
{
|
|
overlap = overlap2;
|
|
xOffset = getCols() - w;
|
|
yOffset = 0;
|
|
}
|
|
if(overlap == 0)
|
|
{
|
|
return;
|
|
}
|
|
overlap2 = computeOverlap(getCols() - w, getRows() - h, w, h);
|
|
if(overlap2 < overlap)
|
|
{
|
|
overlap = overlap2;
|
|
xOffset = getCols() - w;
|
|
yOffset = getRows() - h;
|
|
}
|
|
if(overlap == 0)
|
|
{
|
|
return;
|
|
}
|
|
overlap2 = computeOverlap(0, getRows() - h, w, h);
|
|
if(overlap2 < overlap)
|
|
{
|
|
overlap = overlap2;
|
|
xOffset = 0;
|
|
yOffset = getRows() - h;
|
|
}
|
|
}
|
|
|
|
int computeOverlap(int llx, int lly, int w, int h)
|
|
{
|
|
int cnt = 0;
|
|
for(int y = lly; y < lly + h; y++)
|
|
{
|
|
for(int x = llx; x < llx + w; x++)
|
|
{
|
|
if(nonBackground(getRows() - y, x))
|
|
{
|
|
cnt++;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return cnt;
|
|
}
|
|
|
|
boolean nonBackground(int r, int c)
|
|
{
|
|
int i = r * getCols() + c;
|
|
return i >= 0 && i < pixels.length && pixels[i] != background;
|
|
}
|
|
|
|
void makeNorth()
|
|
{
|
|
Graphics2D g = (Graphics2D)img.getGraphics();
|
|
g.setColor(blackandwhite ? Color.black : Color.white);
|
|
Font font = new Font("Dialog", 1, 48);
|
|
g.setFont(font);
|
|
FontMetrics fm = g.getFontMetrics(font);
|
|
int height = fm.getHeight() + 2;
|
|
int nx = (int)((double)getCols() * 0.94999999999999996D);
|
|
g.drawString("N", nx, (int)((double)getRows() * 0.10000000000000001D) + height);
|
|
int x = nx + fm.stringWidth("N") / 2;
|
|
int yb = (int)((double)getRows() * 0.10000000000000001D - (double)height * 1.25D);
|
|
int yheight = (int)((double)getRows() * 0.050000000000000003D);
|
|
int w = 6;
|
|
g.fillRect(x - w / 2, yb, w, yheight);
|
|
g.fillPolygon(new int[] {
|
|
x, x + 3 * w, x - 3 * w
|
|
}, new int[] {
|
|
yb - w / 2, yb + 3 * w, yb + 3 * w
|
|
}, 3);
|
|
}
|
|
|
|
public void writeImage(String outFile)
|
|
{
|
|
writeImage(outFile, 1);
|
|
}
|
|
|
|
public void writeImage(String outFile, int magstep)
|
|
{
|
|
int ncols = getCols();
|
|
int nrows = getRows();
|
|
BufferedImage toWrite = magstep != 1 ? new BufferedImage(ncols * magstep, nrows * magstep, 1) : img;
|
|
if(magstep > 1)
|
|
{
|
|
int p[] = ((DataBufferInt)toWrite.getRaster().getDataBuffer()).getData();
|
|
for(int r = 0; r < nrows * magstep; r++)
|
|
{
|
|
for(int c = 0; c < ncols * magstep; c++)
|
|
{
|
|
p[r * ncols * magstep + c] = pixels[(r / magstep) * ncols + c / magstep];
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
try
|
|
{
|
|
ImageIO.write(toWrite, "png", new File(outFile));
|
|
}
|
|
catch(IOException e)
|
|
{
|
|
System.out.println((new StringBuilder()).append("Error: ").append(e.toString()).toString());
|
|
}
|
|
}
|
|
|
|
int showColor(double val, double min, double max)
|
|
{
|
|
if(mode == 2)
|
|
{
|
|
return classColor[(int)val];
|
|
}
|
|
if(mode == 0)
|
|
{
|
|
val = val > min ? Math.log(val) : Math.log(min);
|
|
min = min > 0.0D ? Math.log(min) : 0.0D;
|
|
max = max > 0.0D ? Math.log(max) : 0.0D;
|
|
}
|
|
if(val < min)
|
|
{
|
|
val = min;
|
|
}
|
|
if(val > max)
|
|
{
|
|
val = max;
|
|
}
|
|
if(dichromatic)
|
|
{
|
|
if(breakpoint == -9999D)
|
|
{
|
|
breakpoint = (max - min) / 2D;
|
|
}
|
|
double frac = val >= breakpoint ? (val - breakpoint) / (max - breakpoint) : (breakpoint - val) / (breakpoint - min);
|
|
int end = val >= breakpoint ? 1 : 0;
|
|
return fadedColor(dichromaticColors[end], frac);
|
|
}
|
|
int red;
|
|
int green;
|
|
int blue;
|
|
if(redandyellow)
|
|
{
|
|
if(breakpoint == -9999D)
|
|
{
|
|
breakpoint = 50D;
|
|
}
|
|
int index = (int)(((max - val) * 100D) / (max - min));
|
|
red = 255;
|
|
green = (int)((double)index >= breakpoint ? 255D : (double)(index * 255) / breakpoint);
|
|
blue = (int)((double)index >= breakpoint ? (((double)index - breakpoint) * 255D) / (511D - breakpoint) : 0.0D);
|
|
} else
|
|
if(blackandwhite)
|
|
{
|
|
double index = (max - val) / (max - min);
|
|
red = green = blue = (int)(220D * index) + 30;
|
|
} else
|
|
{
|
|
int i = (int)(((max - val) * 1020D) / (max - min));
|
|
red = i >= 256 ? i <= 510 ? 510 - i : 0 : 255;
|
|
green = i >= 256 ? i >= 765 ? 1020 - i : 255 : i;
|
|
blue = i >= 510 ? i >= 765 ? 255 : i - 510 : 0;
|
|
}
|
|
return 0xff000000 | red << 16 | green << 8 | blue;
|
|
}
|
|
|
|
int fadedColor(Color c, double frac)
|
|
{
|
|
int rgb[] = {
|
|
c.getRed(), c.getGreen(), c.getBlue()
|
|
};
|
|
for(int i = 0; i < 3; i++)
|
|
{
|
|
rgb[i] = rgb[i] + (int)((1.0D - frac) * (double)(255 - rgb[i]));
|
|
}
|
|
|
|
return (new Color(rgb[0], rgb[1], rgb[2])).getRGB();
|
|
}
|
|
|
|
public void paint(Graphics g)
|
|
{
|
|
int w = getSize().width;
|
|
int h = getSize().height;
|
|
if(img != null)
|
|
{
|
|
g.drawImage(img, 0, 0, w, h, this);
|
|
}
|
|
}
|
|
|
|
public void update(Graphics g)
|
|
{
|
|
paint(g);
|
|
}
|
|
|
|
public Dimension getPreferredSize()
|
|
{
|
|
return new Dimension(getCols(), getRows());
|
|
}
|
|
|
|
|
|
}
|