package cellularautomata;
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
public class ContinuousApplet extends Applet
{
public static final String VERSION = "1.0";
private ImageCanvas _imageCanvas;
private Label _status;
private Button _drawButton;
private TextField _maxIterField;
private TextField _zoomField;
private ScrollPane _scrollPane;
private StateComponent _stateComponent;
public void init()
{
super.init();
Color background = getColorParameter("background", Color.white);
Color foreground = getColorParameter("foreground", Color.black);
int maxIter = getWidth()/2;
byte[] colorMap = new byte[256*3];
for (int i=0; i<256;i++)
{
int n = 3*i;
colorMap[n] = (byte) (255-i);
colorMap[n+1] = (byte) (255-i);
colorMap[n+2] = (byte) (255-i);
}
_stateComponent = new StateComponent(colorMap,1,0);
_imageCanvas = new ImageCanvas(_stateComponent,
colorMap, maxIter,1);
_scrollPane = new ScrollPane();
_scrollPane.add(_imageCanvas);
_maxIterField = new TextField(new Integer(maxIter).toString());
_zoomField = new TextField("1.0");
_drawButton = new Button("Redraw!");
_status = new Label(
"copyright 2003 (c) Fabien Le Floc'h <fabien@31416.org>");
setBackground(background);
setForeground(foreground);
setLayout(new BorderLayout(0,0));
Panel topPanel = new Panel(new GridLayout(2,1,0,0));
Panel heightPanel = new Panel(new FlowLayout(FlowLayout.CENTER,5,2));
topPanel.add(heightPanel);
topPanel.add(_stateComponent);
heightPanel.add(new Label("zoom:"));
heightPanel.add(_zoomField);
heightPanel.add(new Label("number of iterations:"));
heightPanel.add(_maxIterField);
heightPanel.add(_drawButton);
add(BorderLayout.NORTH,topPanel);
add(BorderLayout.CENTER,_scrollPane);
add(BorderLayout.SOUTH,_status);
}
public boolean action(Event e, Object what)
{
if (e.target == _drawButton)
{
String w = _maxIterField.getText();
String z = _zoomField.getText();
try
{
int maxIter = Integer.parseInt(w);
float zoom = Float.parseFloat(z);
int position = Math.round(maxIter*zoom) -
((int)_scrollPane.getViewportSize().getWidth()/2);
_stateComponent.renew();
_imageCanvas.setSize(maxIter,zoom);
_imageCanvas.repaint();
_scrollPane.layout();
_scrollPane.setScrollPosition(position,0);
return true;
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
return false;
}
public String getAppletInfo()
{
return "Continuous celullar automata v. " + VERSION +
"Written by F. Le Floc'h <fabien@31416.org>.";
}
protected Color getColorParameter(String name, Color defaultColor)
{
String value = this.getParameter(name);
try
{
return new Color(Integer.parseInt(value, 16));
}
catch (Exception e)
{
return defaultColor;
}
}
public String[][] getParameterInfo()
{
return info;
}
private static final String[][] info =
{
{"foreground", "hexadecimal color value", "foreground color"},
{"background", "hexadecimal color value", "background color"}
};
private static class ImageCanvas extends Canvas
{
private Image _image;
private int _maxIter;
private float _zoom;
private ContinuousRule _rule;
private byte[] _colorMap;
public ImageCanvas(ContinuousRule rule,
byte[] colorMap,
int maxIter,
float zoom)
{
this.setBounds(0,0,maxIter*2,maxIter);
_maxIter = maxIter;
_zoom = zoom;
_rule = rule;
_colorMap = colorMap;
}
public void setSize(int maxIter, float zoom)
{
_maxIter = maxIter;
_zoom = zoom;
_image = null;
int height = Math.round(maxIter*zoom);
this.setBounds(0,0,2*height,height);
}
public void paint(Graphics g)
{
if (_image == null)
{
System.gc();
int height = Math.round(_maxIter*_zoom);
_image = this.createImage(height*2,height);
}
g.drawImage(_image, 0, 0, this);
}
public Image createImage(int width, int height)
{
int maxX = _maxIter*2;
byte[] pixels = new byte[maxX*_maxIter];
float[] lastLine = new float[maxX*2];
float[] tempLine = new float[maxX*2];
int index = 0;
for (int i=0;i<lastLine.length;i++)
{
lastLine[i] = 0;
}
lastLine[maxX] = 1;
for (int i=_maxIter; i<maxX+_maxIter;i++)
{
pixels[index++] = (byte) Math.round(255*lastLine[i]);
}
for (int y=1; y<_maxIter; y++)
{
tempLine[0] = 0;
tempLine[tempLine.length-1] = 0;
for (int x=y; x<tempLine.length-y; x++)
{
tempLine[x] = _rule.get(lastLine,x);
}
for (int x=_maxIter;x<maxX+_maxIter;x++)
{
pixels[index++] = (byte) Math.round(255*tempLine[x]);
}
float[] tempRef = lastLine;
lastLine = tempLine;
tempLine = tempRef;
}
lastLine = null;
tempLine = null;
MemoryImageSource mis = new MemoryImageSource(
maxX,_maxIter,
new IndexColorModel(8,256,_colorMap,0,false,-1),
pixels,0,maxX);
mis.setFullBufferUpdates(false);
Image image = super.createImage(mis);
if (_zoom != 1)
{
image = image.getScaledInstance(
width,height,Image.SCALE_SMOOTH);
}
return image;
}
}
public static interface ContinuousRule
{
float get(float[] pixels, int i);
float get(float left, float middle, float right);
}
public static class StateComponent
extends Panel
implements ContinuousRule
{
private Image _initialState;
private TextField _aField, _bField;
private float _a, _b;
private StateCanvas _canvas;
private byte[] _colorMap;
public StateComponent(byte[] colorMap, float a, float b)
{
_initialState = null;
_a = a;
_b = b;
_colorMap = colorMap;
_aField = new TextField(new Float(a).toString());
_bField = new TextField(new Float(b).toString());
_canvas = new StateCanvas(this, _colorMap, 120, 40);
this.setLayout(new FlowLayout(FlowLayout.CENTER,0,2));
this.add(new Label("Next state = FractionalPart["));
this.add(_aField);
this.add(new Label("x +"));
this.add(_bField);
this.add(new Label("]"));
this.add(_canvas);
this.setBounds(0,0,this.getWidth(),41);
}
public void renew()
{
_a = Float.parseFloat(_aField.getText());
_b = Float.parseFloat(_bField.getText());
_canvas.renew();
}
public float get(float[] pixels, int i)
{
return get(pixels[i-1],pixels[i],pixels[i+1]);
}
public float get(float left, float middle, float right)
{
float temp = _a*(left+middle+right)/3+_b;
temp -= (float) Math.floor(temp);
return temp;
}
}
public static class StateCanvas extends Canvas
{
private int _height;
private int _width;
private ContinuousRule _rule;
private Image _image;
private byte[] _colorMap;
public StateCanvas(ContinuousRule rule,
byte[] colorMap,
int width,
int height)
{
_height = height;
_width = width;
_rule = rule;
_image = null;
_colorMap = colorMap;
this.setBounds(0,0,width,height);
}
public void setRule(ContinuousRule rule)
{
_rule = rule;
renew();
}
public void renew()
{
_image = null;
repaint();
}
public void paint(Graphics g)
{
if (_image == null)
{
System.gc();
_image = this.createImage(_width, _height);
}
g.drawImage(_image, 0, 0, this);
}
public Image createImage(int width, int height)
{
Image image = super.createImage(width,height);
Graphics g = image.getGraphics();
int leftWidth = 2*width/3;
int topHeight = height/2;
Color grey;
for (int i=0; i<leftWidth; i++)
{
int mapIndice = 3*255*i/(leftWidth-1);
grey = new Color((int)_colorMap[mapIndice] & 0xFF,
(int)_colorMap[mapIndice+1] & 0xFF,
(int)_colorMap[mapIndice+2] & 0xFF);
g.setColor(grey);
g.drawLine(i,0,i,topHeight);
float f = (float)i/(float)(leftWidth-1);
mapIndice = 3*Math.round(255*_rule.get(f,f,f));
grey = new Color((int)_colorMap[mapIndice] & 0xFF,
(int)_colorMap[mapIndice+1] & 0xFF,
(int)_colorMap[mapIndice+2] & 0xFF);
g.setColor(grey);
g.drawLine(i,topHeight+1,i,height-1);
}
g.setColor(getForeground());
for (int i=leftWidth;i<width;i++)
{
float f = (float)(i-leftWidth)/(float)(width-leftWidth-1);
int y = Math.round((height-1)*_rule.get(f,f,f));
g.drawLine(i,height-y-1,i,height-y-1);
}
g.drawRect(0,0,leftWidth-1,topHeight);
g.drawRect(0,topHeight,leftWidth-1,height-1-topHeight);
g.drawRect(leftWidth-1,0,width-leftWidth,height-1);
return image;
}
}
}