Weird random errors, java drawing
I have written a program which I think ought to work flawlessly. For some reason it doesn't. I will provide the code and hope that somebody can figure out what's wrong. I've been sitting with it for hours but I can't get any further.
import java.awt.*;
import javax.swing.*;
public class CrystalModel
{
private int radius;
private int index;
private boolean[][] crystal;
private Point concludingPoint;
private int escapeRadius;
/**
* Constructor. Initiates an electron bath of size 30x30.
*/
public CrystalModel()
{
radius = 30;
index = 30*2-1;
start();
}
/**
* Constructor. Initiates an electron bath of size r.
* @param r bath radius
*/
public CrystalModel(int r)开发者_Go百科
{
radius = r;
index = r*2-1;
start();
}
/**
* Initiates the experiment
*/
private void start()
{
crystal = new boolean[radius*2][radius*2];
crystal[radius][radius] = true; //The width is always even (2*r), this is as close to the center as one gets
escapeRadius = (int)(1.1*radius);
}
/**
* Determines if a given xy-coordinate is within radius
* @param x x-coordinate
* @param y y-coordinate
* @return whether the active ion is out of range
*/
private boolean outsideCircle(int r, int x, int y)
{
return (Math.pow(x,2)+Math.pow(y,2) >= Math.pow(r, 2));
}
/**
* Determines if the currently active ion has a neighbouring crystallized ion
* @param whether the is a neighbour
*/
private boolean anyNeighbours(int x, int y)
{
x = xBathToModel(x);
y = yBathToModel(y);
boolean left = (x-1 >= 0) && (x-1 <= index) && (y >= 0) && (y <= index) ? crystal[x-1][y] : false;
boolean right = (x+1 >= 0) && (x+1 <= index) && (y >= 0) && (y <= index) ? crystal[x+1][y] : false;
boolean up = (y-1 >= 0) && (y-1 <= index) && (x >= 0) && (x <= index) ? crystal[x][y-1] : false;
boolean down = (y+1 >= 0) && (y+1 <= index) && (x >= 0) && (x <= index) ? crystal[x][y+1] : false;
return ( left || right || up || down );
}
/**
* Determines an xy-coordinate at radius distance from the center
* @param radius radius of escape for ions
* @return Point object encapsulating x, y
*/
private Point dropNewIon()
{
double angle = (int)(Math.random()*2*Math.PI);
return new Point( (int)( Math.cos(angle)*(index/2) ), (int)( Math.sin(angle)*(index/2) ) );
}
/**
* Transform x-coordinate upon the moving of origo from center to top-left
* @ x x-coordinate
*/
public int xBathToModel(int x)
{
return radius+x;
}
/**
* Transform y-coordinate upon the moving of origo from center to top-left
* @param y y-coordinate
*/
public int yBathToModel(int y)
{
return radius+y;
}
/**
* Increments the number of ions in the crystal by one
* @return boolean indicating whether the experiment is done or not
*/
private Point crystallizeOneIon()
{
Point point = dropNewIon();
for( ; ; )
{
switch((int)(Math.random()*4+1))
{
case 1: point.x+=1;
break;
case 2: point.x-=1;
break;
case 3: point.y+=1;
break;
case 4: point.y-=1;
break;
}
if(outsideCircle(escapeRadius, point.x, point.y)) point = dropNewIon();
if(anyNeighbours(point.x, point.y)) break;
}
crystal[xBathToModel(point.x)][yBathToModel(point.y)] = true;
return point;
}
/**
* Let the algorithm (CrystalExperiment) simulate a number of steps
* @param steps how many steps
* @return boolean indiciating whether the experiment is concluded
*/
public boolean runExperiment(int steps)
{
for(int i=0; i<steps; i++)
{
concludingPoint = crystallizeOneIon();
if(outsideCircle((int)index/2, concludingPoint.x, concludingPoint.y))
{
concludingPoint.x = xBathToModel(concludingPoint.x);
concludingPoint.y = yBathToModel(concludingPoint.y);
return true;
}
else
{
concludingPoint.x = xBathToModel(concludingPoint.x);
concludingPoint.y = yBathToModel(concludingPoint.y);
}
}
return false;
}
/**
* Return a textual representation of the crystal
* @return String representing the crystal
*/
public String toString()
{
String output = "";
for(int y=-1; y<=index+1; y++)
{
for(int x=-1; x<=index+1; x++)
{
if(y == -1) output+="--";
else if(y == index+1) output+="--";
else
{
if(x == -1) output+="|";
else if(x == index+1) output+="|";
else
{
if(concludingPoint.equals(new Point(x,y))) output+="# ";
else if(crystal[x][y] == true) output+="* ";
else output+=" ";
}
}
}
output+="\n";
}
return output;
}
public int getIndexSize()
{
return index;
}
public boolean getMatrixValue(int x, int y)
{
return crystal[x][y];
}
private void drawCrystal()
{
JFrame frame = new JFrame("");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setBounds(0, 0, 200, 200);
CrystalView drawing = new CrystalView(this);
frame.add(drawing);
}
public static void main(String[] args)
{
(new CrystalModel(200)).drawCrystal();
}
}
This is my view, it doesn't work (although the toString method works, and this is similar):
import javax.swing.*;
import java.awt.*;
public class CrystalView extends JPanel
{
CrystalModel model;
public CrystalView(CrystalModel m)
{
model = m;
}
public void paintComponent(Graphics g)
{
while(!model.runExperiment(1))
{
for(int y=0; y<model.getIndexSize(); y++)
{
for(int x=0; x<model.getIndexSize(); x++)
{
if(model.getMatrixValue(x,y))
g.drawOval(x, y, 1, 1);
}
}
this.repaint();
}
}
}
The error is in the drawing. It (1) generates errors in the terminal, and (2) doesn't draw a full size. Please run the program and you will see what I mean.
public void paintComponent(Graphics g)
{
while(!model.runExperiment(1))
{
for(int y=0; y<model.getIndexSize(); y++)
{
for(int x=0; x<model.getIndexSize(); x++)
{
if(model.getMatrixValue(x,y))
g.drawOval(x, y, 1, 1);
}
}
this.repaint();
}
}
I don't know what the code should do but you should never have a loop that invokes repaint() like that. that is one way to cause an infinite loop.
If you are trying to animate something then you need to use a Thread or a Swing Timer to do the animation.
I tried to fix your code (see below). The problem place is marked with TODO. Don't know how is it intended to work, but now it draws some points.
As mentioned in previous answer you can't get animation like this. The paintComponent()
method is only called once to draw the component. This happens when the form is resized for example. So you can get only static image.
CrystalModel.java
import java.awt.Point;
import javax.swing.JFrame;
public class CrystalModel
{
private int radius;
private int index;
private boolean[][] crystal;
private Point concludingPoint;
private int escapeRadius;
/**
* Constructor. Initiates an electron bath of size 30x30.
*/
public CrystalModel()
{
radius = 30;
index = 30*2-1;
start();
}
/**
* Constructor. Initiates an electron bath of size r.
* @param r bath radius
*/
public CrystalModel(int r)
{
radius = r;
index = r*2-1;
start();
}
/**
* Initiates the experiment
*/
private void start()
{
crystal = new boolean[radius*2][radius*2];
crystal[radius][radius] = true; //The width is always even (2*r), this is as close to the center as one gets
escapeRadius = (int)(1.1*radius);
}
/**
* Determines if a given xy-coordinate is within radius
* @param x x-coordinate
* @param y y-coordinate
* @return whether the active ion is out of range
*/
private boolean outsideCircle(int r, int x, int y)
{
return (Math.pow(x,2)+Math.pow(y,2) >= Math.pow(r, 2));
}
/**
* Determines if the currently active ion has a neighbouring crystallized ion
* @param whether the is a neighbour
*/
private boolean anyNeighbours(int x, int y)
{
x = xBathToModel(x);
y = yBathToModel(y);
boolean left = (x-1 >= 0) && (x-1 <= index) && (y >= 0) && (y <= index) ? crystal[x-1][y] : false;
boolean right = (x+1 >= 0) && (x+1 <= index) && (y >= 0) && (y <= index) ? crystal[x+1][y] : false;
boolean up = (y-1 >= 0) && (y-1 <= index) && (x >= 0) && (x <= index) ? crystal[x][y-1] : false;
boolean down = (y+1 >= 0) && (y+1 <= index) && (x >= 0) && (x <= index) ? crystal[x][y+1] : false;
return ( left || right || up || down );
}
/**
* Determines an xy-coordinate at radius distance from the center
* @param radius radius of escape for ions
* @return Point object encapsulating x, y
*/
private Point dropNewIon()
{
double angle = (int)(Math.random()*2*Math.PI);
return new Point( (int)( Math.cos(angle)*(index/2) ), (int)( Math.sin(angle)*(index/2) ) );
}
/**
* Transform x-coordinate upon the moving of origo from center to top-left
* @ x x-coordinate
*/
public int xBathToModel(int x)
{
return radius+x;
}
/**
* Transform y-coordinate upon the moving of origo from center to top-left
* @param y y-coordinate
*/
public int yBathToModel(int y)
{
return radius+y;
}
/**
* Increments the number of ions in the crystal by one
* @return boolean indicating whether the experiment is done or not
*/
private Point crystallizeOneIon()
{
Point point = dropNewIon();
for( ; ; )
{
switch((int)(Math.random()*4+1))
{
case 1: point.x+=1;
break;
case 2: point.x-=1;
break;
case 3: point.y+=1;
break;
case 4: point.y-=1;
break;
}
if(outsideCircle(escapeRadius, point.x, point.y)) point = dropNewIon();
if(anyNeighbours(point.x, point.y)) break;
break;
}
try {
// TODO The logic is wrong here - calculated points sometimes are out of array. See console output
crystal[xBathToModel(point.x)][yBathToModel(point.y)] = true;
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Oops, point (" + point.x + ", " + point.y + ") is out of array");
}
return point;
}
/**
* Let the algorithm (CrystalExperiment) simulate a number of steps
* @param steps how many steps
* @return boolean indiciating whether the experiment is concluded
*/
public synchronized boolean runExperiment(int steps)
{
for(int i=0; i<steps; i++)
{
concludingPoint = crystallizeOneIon();
if(outsideCircle((int)index/2, concludingPoint.x, concludingPoint.y))
{
concludingPoint.x = xBathToModel(concludingPoint.x);
concludingPoint.y = yBathToModel(concludingPoint.y);
return true;
}
else
{
concludingPoint.x = xBathToModel(concludingPoint.x);
concludingPoint.y = yBathToModel(concludingPoint.y);
}
}
return false;
}
/**
* Return a textual representation of the crystal
* @return String representing the crystal
*/
public String toString()
{
String output = "";
for(int y=-1; y<=index+1; y++)
{
for(int x=-1; x<=index+1; x++)
{
if(y == -1) output+="--";
else if(y == index+1) output+="--";
else
{
if(x == -1) output+="|";
else if(x == index+1) output+="|";
else
{
if(concludingPoint.equals(new Point(x,y))) output+="# ";
else if(crystal[x][y] == true) output+="* ";
else output+=" ";
}
}
}
output+="\n";
}
return output;
}
public int getIndexSize()
{
return index;
}
public boolean getMatrixValue(int x, int y)
{
return crystal[x][y];
}
private void drawCrystal()
{
JFrame frame = new JFrame("");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setBounds(0, 0, 600, 600);
CrystalView drawing = new CrystalView(this);
frame.add(drawing);
frame.validate();
}
public static void main(String[] args)
{
(new CrystalModel(200)).drawCrystal();
}
}
CrystalView.java
import java.awt.Graphics;
import javax.swing.JPanel;
public class CrystalView extends JPanel {
private static final long serialVersionUID = 1L;
CrystalModel model;
public CrystalView(CrystalModel m) {
model = m;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
while (!model.runExperiment(1)) {
for (int y = 0; y < model.getIndexSize(); y++) {
for (int x = 0; x < model.getIndexSize(); x++) {
if (model.getMatrixValue(x, y)) {
g.drawOval(x, y, 2, 2);
}
}
}
}
}
}
精彩评论