/*
* IslandLattice.java
*
* Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
*
* This file is part of BEAST.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* BEAST is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* BEAST 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BEAST; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package dr.geo;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
/**
* @author Alexei Drummond
*/
public class IslandLattice extends JComponent implements Lattice {
private int[][] lattice;
private final int width;
private final int height;
public IslandLattice(int width, int height) {
lattice = new int[width][height];
this.width = width;
this.height = height;
}
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public void paintLattice(Graphics g) {
g.setColor(Color.blue);
g.fillRect(0, 0, width, height);
g.setColor(Color.green);
for (int i = 0; i < lattice.length; i++) {
for (int j = 0; j < lattice.length; j++) {
if (lattice[i][j] > 0) {
g.drawRect(i, j, 1, 1);
}
}
}
}
public void paintComponent(Graphics g) {
paintLattice(g);
}
public final int latticeWidth() {
return width;
}
public final int latticeHeight() {
return height;
}
public void setState(int i, int j, int state) {
lattice[i][j] = state;
}
public int getState(int i, int j) {
return lattice[i][j];
}
public int getState(Location loc) {
return lattice[loc.i][loc.j];
}
public void smooth(int boundary) {
int[][] newLattice = new int[width][height];
for (int i = 0; i < lattice.length; i++) {
for (int j = 0; j < lattice.length; j++) {
int ncount = getNeighbourSum(i, j);
if (ncount > boundary) {
newLattice[i][j] = 1;
} else {
newLattice[i][j] = 0;
}
}
}
lattice = newLattice;
}
/**
* @param n the number of pixels to be flipped
* @return the locations of unique islands formed, since some may merge
*/
public List<Location> addIslands(int n, Random random) {
List<Location> locations = new ArrayList<Location>();
for (int k = 0; k < n; k++) {
int i = random.nextInt(width);
int j = random.nextInt(height);
if (getState(i, j) == 0) {
setState(i, j, 1);
if (getNeighbourSum(i, j) == 0) {
locations.add(new Location(i, j));
}
}
}
return locations;
}
/**
* @param n the number of pixels to move from 0 -> 1
* @param random
* @return the number of attempts taken to grow the current islands the
* perscribed amount of land
*/
public int growIslands(int n, Random random) {
int count = 0;
int attempts = 0;
while (count < n) {
int i = random.nextInt(width);
int j = random.nextInt(height);
if (getState(i, j) == 0) {
if (getNeighbourSum(i, j) > 0) {
setState(i, j, 1);
count += 1;
}
}
attempts += 1;
}
return attempts;
}
public int sum() {
int sum = 0;
for (int i = 0; i < lattice.length; i++) {
for (int j = 0; j < lattice.length; j++) {
sum += lattice[i][j];
}
}
return sum;
}
int getNeighbourSum(int i, int j) {
int sum = 0;
if (i > 0) {
sum += getState(i - 1, j);
}
if (i < width - 1) {
sum += getState(i + 1, j);
}
if (j > 0) {
sum += getState(i, j - 1);
}
if (j < height - 1) {
sum += getState(i, j + 1);
}
return sum;
}
private List<Location> getNeighbours(Location loc) {
List<Location> neighbours = new ArrayList<Location>();
if (loc.i > 0) {
neighbours.add(new Location(loc.i - 1, loc.j));
}
if (loc.i < width - 1) {
neighbours.add(new Location(loc.i + 1, loc.j));
}
if (loc.j > 0) {
neighbours.add(new Location(loc.i, loc.j - 1));
}
if (loc.j < height - 1) {
neighbours.add(new Location(loc.i, loc.j + 1));
}
return neighbours;
}
private Set<Location> getEmptyNeighboursOfIsland(Location loc) {
List<Location> toProcess = new ArrayList<Location>();
Set<Location> processed = new HashSet<Location>();
Set<Location> empty = new HashSet<Location>();
toProcess.add(loc);
while (toProcess.size() > 0) {
Location l = toProcess.remove(toProcess.size() - 1);
List<Location> neighbours = getNeighbours(l);
for (Location neighbour : neighbours) {
if (getState(neighbour) == 0) {
empty.add(neighbour);
} else if (!processed.contains(neighbour)) {
toProcess.add(neighbour);
}
}
processed.add(l);
}
return empty;
}
public static void main(String[] args) {
Random random = new Random();
IslandLattice lattice = new IslandLattice(500, 500);
List<Location> islands = lattice.addIslands(50, random);
System.out.println("Created " + islands.size() + " islands");
int growth = 4950;
int attempts = lattice.growIslands(growth, random);
System.out.println("Took " + attempts + " attempts to grow islands by " + growth);
lattice.smooth(2);
JFrame frame = new JFrame();
frame.getContentPane().add(lattice, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}