I want to draw a Koch Curve Snowflake in my program, its working fine so far except for 1 Problem.
I want to show a drawn Curve directly at start up, but cant get this to show ( see section in code with comment). After I press the button intended to draw a curve, it shows just fine.
What do I need to change to show something drawn on the panel before any button is pressed?
package fractals;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class fractalsGUI extends JFrame {
private JPanel drawPanel, menuPanel;
private JButton drawButton;
private JTextField iterField;
private final JLabel iterLabel = new JLabel("Iterations:");
private final int defaultIterations = 4;
private final double cos60 = 0.5;
private final double sin60 = 0.5 * Math.sqrt(3);
private final double lengthModifier = Math.sqrt(3) * 2 / 3;
public fractalsGUI() {
/*
* GUI grafics setup stuff
*
*/
setTitle("Koch Curve Snowflake Generator");
drawPanel = new JPanel();
menuPanel = new JPanel();
drawButton = new JButton();
iterField = new JTextField("" + defaultIterations, 2);
this.setSize(600, 600);
drawButton.setText("Draw Curve");
drawButton.setActionCommand("drawCurve");
setLayout(new BorderLayout());
this.add(drawPanel, BorderLayout.CENTER);
this.add(menuPanel, BorderLayout.SOUTH);
menuPanel.add(iterLabel);
menuPanel.add(iterField);
menuPanel.add(drawButton);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
/*
* draw initial Curve --- THIS DOES NOT SHOW ---
*/
drawSegment(drawPanel.getGraphics(), new Point(200,300), new Point(400,300), 3);
/*
* GUI Button functions
*
*/
drawButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("drawCurve")) {
int iterations = Integer.parseInt(iterField.getText());
if (iterations > 8)
iterations = 8;
else if (iterations < 0)
iterations = 0;
drawCurve(iterations, drawPanel.getGraphics(), new Rectangle(drawPanel.getSize()));
}
}
});
}
public void drawSegment(Graphics g, Point start, Point end, int iteration) {
// base case
if (iteration == 0)
g.drawLine(start.x, start.y, end.x, end.y);
// recursion
else {
Point distance = new Point((end.x - start.x) / 3, (end.y - start.y) / 3);
Point firstThirdEnd = new Point(start.x + distance.x, start.y + distance.y);
Point lastThirdStart = new Point(end.x - distance.x, end.y - distance.y);
Point triangleTip = new Point(firstThirdEnd.x + (int) (distance.x * cos60 + distance.y * sin60), firstThirdEnd.y + (int) (distance.y * cos60 - distance.x * sin60));
drawSegment(g, start, firstThirdEnd, iteration - 1);
drawSegment(g, firstThirdEnd, triangleTip, iteration - 1);
drawSegment(g, triangleTip, lastThirdStart, iteration - 1);
drawSegment(g, lastThirdStart, end, iteration - 1);
}
}
public void drawCurve(int iterations, Graphics g, Rectangle bounds) {
// fill in background
g.setColor(Color.white);
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
double w, h;
if (bounds.height < (int) (bounds.width * lengthModifier)) {
// height is limiting
h = bounds.height;
w = h / lengthModifier;
}
else {
// width is limiting
w = bounds.width;
h = w * lengthModifier;
}
int top = bounds.y + (int) ((bounds.height - h) / 2 + (h / 4));
Point curve1start = new Point(bounds.x + (int) ((bounds.width - w) / 2), top);
Point curve2start = new Point(bounds.x + (int) ((bounds.width + w) / 2), top);
Point curve3start = new Point(bounds.x + (bounds.width / 2), bounds.y + (int) ((bounds.height + h) / 2));
// draw recursion
g.setColor(Color.red);
drawSegment(g, curve1start, curve2start, iterations);
g.setColor(Color.blue);
drawSegment(g, curve2start, curve3start, iterations);
g.setColor(Color.green);
drawSegment(g, curve3start, curve1start, iterations);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
fractalsGUI mainWindow = new fractalsGUI();
}
});
}
}
after this
drawSegment(drawPanel.getGraphics(), new Point(200,300), new Point(400,300), 3);
call this
drawPanel.repaint()
Related
Below is my current algorithm to align the rectangle (representing symbol) in the center of the canvas space (representing icon). It is only the algorithm I am interested in so ignore the rest of the code as it is merely for demonstration purposes as a visual aid.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class IconSymbol extends JFrame {
public IconSymbol(double iWH, double s, double w, double h) {
getContentPane().add(new Canvas((int)iWH, s, w, h));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize((int)iWH, (int)iWH);
setVisible(true);
}
public static void main(String arg[]) {
IconSymbol is = new IconSymbol(100, 0.9, 50, 50);
}
class Canvas extends JPanel {
// STIPULATED
double iconWH = 0;
double sScale = 0;
double sWidth = 0;
double sHeight = 0;
// CALCULATED
double padX = 0;
double padY = 0;
double xOffSet = 0;
double yOffSet = 0;
public Canvas(double iWH,double sS,double sW,double sH) {
this.iconWH = iWH;
this.sScale = sS;
this.sWidth = sW;
this.sHeight = sH;
}
public void paint(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
g2D.setBackground(Color.WHITE);
g2D.setPaint(Color.BLUE);
Shape icon = new Rectangle.Double(0,0,(int)iconWH,(int)iconWH);
g2D.fill(icon);
g2D.setPaint(Color.BLACK);
int width = (int)iconWH / 10;
int height= (int)iconWH / 10;
for(int row=0;row<10;row++){
for(int col=0;col<10;col++){
g.drawRect(row*width,col*height,width,height);
}
}
Point off = algorithm();
g2D.setPaint(Color.RED);
Shape s = new Rectangle.Double(off.x,off.y,(int)sWidth,(int)sHeight);
AffineTransform tran = AffineTransform.getScaleInstance(sScale, sScale);
g2D.fill(tran.createTransformedShape(s));
}
public Point algorithm(){
// ALGORITHM WITH EXACT NEEDED PARAMETERS
padX = (sWidth - ((sWidth * sScale))) / 2;
padY = (sHeight - ((sHeight * sScale))) / 2;
xOffSet = padX + ((iconWH - (sWidth * sScale)) / 2);
yOffSet = padX + ((iconWH - (sHeight * sScale)) / 2);
Point point = new Point((int)xOffSet, (int)yOffSet);
return point;
}
}
}
The problem with your code is that the scale transform tran is scaling the calculated origin of the rectangle, off, as well as sWidth and sHeight. If you want to keep with your current scheme you need to apply the inverse of the scale transform to the calculated offset in your algorithm method:
public Point algorithm(){
// ALGORITHM WITH EXACT NEEDED PARAMETERS
xOffSet = ((iconWH - (sWidth * sScale)) / 2) / sScale;
yOffSet = ((iconWH - (sHeight * sScale)) / 2) / sScale;
Point point = new Point((int)xOffSet, (int)yOffSet);
return point;
}
Note that I removed padX and padY as they weren't required for calculating the offset.
Im searching for an algorythem to get the location of a hexagon in a grid.
I found this one but it doesnt seam to work:
for(int i = 0; i < width; i++) {
for(int j = 0; j < height; j++) {
grid[i][j] = new Hexagon(x+(j*((3*Hexagon.S)/2)), y+((j%2)*Hexagon.A)+(2*i*Hexagon.A));
}
}
The output is kind of strange:
output
This is the window-creating class(just a test class):
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Grid extends JPanel {
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
int width = 2;
int height = 4;
int x = 100;
int y = 100;
Hexagon[][] grid = new Hexagon[width][height];
JFrame f = new JFrame();
Container cp = f.getContentPane();
for(int i = 0; i < width; i++) {
for(int j = 0; j < height; j++) {
grid[i][j] = new Hexagon(x+(j*((3*Hexagon.S)/2)), y+((j%2)*Hexagon.A)+(2*i*Hexagon.A));
cp.add(grid[i][j]);
}
}
f.setLayout(null);
f.setBounds(100, 100, 300, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
The Hexagon.java class:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import javax.swing.JButton;
public class Hexagon extends JButton {
public static final int S = 50;
public static final int A = (int) (Math.sqrt(3)*(S/2));
private static final long serialVersionUID = 1L;
private final int x, y;
private final Polygon shape;
public Hexagon(int x, int y) {
this.x = x;
this.y = y;
this.shape = initHexagon();
setSize(2*S, 2*A);
setLocation(x-S, y-A);
setContentAreaFilled(false);
}
private Polygon initHexagon() {
Polygon p = new Polygon();
p.addPoint(x+(S/2), y-A);
p.addPoint(x+S, y);
p.addPoint(x+(S/2), y+A);
p.addPoint(x-(S/2), y+A);
p.addPoint(x-S, y);
p.addPoint(x-(S/2), y-A);
return p;
}
protected void paintComponent(Graphics g) {
g.setColor(Color.BLACK);
g.drawPolygon(this.shape);
}
protected void paintBorder(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLACK);
g2.setStroke(new BasicStroke(4));
g2.drawPolygon(this.shape);
}
public boolean contains(int x, int y) {
return this.shape.contains(x, y);
}
}
As i said, this class worked just fine using non-rectangular shapes.
There was no clipping or such.
You've posted your definition of Hexagon too late, so I copy-pasted a modified version of a similar class from my collection of code snippets.
Here is one way to generate a hexagonal grid:
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JComponent;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.GridLayout;
import java.util.function.*;
public class Hexagons extends JPanel {
private static final long serialVersionUID = 1L;
/** Height of an equilateral triangle with side length = 1 */
private static final double H = Math.sqrt(3) / 2;
static class Hexagon {
final int row;
final int col;
final double sideLength;
public Hexagon(int r, int c, double a) {
this.row = r;
this.col = c;
this.sideLength = a;
}
double getCenterX() {
return 2 * H * sideLength * (col + (row % 2) * 0.5);
}
double getCenterY() {
return 3 * sideLength / 2 * row;
}
void foreachVertex(BiConsumer<Double, Double> f) {
double cx = getCenterX();
double cy = getCenterY();
f.accept(cx + 0, cy + sideLength);
f.accept(cx - H * sideLength, cy + 0.5 * sideLength);
f.accept(cx - H * sideLength, cy - 0.5 * sideLength);
f.accept(cx + 0, cy - sideLength);
f.accept(cx + H * sideLength, cy - 0.5 * sideLength);
f.accept(cx + H * sideLength, cy + 0.5 * sideLength);
}
}
public static void main(String[] args) {
final int width = 50;
final int height = 50;
final Hexagon[][] grid = new Hexagon[height][width];
for(int row = 0; row < height; row++) {
for(int col = 0; col < width; col++) {
grid[row][col] = new Hexagon(row, col, 50);
}
}
JFrame f = new JFrame("Hexagons");
f.getContentPane().setLayout(new GridLayout());
f.getContentPane().add(new JComponent() {
#Override public void paint(Graphics g) {
g.setColor(new Color(0xFF, 0xFF, 0xFF));
g.fillRect(0,0,1000,1000);
g.setColor(new Color(0,0,0));
final int[] xs = new int[6];
final int[] ys = new int[6];
for (Hexagon[] row : grid) {
for (Hexagon h: row) {
final int[] i = {0};
h.foreachVertex((x, y) -> {
xs[i[0]] = (int)((double)x);
ys[i[0]] = (int)((double)y);
i[0]++;
});
g.drawPolygon(xs, ys, 6);
g.drawString(
"(" + h.row + "," + h.col + ")",
(int)(h.getCenterX() - 15),
(int)(h.getCenterY() + 12)
);
}
}
}
});
f.setBounds(0, 0, 500, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
try {
Thread.sleep(100);
} catch (Throwable e) {
} finally {
f.repaint();
}
}
}
It produces the following output:
Sorry for the lack of anti-aliasing. A few hints:
Height H of an equilateral triangle with unit side length is sqrt(3) / 2
The six offsets from the center are (0, +1), (H, +1/2), (H, -1/2), (0, -1), (-H, -1/2), (-H, +1/2), everything times side length.
Distance between rows is 1.5, distance between columns is 2 * H (times scaling constant = side length).
Every odd row is shifted by (0, H) (times scaling constant).
The position of (row,col)-th hexagon is (1.5 * row, 2 * H * (col + 0.5 * (row % 2))) (times constant).
If you want to rotate the hexagons such that two of their sides are horizontal, you have to flip rows and columns.
I am trying to create a program such that there is a square going inside another square (slightly rotated), and another square going inside and so on. I've managed to create a program that does that. But I want the program to make several boxes like that. Take a look at the illustration to get a better idea:
My problem is that after drawing the first box, and then trying to draw the second, the "cursor" drawing the lines is kind of stuck at the last point, so it's drawing the line from the last point of my first square to the first point in the second square, like this:
So as you can see inside pointPanel-constructor I've tried clearing the list, and resetting the counter and i-variable, but no luck. Is there any modifications I can do such that I don't have this problem? I've tried placing the clear()-instruction other places. But maybe I'm missing something.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Art {
ArrayList<Point> points = new ArrayList<>();
int i =0;
public static void main(String[] args) {
new Art();
}
public Art() {
JFrame frame = new JFrame("Art");
frame.add(new pointPanel());
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class pointPanel extends JPanel{
//Constructor
public pointPanel(){
points(0, 100);
//points.clear();
points(500, 200);
}
#Override
//Dimension
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
public void points(double x, double y){
double t=0.1; //constant
final int side = 100;
int counter=0;
while (counter<20){
//Init the first points-->
Point p = new Point((int)(x), (int) (y) );
Point p1 = new Point((int)(x+side), (int)(y) );
Point p2 = new Point((int)(x+side), (int) (y-side) );
Point p3 = new Point((int)(x), (int)(y-side) );
Point p4 = new Point((int)(x), (int)(y) );
//-->and adding them to the list
if (counter == 0) {
points.add(p);
points.add(p1);
points.add(p2);
points.add(p3);
points.add(p4);
}
//Dynamic part:
//If the method has been run earlier - place points making it possible to draw lines
if (counter>0){
x=(1-t)*points.get(i).x + t * points.get(i+1).x;
y=(1-t)*points.get(i).y + t * points.get(i+1).y;
points.add( new Point( (int) x, (int) y) );
i++;
}
if (counter>0){
x=(1-t)*points.get(i).x + t * points.get(i+1).x;
y=(1-t)*points.get(i).y + t * points.get(i+1).y;
points.add( new Point( (int) x, (int) y) );
i++;
}
if (counter>0){
x=(1-t)*points.get(i).x + t * points.get(i+1).x;
y=(1-t)*points.get(i).y + t * points.get(i+1).y;
points.add( new Point( (int) x, (int) y) );
i++;
}
if (counter>0){
x=(1-t)*points.get(i).x + t * points.get(i+1).x;
y=(1-t)*points.get(i).y + t * points.get(i+1).y;
points.add( new Point( (int) x, (int) y) );
i++;
}
if (counter>0){
x=(1-t)*points.get(i).x + t * points.get(i-3).x;
y=(1-t)*points.get(i).y + t * points.get(i-3).y;
points.add( new Point( (int) x, (int) y) );
i++;
}
counter++;
}//while
//counter=0;
//i=0;
x=0;
y=0;
}//metode
//Paint-method
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
for (int i = 0; i < points.size()-1; i++) {
g2d.drawLine(points.get(i).x, points.get(i).y, points.get(i+1).x, points.get(i+1).y);
}
g2d.dispose();
}
}
}
You have to separate the points of your squares, e.g. create a class Square with four points and a method that draws this square in a Graphics2d. How you do it, every point is connected with its successor, no matter whether it belongs to the same square or not.
public class Square {
private final Point v1;
private final Point v2;
private final Point v3;
private final Point v4;
public Square(Point v1, Point v2, Point v3, Point v4) {
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
this.v4 = v4;
}
public void paint(Graphics2D g) {
g.setColor(Color.RED);
g.drawLine(v1.x, v1.y, v2.x, v2.y);
g.drawLine(v2.x, v2.y, v3.x, v3.y);
g.drawLine(v3.x, v3.y, v4.x, v4.y);
g.drawLine(v4.x, v4.y, v1.x, v1.y);
}
public void nextSquare() {
int x1=(1-t)*v1.x + t * v2.x;
int y1=(1-t)*v1.y + t * v2.y;
int x2=(1-t)*v2.x + t * v3.x;
int y2=(1-t)*v2.y + t * v3.y;
int x3=(1-t)*v3.x + t * v4.x;
int y3=(1-t)*v3.y + t * v4.y;
int x4=(1-t)*v4.x + t * v1.x;
int y4=(1-t)*v4.y + t * v1.y;
return new Square(
new Point(x1, y1),
new Point(x2, y2),
new Point(x3, y3),
new Point(x4, y4));
}
}
Create the squares:
List<Square> squares = new ArrayList<>();
Point p = new Point((int)(x), (int) (y) );
Point p1 = new Point((int)(x+side), (int)(y) );
Point p2 = new Point((int)(x+side), (int) (y-side) );
Point p3 = new Point((int)(x), (int)(y-side) );
Square s = new Square(p, p1, p2, p3);
squares.add(s);
for (int i = 1; i < 20; i++) {
s = s.nextSquare();
squares.add(s);
}
Code is not 100% as I'm typing this on my mobile...
Paint-method, assuming that squares is an instance variable:
//Paint-method
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (Square s : squares) {
s.paint(g2d);
}
g2d.dispose();
}
I drew a line that is at an angle based on a slider.
I am trying to make the line's end Y coordinate a certain number (let's say 300), even if it is at an angle.
Any ideas on how to do this? Here is the work on my line so far:
double angle = intAngle;
angle = angle * Math.PI / 180;
double length = 300;
graphics.setColor(Color.RED);
double startX = 300;
double startY = 100;
double endX = startX + length * Math.cos(angle);
double endY = startY + length * Math.sin(angle);
double end2X;
double end2Y;
double dblAngle;
double angle2;
int intAngle2;
double start2X = endX;
double start2Y = endY;
intAngle2 = 180 - intAngle;
angle2 = intAngle2;
angle2 = (angle2 * Math.PI / 180);
end2X = (start2X - length * Math.cos(angle2));
end2Y = (start2Y - length * Math.sin(angle2));
int intEndX = (int)endX;
int intEndY = (int)endY;
if(blnButton == true){
graphics.draw(new Line2D.Double(startX, startY, endX, endY));
graphics.draw(new Line2D.Double(start2X, start2Y, end2X, end2Y));
}
There's probably a simpler way, but basically, you can calculate two points on a circle based on the angle and the inverse of the angle (angle - 360)
With a circle with a radius of 150, this will give you a line of 300, for example
The red line is the line from the center of the circle to point on the circle represented by the given angel. The blue is the inverse. Each line is 150 pixels line, meaning together, they are 300 pixels in length.
This examples draws the separately, but realistically, they could be draw as a single line
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
DrawPane drawPane = new DrawPane();
add(drawPane);
JSlider slider = new JSlider(0, 100);
add(slider, BorderLayout.SOUTH);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
drawPane.setAngleInDegrees(360d * (slider.getValue() / 100d));
}
});
slider.setValue(0);
}
}
public class DrawPane extends JPanel {
private double angle;
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// Radius of the circle
double r = 150;
// Degrees to radians...
double radians = Math.toRadians(angle);
// The end point on the circle...
int endX = (int) Math.round(r * Math.cos(radians));
int endY = (int) Math.round(r * Math.sin(radians));
// The start point on the circle, 360 degress from the
// start angle
radians = Math.toRadians(angle - 360);
int startX = (int) Math.round(r * Math.cos(radians));
int startY = (int) Math.round(r * Math.sin(radians));
// Offset for the ellipse (center of the screen)
double x = (getWidth() / 2d) - r;
double y = (getWidth() / 2d) - r;
g2d.setColor(Color.LIGHT_GRAY);
g2d.draw(new Ellipse2D.Double(x, y, r * 2, r * 2));
// Center of the circle...
x = (getWidth() / 2d);
y = (getWidth() / 2d);
// One single line
//g2d.setColor(Color.BLACK);
//g2d.draw(new Line2D.Double(x - startX, y - startY, x + endX, y + endY));
g2d.setColor(Color.RED);
g2d.draw(new Line2D.Double(x, y, x - startX, y - startY));
g2d.setColor(Color.BLUE);
g2d.draw(new Line2D.Double(x, y, x + endX, y + endY));
g2d.dispose();
}
public void setAngleInDegrees(double value) {
if (angle != value) {
angle = Math.min(Math.max(value, 0), 360);
repaint();
}
}
}
}
or something along those lines...
I have to write a program that will generate 20 random circles with random radius lengths. If any of these circles intersect with another, the circle must be blue, and if it does not intersect, the color is red. I must also place a button on the JFrame. If this button is pressed, it needs to clear out the JFrame, and generate a new set of 20 circles following the same color rules. I am extremely new to Java Swing and am really stuck. I have everything working except the button. I cannot get a new set of circles to generate. Any help would be greatly appreciated. Thank You.
import java.awt.Graphics;
import javax.swing.JPanel;
import java.util.Random;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class IntersectingCircles extends JPanel
{
private int[] xAxis = new int [20]; // array to hold x axis points
private int[] yAxis = new int [20]; // array to hold y axis points
private int[] radius = new int [20]; // array to hold radius length
public static void main (String[] args)
{
JFrame frame = new JFrame("Random Circles");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add (new IntersectingCircles());
frame.pack();
frame.setVisible(true);
}
public IntersectingCircles()
{
setPreferredSize(new Dimension(1000, 800)); // set window size
Random random = new Random();
// Create coordinates for circles
for (int i = 0; i < 20; i++)
{
xAxis[i] = random.nextInt(700) + 100;
yAxis[i] = random.nextInt(500) + 100;
radius[i] = random.nextInt(75) + 10;
}
}
public void paintComponent(Graphics g)
{
// Add button to run again
JButton btnAgain = new JButton("Run Again");
btnAgain.setBounds(850, 10, 100, 30);
add(btnAgain);
btnAgain.addActionListener(new ButtonClickListener());
// Determine if circles intersect, create circles, color circles
for (int i = 0; i < 20; i++)
{
int color = 0;
for (int h = 0; h < 20; h++)
{
if(i != h)
{
double x1 = 0, x2 = 0, y1 = 0, y2 = 0, d = 0;
x1 = (xAxis[i] + radius[i]);
y1 = (yAxis[i] + radius[i]);
x2 = (xAxis[h] + radius[h]);
y2 = (yAxis[h] + radius[h]);
d = (Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1)*(y2 - y1))));
if (d > radius[i] + radius[h] || d < (Math.abs(radius[i] - radius[h])))
{
color = 0;
}
else
{
color = 1;
break;
}
}
}
if (color == 0)
{
g.setColor(Color.RED);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
else
{
g.setColor(Color.BLUE);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
}
}
private class ButtonClickListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String action = e.getActionCommand();
if(action.equals("Run Again"))
{
new IntersectingCircles();
}
}
}
}
Suggestions:
Give your class a method that creates the random circles and calls repaint()
This method should create the circles and add them into an ArrayList.
Consider using Ellipse2D to represent your circles, and so you'd have an ArrayList<Ellipse2D>.
Call this method in your class constructor.
Call it again in the button's ActionListener.
Never add button's or change the state of your class from within your paintComponent method. This method is for drawing the circles and drawing them only and nothing more. Your way you will be creating the button each time the paintComponent method is called, so you could be potentially needlessly creating many JButtons
and needlessly slowing down your time-critical painting method.
Instead add the button in the constructor.
Be sure to call super.paintComponent(g) in your paintComponent method as its first call. This will clear the old circles when need be.
Also in paintComponent, iterate through the ArrayList of circles, drawing each one.
After some searching on this website, i found what i needed. Everything seems to work now. Thanks.
import java.awt.Graphics;
import javax.swing.JPanel;
import java.util.Random;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class IntersectingCircles extends JPanel
{
private int[] xAxis = new int [20]; // array to hold x axis points
private int[] yAxis = new int [20]; // array to hold y axis points
private int[] radius = new int [20]; // array to hold radius length
public static void main (String[] args)
{
JFrame frame = new JFrame("Random Circles");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(1000, 800));
ActionListener runAgain = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent c)
{
frame.getContentPane().add(new IntersectingCircles());
frame.pack();
}
};
JButton btnAgain = new JButton("Run Again");
btnAgain.setBounds(850, 10, 100, 30);
btnAgain.addActionListener(runAgain);
frame.add(btnAgain);
frame.getContentPane().add (new IntersectingCircles());
frame.pack();
frame.setVisible(true);
}
public IntersectingCircles()
{
Random random = new Random();
// Create coordinates for circles
for (int i = 0; i < 20; i++)
{
xAxis[i] = random.nextInt(700) + 100;
yAxis[i] = random.nextInt(500) + 100;
radius[i] = random.nextInt(75) + 10;
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// Determine if circles intersect, create circles, color circles
for (int i = 0; i < 20; i++)
{
int color = 0;
for (int h = 0; h < 20; h++)
{
if(i != h)
{
double x1 = 0, x2 = 0, y1 = 0, y2 = 0, d = 0;
x1 = (xAxis[i] + radius[i]);
y1 = (yAxis[i] + radius[i]);
x2 = (xAxis[h] + radius[h]);
y2 = (yAxis[h] + radius[h]);
d = (Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1)*(y2 - y1))));
if (d > radius[i] + radius[h] || d < (Math.abs(radius[i] - radius[h])))
{
color = 0;
}
else
{
color = 1;
break;
}
}
}
if (color == 0)
{
g.setColor(Color.RED);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
else
{
g.setColor(Color.BLUE);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
}
}
}
private class ButtonClickListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
repaint();
}
}
Maybe you can have a try...