/*
* Open Source Physics software is free software as described near the bottom of this code file.
*
* For additional information and documentation on Open Source Physics please see:
* <http://www.opensourcephysics.org/>
*/
package org.opensourcephysics.display2d;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.util.Random;
import javax.swing.JFrame;
import org.opensourcephysics.display.DrawingPanel;
import org.opensourcephysics.display.Grid;
import org.opensourcephysics.display.MeasuredImage;
import org.opensourcephysics.display.OSPRuntime;
/**
* A BinaryLattice is an array where each array element has a value of 0 or 1.
*
* The lattice is drawn as an array of rectangles to distinguish between the two possible values.
*
* @author Wolfgang Christian
* @created February 11, 2003
* @version 1.0
*/
public class BinaryLattice extends MeasuredImage implements ByteLattice {
WritableRaster raster;
Grid grid;
byte[] packedData;
int ny, nx;
boolean visible = true;
Color zeroColor = Color.red, oneColor = Color.blue;
/**
* Constructs a binary lattice with the given size.
* @param _nx the number of values in x direction
* @param _ny the number of values in y direction
*/
public BinaryLattice(int _nx, int _ny) {
ny = _ny;
nx = _nx;
int len = ((nx+7)/8)*ny; // each row starts on a byte boundary
packedData = new byte[len];
DataBuffer databuffer = new DataBufferByte(packedData, len);
raster = Raster.createPackedRaster(databuffer, nx, ny, 1, null);
// default colors are red and blue
ColorModel colorModel = new IndexColorModel(1, 2, new byte[] {(byte) 255, (byte) 0}, new byte[] {(byte) 0, (byte) 0}, new byte[] {(byte) 0, (byte) 255});
image = new BufferedImage(colorModel, raster, false, null);
xmin = 0;
xmax = nx;
ymin = 0;
ymax = ny;
grid = new Grid(nx, ny, xmin, xmax, ymin, ymax);
grid.setColor(Color.lightGray);
}
/**
* Creates the default palette.
*/
public void createDefaultColors() {
zeroColor = Color.red;
oneColor = Color.blue;
}
/**
* Resize the lattice.
* @param _nx number of x sites
* @param _ny number of y sites
*/
public void resizeLattice(int _nx, int _ny) {
ny = _ny;
nx = _nx;
int len = ((nx+7)/8)*ny; // each row starts on a byte boundary
packedData = new byte[len];
DataBuffer databuffer = new DataBufferByte(packedData, len);
raster = Raster.createPackedRaster(databuffer, nx, ny, 1, null);
ColorModel colorModel = image.getColorModel();
image = new BufferedImage(colorModel, raster, false, null);
Color color = grid.getColor();
grid = new Grid(nx, ny, xmin, xmax, ymin, ymax);
setMinMax(xmin, xmax, ymin, ymax);
grid.setColor(color);
}
public void setXMin(double _value) {
super.setXMin(_value);
grid.setMinMax(xmin, xmax, ymin, ymax);
}
public void setXMax(double _value) {
super.setXMax(_value);
grid.setMinMax(xmin, xmax, ymin, ymax);
}
public void setYMin(double _value) {
super.setYMin(_value);
grid.setMinMax(xmin, xmax, ymin, ymax);
}
public void setYMax(double _value) {
super.setYMax(_value);
grid.setMinMax(xmin, xmax, ymin, ymax);
}
/**
* Randomizes the lattice values.
*/
public void randomize() {
Random random = new Random();
random.nextBytes(packedData);
}
/**
* Draws the lattice and the grid.
* @param panel
* @param g
*/
public void draw(DrawingPanel panel, Graphics g) {
if(!visible) {
return;
}
if (!OSPRuntime.isMac()) { //Rendering hint bug in Mac Snow Leopard
Graphics2D g2 = ((Graphics2D) g);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
}
super.draw(panel, g);
grid.draw(panel, g);
}
/**
* Sets a block of data to new values.
*
* The lattice is resized to fit the new data if needed.
*
* @param val
*/
public void setAll(byte val[][]) {
if((getNx()!=val.length)||(getNy()!=val[0].length)) {
resizeLattice(val.length, val[0].length);
}
setBlock(0, 0, val);
}
/**
* Sets the lattice values and scale.
*
* The lattice is resized to fit the new data if needed.
*
* @param val int[][] the new values
* @param xmin double
* @param xmax double
* @param ymin double
* @param ymax double
*/
public void setAll(byte val[][], double xmin, double xmax, double ymin, double ymax) {
setAll(val);
setMinMax(xmin, xmax, ymin, ymax);
}
/**
* Scales the grid to the given values in world units.
* @param xmin
* @param xmax
* @param ymin
* @param ymax
*/
public void setMinMax(double xmin, double xmax, double ymin, double ymax) {
super.setMinMax(xmin, xmax, ymin, ymax);
grid.setMinMax(xmin, xmax, ymin, ymax);
}
/**
* Sets a block of cells to new values.
*
* A cell is set to 1 if the value is >0; the cell is set to zero otherwise
*
* @param row_offset
* @param col_offset
* @param val the array of values
*/
/**
* Sets a block of cells to new values.
*
* A cell is set to 1 if the value is >0; the cell is set to zero otherwise
*
* @param x_offset int
* @param y_offset int
* @param val int[][]
*/
public void setBlock(int x_offset, int y_offset, int val[][]) {
if((y_offset<0)||(y_offset+val[0].length>ny)) {
throw new IllegalArgumentException("Row index out of range in binary lattice setBlock."); //$NON-NLS-1$
}
if((x_offset<0)||(x_offset+val.length>nx)) {
throw new IllegalArgumentException("Column index out of range in binary lattice setBlock."); //$NON-NLS-1$
}
for(int iy = y_offset, my = val[0].length+y_offset; iy<my; iy++) {
for(int ix = x_offset, mx = val.length+x_offset; ix<mx; ix++) {
int arrayIndex = (ny-iy-1)*((nx+7)/8)+ix/8; // each row starts on a byte boundary
byte packedcell = packedData[arrayIndex];
int mask = 0x80>>>(ix%8); // start with 0x10000000 and shift right
if(val[ix-x_offset][iy-y_offset]<=0) {
packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit
} else {
packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit
}
packedData[arrayIndex] = packedcell;
}
}
}
/**
* Sets a block of cells to new values.
*
* A cell is set to 1 if the value is >0; the cell is set to zero otherwise
*
* @param ix_offset
* @param iy_offset
* @param val the value array
*/
public void setBlock(int ix_offset, int iy_offset, byte val[][]) {
if((iy_offset<0)||(iy_offset+val[0].length>ny)) {
throw new IllegalArgumentException("Row index out of range in binary lattice setBlock."); //$NON-NLS-1$
}
if((ix_offset<0)||(ix_offset+val.length>nx)) {
throw new IllegalArgumentException("Column index out of range in binary lattice setBlock."); //$NON-NLS-1$
}
for(int iy = iy_offset, my = val[0].length+iy_offset; iy<my; iy++) {
for(int ix = ix_offset, mx = val.length+ix_offset; ix<mx; ix++) {
int arrayIndex = (ny-iy-1)*((nx+7)/8)+ix/8; // each row starts on a byte boundary
byte packedcell = packedData[arrayIndex];
int mask = 0x80>>>(ix%8); // start with 0x10000000 and shift right
if(val[ix-ix_offset][iy-iy_offset]<=0) {
packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit
} else {
packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit
}
packedData[arrayIndex] = packedcell;
}
}
}
/**
* Sets a block of data starting at (0,0) to new values.
*
* @param val
*/
public void setBlock(byte[][] val) {
setBlock(0, 0, val);
}
/**
* Sets a column of cells to new values.
*
* A cell is set to 1 if the value is >0; the cell is set to zero otherwise
*
* @param ix
* @param iy_offset
* @param val the array of values
*/
public void setCol(int ix, int iy_offset, int val[]) {
if((iy_offset<0)||(iy_offset+val.length>ny)) {
throw new IllegalArgumentException("Row index out of range in binary lattice setCol."); //$NON-NLS-1$
}
if((ix<0)||(ix>=nx)) {
throw new IllegalArgumentException("Column index out of range in binary lattice setCol."); //$NON-NLS-1$
}
for(int iy = iy_offset, nr = val.length+iy_offset; iy<nr; iy++) {
int arrayIndex = (ny-iy-1)*((nx+7)/8)+ix/8; // each row starts on a byte boundary
byte packedcell = packedData[arrayIndex];
int mask = 0x80>>>(ix%8); // start with 0x10000000 and shift right
if(val[iy-iy_offset]<=0) {
packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit
} else {
packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit
}
packedData[arrayIndex] = packedcell;
}
}
/**
* Sets a column of cells to new values.
*
* A cell is set to 1 if the value is >0; the cell is set to zero otherwise
*
* @param ix
* @param iy_offset
* @param val the array of values
*/
public void setCol(int ix, int iy_offset, byte val[]) {
if((iy_offset<0)||(iy_offset+val.length>ny)) {
throw new IllegalArgumentException("Row index out of range in binary lattice setCol."); //$NON-NLS-1$
}
if((ix<0)||(ix>=nx)) {
throw new IllegalArgumentException("Column index out of range in binary lattice setCol."); //$NON-NLS-1$
}
for(int iy = iy_offset, nr = val.length+iy_offset; iy<nr; iy++) {
int arrayIndex = (ny-iy-1)*((nx+7)/8)+ix/8; // each row starts on a byte boundary
byte packedcell = packedData[arrayIndex];
int mask = 0x80>>>(ix%8); // start with 0x10000000 and shift right
if(val[iy-iy_offset]<=0) {
packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit
} else {
packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit
}
packedData[arrayIndex] = packedcell;
}
}
/**
* Sets a row of cells to new values starting at the given column.
*
* A cell is set to 1 if the value is >0; the cell is set to zero otherwise
*
* @param iy
* @param ix_offset the x offset
* @param val the value array
*/
public void setRow(int iy, int ix_offset, int val[]) {
if((iy<0)||(iy>=ny)) {
throw new IllegalArgumentException("Row index out of range in binary lattice setRow."); //$NON-NLS-1$
}
if((ix_offset<0)||(ix_offset+val.length>nx)) {
throw new IllegalArgumentException("Column index out of range in binary lattice setRow."); //$NON-NLS-1$
}
for(int ix = ix_offset, nc = val.length+ix_offset; ix<nc; ix++) {
int arrayIndex = (ny-iy-1)*((nx+7)/8)+ix/8; // each row starts on a byte boundary
byte packedcell = packedData[arrayIndex];
int mask = 0x80>>>(ix%8); // start with 0x10000000 and shift right
if(val[ix-ix_offset]<=0) {
packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit
} else {
packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit
}
packedData[arrayIndex] = packedcell;
}
}
/**
* Sets a row of cells to new values starting at the given column.
*
* A cell is set to 1 if the value is >0; the cell is set to zero otherwise
*
* @param iy
* @param ix_offset the x offset
* @param val the value array
*/
public void setRow(int iy, int ix_offset, byte val[]) {
if((iy<0)||(iy>=ny)) {
throw new IllegalArgumentException("Row index out of range in binary lattice setRow."); //$NON-NLS-1$
}
if((ix_offset<0)||(ix_offset+val.length>nx)) {
throw new IllegalArgumentException("Column index out of range in binary lattice setRow."); //$NON-NLS-1$
}
for(int ix = ix_offset, nc = val.length+ix_offset; ix<nc; ix++) {
int arrayIndex = (ny-iy-1)*((nx+7)/8)+ix/8; // each row starts on a byte boundary
byte packedcell = packedData[arrayIndex];
int mask = 0x80>>>(ix%8); // start with 0x10000000 and shift right
if(val[ix-ix_offset]<=0) {
packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit
} else {
packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit
}
packedData[arrayIndex] = packedcell;
}
}
/**
* Sets a cell at the given location to a new value.
*
* A cell should take on a value of 0 or 1.
* @param ix
* @param iy
* @param val
*/
public void setValue(int ix, int iy, int val) {
if((iy<0)||(iy>=ny)||(ix<0)||(ix>=nx)) {
throw new IllegalArgumentException("Cell row or column index out of range. row="+iy+" col="+ix); //$NON-NLS-1$ //$NON-NLS-2$
}
int arrayIndex = (ny-iy-1)*((nx+7)/8)+ix/8; // each row starts on a byte boundary
byte packedcell = packedData[arrayIndex];
int mask = 0x80>>>(ix%8); // start with 0x10000000 and shift right
if(val<=0) {
packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit
} else {
packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit
}
packedData[arrayIndex] = packedcell;
}
public void setValue(int ix, int iy, byte val) {
setValue(ix, iy, (int) val);
}
/**
* Gets a value from the given location.
*
* Cell values are zero or one.
*
* @param ix
* @param iy
* @return the cell value.
*/
public byte getValue(int ix, int iy) {
byte packedcell = packedData[(ny-iy-1)*((nx+7)/8)+ix/8]; // each row starts on a byte boundary
int mask = 0x80>>>(ix%8); // start with 0x10000000 and shift right
if((packedcell&mask)>0) {
return 1;
}
return 0;
}
/**
* Gets the number of x entries.
* @return nx
*/
public int getNx() {
return nx;
}
/**
* Gets the number of y entries.
* @return ny
*/
public int getNy() {
return ny;
}
/**
* Sets the show grid option.
*
* @param showGrid
*/
public void setShowGrid(boolean showGrid) {
grid.setVisible(showGrid);
}
/**
* Sets color palette.
*
* @param colors
*/
public void setColorPalette(Color[] colors) {
zeroColor = colors[0];
oneColor = colors[1];
ColorModel colorModel = new IndexColorModel(1, 2, new byte[] {(byte) zeroColor.getRed(), (byte) oneColor.getRed()}, // red
new byte[] {(byte) zeroColor.getGreen(), (byte) oneColor.getGreen()}, // green
new byte[] {(byte) zeroColor.getBlue(), (byte) oneColor.getBlue()}, // blue
new byte[] {(byte) zeroColor.getAlpha(), (byte) oneColor.getAlpha()}); // alpha
image = new BufferedImage(colorModel, raster, false, null);
}
/**
* Sets the color for a single index.
* @param i
* @param color
*/
public void setIndexedColor(int i, Color color) {
if(i==0) {
zeroColor = color;
} else {
oneColor = color;
}
ColorModel colorModel = new IndexColorModel(1, 2, new byte[] {(byte) zeroColor.getRed(), (byte) oneColor.getRed()}, // red
new byte[] {(byte) zeroColor.getGreen(), (byte) oneColor.getGreen()}, // green
new byte[] {(byte) zeroColor.getBlue(), (byte) oneColor.getBlue()}, // blue
new byte[] {(byte) zeroColor.getAlpha(), (byte) oneColor.getAlpha()}); // alpha
image = new BufferedImage(colorModel, raster, false, null);
}
/**
* Sets the grid color.
* @param color
*/
public void setGridLineColor(Color color) {
grid.setColor(color);
}
public void setShowGridLines(boolean showGridLines) {
grid.setVisible(showGridLines);
}
/**
* Gets closest index from the given x world coordinate.
*
* @param x double the coordinate
* @return int the index
*/
public int xToIndex(double x) {
int nx = getNx();
double xMin = getXMin();
double xMax = getXMax();
double deltaX = (x-xMin)/(xMax-xMin);
int ix = (int) (deltaX*nx);
if(ix<0) {
return 0;
}
if(ix>=nx) {
return nx-1;
}
return ix;
}
/**
* Gets closest index from the given y world coordinate.
*
* @param y double the coordinate
* @return int the index
*/
public int yToIndex(double y) {
int ny = getNy();
double yMin = getYMin();
double yMax = getYMax();
double deltaY = (y-yMin)/(yMax-yMin);
int iy = (int) (deltaY*ny);
if(iy<0) {
return 0;
}
if(iy>=ny) {
return ny-1;
}
return iy;
}
/**
* Determines the lattice index (row-major order) from given x and y world coordinates
* Returns -1 if the world coordinates are outside the lattice.
*
* @param x
* @param y
* @return index
*/
public int indexFromPoint(double x, double y) {
int nx = getNx();
int ny = getNy();
double xMin = getXMin();
double xMax = getXMax();
double yMin = getYMin();
double yMax = getYMax();
double deltaX = (x-xMin)/(xMax-xMin);
double deltaY = (y-yMin)/(yMax-yMin);
int ix = (int) (deltaX*nx);
int iy = (int) (deltaY*ny);
if((ix<0)||(iy<0)||(ix>=nx)||(iy>=ny)) {
return -1;
}
return iy*nx+ix;
}
public JFrame showLegend() {
return null;
}
}
/*
* Open Source Physics software is free software; you can redistribute
* it and/or modify it under the terms of the GNU General Public License (GPL) as
* published by the Free Software Foundation; either version 2 of the License,
* or(at your option) any later version.
* Code that uses any portion of the code in the org.opensourcephysics package
* or any subpackage (subdirectory) of this package must must also be be released
* under the GNU GPL license.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
* or view the license online at http://www.gnu.org/copyleft/gpl.html
*
* Copyright (c) 2007 The Open Source Physics project
* http://www.opensourcephysics.org
*/