/*
* 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.frames;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.event.MouseInputAdapter;
import org.opensourcephysics.display.DisplayRes;
import org.opensourcephysics.display.Drawable;
import org.opensourcephysics.display.DrawingFrame;
import org.opensourcephysics.display.InteractivePanel;
import org.opensourcephysics.display.PlottingPanel;
import org.opensourcephysics.display2d.ByteRaster;
/**
* A DrawingFrame that displays data using a ByteRaster.
*
* @author W. Christian
* @version 1.0
*/
public class RasterFrame extends DrawingFrame {
protected ByteRaster raster = new ByteRaster(1, 1);
MouseInputAdapter mouseAdapter;
int[] editValues = new int[2];
int dragV;
Color[] customColors;
/**
* Constructs a RasterFrame with the given axes labels and frame title.
* @param xlabel String
* @param ylabel String
* @param frameTitle String
*/
public RasterFrame(String xlabel, String ylabel, String frameTitle) {
super(new PlottingPanel(xlabel, ylabel, null));
setTitle(frameTitle);
((PlottingPanel) drawingPanel).getAxes().setShowMajorXGrid(false);
((PlottingPanel) drawingPanel).getAxes().setShowMajorYGrid(false);
addMenuItems();
drawingPanel.addDrawable(raster);
setAnimated(true);
setAutoclear(true);
}
/**
* Constructs a RasterFrame with the given frame title but without axes.
* @param frameTitle String
*/
public RasterFrame(String frameTitle) {
super(new InteractivePanel());
setTitle(frameTitle);
addMenuItems();
drawingPanel.addDrawable(raster);
setAnimated(true);
setAutoclear(true);
}
/**
* Adds Views menu items on the menu bar.
*/
protected void addMenuItems() {
JMenuBar menuBar = getJMenuBar();
if(menuBar==null) {
return;
}
JMenu helpMenu = this.removeMenu(DisplayRes.getString("DrawingFrame.Help_menu_item")); //$NON-NLS-1$
JMenu menu = getMenu(DisplayRes.getString("DrawingFrame.Views_menu")); //$NON-NLS-1$
if(menu==null) {
menu = new JMenu(DisplayRes.getString("DrawingFrame.Views_menu")); //$NON-NLS-1$
menuBar.add(menu);
menuBar.validate();
} else { // add a separator if tools already exists
menu.addSeparator();
}
if(helpMenu!=null) {
menuBar.add(helpMenu);
}
// add a menu item to show the data table
JMenuItem menuItem = new JMenuItem(DisplayRes.getString("RasterFrame.MenuItem.Color")); //$NON-NLS-1$
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
setColorPalette();
}
};
menuItem.addActionListener(actionListener);
menu.add(menuItem);
// add a menu item to show the data table
menuItem = new JMenuItem(DisplayRes.getString("RasterFrame.MenuItem.B&W")); //$NON-NLS-1$
actionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
setBWPalette();
}
};
menuItem.addActionListener(actionListener);
menu.add(menuItem);
}
/**
* Sets black and white palette.
*/
public void setBWPalette() {
raster.setBWPalette();
repaint();
}
public void setColorPalette() {
if(customColors==null) {
raster.createDefaultColors();
} else {
raster.setColorPalette(customColors);
}
repaint();
}
public void showLegend() {
raster.showLegend();
}
/**
* Sets the color palette.
*
* @param colors
*/
public void setColorPalette(Color[] colors) {
customColors = colors;
raster.setColorPalette(colors);
repaint();
}
/**
* Clears drawable objects added by the user from this frame.
*/
public void clearDrawables() {
drawingPanel.clear(); // removes all drawables
drawingPanel.addDrawable(raster);
}
/**
* Gets Drawable objects added by the user to this frame.
*
* @return the list
*/
public synchronized ArrayList<Drawable> getDrawables() {
ArrayList<Drawable> list = super.getDrawables();
list.remove(raster);
return list;
}
/**
* Gets Drawable objects added by the user of an assignable type. The list contains
* objects that are assignable from the class or interface.
*
* @param c the type of Drawable object
*
* @return the cloned list
*
* @see #getObjectOfClass(Class c)
*/
public synchronized <T extends Drawable> ArrayList<T> getDrawables(Class<T> c) {
ArrayList<T> list = super.getDrawables(c);
list.remove(raster);
return list;
}
/**
* Clears the lattice data by setting all values to zero.
*/
public void clearData() {
raster.setBlock(0, 0, new byte[raster.getNx()][raster.getNy()]);
drawingPanel.invalidateImage();
}
/**
* Randomizes the lattice values.
*/
public void randomize() {
raster.randomize();
}
/**
* Resizes the number of columns and rows in the raster and centers the raster.
*
* @param nx int
* @param ny int
*/
private void resizeRaster(int nx, int ny) {
drawingPanel.setPreferredSize(new java.awt.Dimension(Math.max(nx+drawingPanel.getLeftGutter()+drawingPanel.getRightGutter(), 50), Math.max(ny+drawingPanel.getTopGutter()+drawingPanel.getBottomGutter(), 50)));
pack();
raster.resizeLattice(nx, ny);
drawingPanel.invalidateImage();
drawingPanel.repaint();
}
/**
* Sets the color for a single index.
* @param index
* @param color
*/
public void setIndexedColor(int index, Color color) {
raster.setIndexedColor(index, color);
}
/**
* Sets the raster's values and scale.
*
* @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);
raster.setMinMax(xmin, xmax, ymin, ymax);
}
/**
* Sets the raster's values using byte values.
*
* @param val
*/
public void setAll(byte val[][]) {
if((val.length!=raster.getNx())||(val[0].length!=raster.getNy())) {
this.resizeRaster(val.length, val[0].length);
}
raster.setBlock(0, 0, val);
}
/**
* Sets the raster's values using integer values.
*
* @param val
*/
public void setAll(int val[][]) {
if((val.length!=raster.getNx())||(val[0].length!=raster.getNy())) {
resizeRaster(val.length, val[0].length);
}
raster.setBlock(0, 0, val);
}
/**
* Sets the raster's values and scale.
*
* @param val int[][] the new values
* @param xmin double
* @param xmax double
* @param ymin double
* @param ymax double
*/
public void setAll(int val[][], double xmin, double xmax, double ymin, double ymax) {
setAll(val);
raster.setMinMax(xmin, xmax, ymin, ymax);
}
/**
* Sets the raster's values and scale.
*
* @param val int[] the new values
* @param nx
* @param xmin double
* @param xmax double
* @param ymin double
* @param ymax double
*/
public void setAll(int val[], int nx, double xmin, double xmax, double ymin, double ymax) {
if(val.length%nx!=0) {
throw new IllegalArgumentException("Raster dimension must match number of values."); //$NON-NLS-1$
}
resizeRaster(nx, val.length/nx);
setAll(val);
raster.setMinMax(xmin, xmax, ymin, ymax);
}
/**
* Sets an array v of int values into the raster, starting at (x=0,y=0).
* Values are in row-major format such that the index corresponds to iy*ny+ix.
*
* @param v
*/
public void setAll(int[] v) {
if(v.length!=raster.getNx()*raster.getNy()) {
throw new IllegalArgumentException("Raster size must be set before using row-major format."); //$NON-NLS-1$
}
for(int i = 0; i<v.length; i++) {
setAtIndex(i, v[i]);
}
}
/**
* Sets the ith indexed pixel to value v
* Values are in row-major format such that the index corresponds to iy*ny+ix.
*
* @param i
* @param v
*/
public void setAtIndex(int i, int v) {
int nx = raster.getNx();
setValue(i%nx, i/nx, v);
}
/**
* Sets the (ix,iy) cell or the site of the raster to store value v
*
* @param ix
* @param iy
* @param v
*/
public void setValue(int ix, int iy, int v) {
raster.setValue(ix, iy, (byte) v);
}
/**
* Gets the ith indexed pixel of the raster
* Values are in row-major format such that the index corresponds to iy*ny+ix.
*
* @param i
* @return value indexed by i
*/
public int getAtIndex(int i) {
int Nx = raster.getNx();
return get(i%Nx, i/Nx);
}
/**
* Gets the (x,y) pixel of the raster
*
* @param ix
* @param iy
* @return value at (ix,iy)
*/
public int get(int ix, int iy) {
return(raster.getValue(ix, iy)+128);
}
/**
* Gets the entire raster contents in an int array
* Values are in row-major format such that the index corresponds to iy*ny+ix.
*
* @return array containing entire lattice contents
*/
public int[] getAll() {
int N = raster.getNx()*raster.getNy();
int[] ret = new int[N];
for(int i = 0; i<N; i++) {
ret[i] = getAtIndex(i);
}
return ret;
}
/**
* Sets an action to toggle the grid betweem the given values when the mouse is pressed.
* @param enable boolean
* @param v1 int
* @param v2 int
*/
public void setToggleOnClick(boolean enable, int v1, int v2) {
editValues = new int[] {v1, v2};
if(enable) {
drawingPanel.addMouseListener(getMouseAdapter());
drawingPanel.addMouseMotionListener(getMouseAdapter());
} else {
drawingPanel.removeMouseListener(getMouseAdapter());
drawingPanel.removeMouseMotionListener(getMouseAdapter());
}
}
void mouse(MouseEvent e, boolean pressed) {
// button three is used for popup menu
if(e.getButton()==MouseEvent.BUTTON3) {
return;
}
double x = drawingPanel.pixToX(e.getX());
double y = drawingPanel.pixToY(e.getY());
int i = indexFromPoint(x, y);
if(i==-1) {
return;
}
if(pressed) {
dragV = editValues[0];
int len = editValues.length;
for(int j = 0; j<len; j++) {
if(getAtIndex(i)==editValues[j]) {
dragV = editValues[(j+1)%len];
}
}
}
if(getAtIndex(i)!=dragV) {
setAtIndex(i, dragV);
drawingPanel.render();
}
}
/**
* Gets the x coordinate for the given index.
*
* @param i int
* @return double the x coordiante
*/
public double indexToX(int i) {
if(raster==null) {
throw new IllegalStateException("Data has not been set. Invoke setAll before invoking this method."); //$NON-NLS-1$
}
return raster.indexToX(i);
}
/**
* Gets the index that is closest to the given x value
*
* @return double the x coordiante
*/
public int xToIndex(double x) {
if(raster==null) {
throw new IllegalStateException("Data has not been set. Invoke setAll before invoking this method."); //$NON-NLS-1$
}
return raster.xToIndex(x);
}
/**
* Gets the index that is closest to the given y value
*
* @return double the y coordiante
*/
public int yToIndex(double y) {
if(raster==null) {
throw new IllegalStateException("Data has not been set. Invoke setAll before invoking this method."); //$NON-NLS-1$
}
return raster.yToIndex(y);
}
/**
* Gets the y coordinate for the given index.
*
* @param i int
* @return double the y coordiante
*/
public double indexToY(int i) {
if(raster==null) {
throw new IllegalStateException("Data has not been set. Invoke setAll before invoking this method."); //$NON-NLS-1$
}
return raster.indexToY(i);
}
/**
* Determines the lattice index (row-major order) from given x and y world coordinates
*
* @param x
* @param y
* @return index
*/
public int indexFromPoint(double x, double y) {
return raster.indexFromPoint(x, y);
}
synchronized MouseInputAdapter getMouseAdapter() {
if(mouseAdapter==null) {
return new MouseInputAdapter() {
public void mousePressed(MouseEvent e) {
mouse(e, true);
}
public void mouseDragged(MouseEvent e) {
mouse(e, false);
}
};
}
return mouseAdapter;
}
}
/*
* 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
*/