//
// Percolation Applet
// by Kevin Chase
//
// This Java applet generates and displays bond
// percolation lattices, identifying the first few large clusters
// with distinct colors.
//
// It's a work in progress, so don't be too critical.
//
import java.applet.*;
import java.awt.*;
import java.util.*;
//
// BondLattice class
// contains the lattice data and its cluster maps.
//
class BondLattice extends Object {
static final int colored_clusters = 8;
double p; // Bond filling probability
int x_sites, y_sites; // Dimensions of lattice (width, height)
double bondx[], bondy[]; // Bond data:
site belongs to cluster n
int large_cluster[]; // Cluster data: 0th entry is largest, etc.
// Constructor for the lattice
BondLattice(double p, int x, int y) {
this.p = p;
x_sites = x;
y_sites = y;
bondx = new double[x_sites*y_sites];
bondy = new double[x_sites*y_sites];
cluster_id = new int[x_sites*y_sites];
large_cluster = new int[colored_clusters+1];
}
//
// randomize(p)
// Generates a random bond percolation lattice with bond
// occupation probability p. Avoids edge bonds.
//
void randomize() {
int i, j, idx;
Random r = new Random();
// Randomize Central bonds
for (i = 0; i=0; k--)
cluster_id[k] = -1; // Initially all sites unlabeled
new_label = 0;
for (k=0; k= k) {
clusters += 1; // Update number of clusters
temp = k; // Start with kth cluster
new_size = 0;
do {
new_size += size[temp]; // Add this cluster to k'th cluster size
size[temp] = 0; // Zero size of this cluster to remove it
hold = remap[temp]; // Grab next cluster in remap
remap[temp] = k; // Convert from cycle to direct map to k
temp = hold; // Go to next cluster
} while (temp != k);
size[k] = new_size;
}
}
// Relabel sites according to remap
for (k=0; k smallest_big_cluster_size) {
// Add this cluster to list (in correct order)
for (j=number_of_big_clusters-1; j>=0; j--)
if (size[k] > size[large_cluster[j]]) {
large_cluster[j+1] = large_cluster[j];
if (j==0) large_cluster[0] = k;
} else {
large_cluster[j+1] = k;
j = -1;
}
if (number_of_big_clusters < colored_clusters)
number_of_big_clusters++;
else
smallest_big_cluster_size =
size[large_cluster[number_of_big_clusters-1]];
}
}
void label_site(int label, int k, int remap[]) {
int temp, old_label = cluster_id[k];
boolean needs_remap;
if (old_label < 0) cluster_id[k] = label;
else {
// Cycle through remap to see if this labeling error
// has already been caught?
temp = label;
needs_remap = true;
do {
if (temp == old_label) needs_remap = false;
temp = remap[temp];
} while ((temp != label) && needs_remap);
// If not caught, add this to the remap cycle.
if (needs_remap) {
temp = remap[label];
remap[label] = remap[old_label];
remap[old_label] = temp;
}
}
}
}
//
// LatticePanel class
// contains the LatticeCanvas and the scrollbar
//
class LatticePanel extends Panel {
Scrollbar pbar;
LatticeCanvas lc;
int pbar_value;
LatticePanel(BondLattice lattice, int x, int y) {
setLayout(new BorderLayout());
lc = new LatticeCanvas(lattice, (int)(0.95*x), (int)(0.95*y));
add("Center", lc);
pbar_value = (int)(lc.lattice.p*100);
pbar = new Scrollbar(Scrollbar.HORIZONTAL);
pbar.setValues(pbar_value, 10, 0, 110);
add("South", pbar);
}
public boolean handleEvent(Event e) {
if (e.target == pbar) {
switch(e.id) {
case Event.SCROLL_LINE_UP:
case Event.SCROLL_LINE_DOWN:
case Event.SCROLL_PAGE_UP:
case Event.SCROLL_PAGE_DOWN:
case Event.SCROLL_ABSOLUTE:
pbar_value = ((Integer)e.arg).intValue();
lc.lattice.p = (double)pbar_value/100.0;
lc.lattice.label();
lc.draw(lc.offscreen.getGraphics(),0,lc.x,0,lc.y);
lc.paint(lc.getGraphics());
break;
}
}
return super.handleEvent(e);
}
}
//
// LatticeCanvas class
// contains the lattice and its offscreen bitmap.
//
class LatticeCanvas extends Canvas {
BondLattice lattice; // Bond Lattice for this Canvas
int x, y; // x, y dimensions of Canvas
Image offscreen; // Offscreen bitmap (makes drawing smoother)
LatticeCanvas(BondLattice lattice, int x, int y) {
this.lattice = lattice;
this.x = x;
this.y = y;
resize(x,y);
}
//
// addNotify()
// createImage() can't be called until the component exists!
// addNotify creates the component, so this method overloading
// neatly solves the problem by postponing createImage() until
// super.addNotify() is completed.
//
public void addNotify() {
super.addNotify();
offscreen = createImage(size().height, size().width);
}
//
// mouseDown event
//
public boolean mouseDown(Event e, int xx, int yy) {
lattice.randomize();
draw(offscreen.getGraphics(),0,x,0,y);
paint(getGraphics());
return true;
}
//
// draw(g)
// Draw the percolation lattice onto graphics object g.
//
void draw(Graphics g, int x_min, int x_max, int y_min, int y_max) {
int x, y, i, j;
int delta_x = (x_max-x_min)/lattice.x_sites;
int delta_y = (y_max-y_min)/lattice.y_sites;
// Clear the region before drawing
g.clearRect(x_min, y_min, x_max, y_max);
// Draw the bonds which are filled
for (x = x_min+delta_x/2, i = 0; i