Search code examples
javaswingpaint

Paint fractals simultaneously


I need to do a java code with Threads (implements Runnable()) for a college assigment. I need to draw 4 fractals at the same time ( with thread.sleep()). I already tried almost everything I knew, and this still doesn't working. So I cleaned up the source.

I have four classes ( four fractals). In my JPanel, i call a paint method to draw them ( they are recursive ). Can anyone save me please?

public class MainPanel extends JPanel {
FractalTree tree = new FractalTree();
FractalCircle circle = new FractalCircle();
FractalSquare square = new FractalSquare();
FractalCircle2 circle2 = new FractalCircle2();

@Override
public void paint(Graphics g) {
    setBackground(Color.black,g);
    Graphics2D g2 = (Graphics2D) g;
    g.setColor(Color.WHITE);
    DrawBounds(g);

    tree.drawTree(g,200,290,-90,9);
    circle.drawCircle(g2,675,175,300);
    square.drawSquares(g, 200, 525, 100,7);
    circle2.drawCircle(g2,675,518,300);
}

public void DrawBounds(Graphics g){
    g.drawLine(0,350,900,350);
    g.drawLine(450,0,450,700);
}

public void setBackground(Color c,Graphics g){
    g.fillRect(0, 0, 900, 700);
}

}

public class FractalSquare{
public void drawSquares(Graphics g,int x, int y, int side ,int size){
    g.setColor(Color.BLUE);
    if(size >2){
        size--;
        g.fillRect(x-side/2, y-side/2, side, side);  
        side = side/2;
        x = x-side;
        y = y-side;
        drawSquares(g,x,y,side,size);
        drawSquares(g,x+side*2,y,side,size);
        drawSquares(g,x,y+side*2,side,size);
        drawSquares(g,x+side*2,y+side*2,side,size);
    } else return;
}

}

public class FractalCircle {
 public void drawCircle(Graphics2D g, float x, float y, float radius) {
     g.setColor(Color.RED);
   g.draw(new Ellipse2D.Float(x-radius/2, y-radius/2, radius,radius));
    if(radius > 2) {
        radius *= 0.75f;
        drawCircle(g,x, y, radius);
    } else return ;
}

}

public class FractalCircle2 {

 public void drawCircle(Graphics2D g, float x, float y, float radius) {
   Color color = new Color(255,0,255);
   g.setColor(color);
   g.draw(new Ellipse2D.Float(x-radius/2, y-radius/2, radius,radius));
    if(radius > 1) {
        radius *= 0.75f;
        drawCircle(g,x + radius/2, y, radius/2);
        drawCircle(g,x - radius/2, y, radius/2);
    } else return ;
}

}

public class FractalTree {

public void drawTree(Graphics g, int x1, int y1, double angle, int depth) {
    g.setColor(Color.GREEN);
    if (depth == 0) return;
    int x2 = x1 + (int) (Math.cos(Math.toRadians(angle)) * depth * 5.0);
    int y2 = y1 + (int) (Math.sin(Math.toRadians(angle)) * depth * 5.0);
    g.drawLine(x1, y1, x2, y2);
    drawTree(g, x2, y2, angle - 20, depth - 1);
    drawTree(g, x2, y2, angle + 20, depth - 1);

}

}


Solution

  • You'll have to render your fractals into separate images and copy them to the screen as the rendering progresses.

    Swing will do most of the work for you if you wrap each fractal in a JComponent.

    Here's an example using one of your fractals:

    public class FractalPanel extends JPanel {
        final FractalSquare square = new FractalSquare(450, 350);
    
        public FractalPanel() {
            add(square);
        }
    
        public static void main(String[] args) {
            FractalPanel fractalPanel = new FractalPanel();
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(fractalPanel);
            frame.pack();
            frame.setVisible(true);
    
            Thread squareThread = new Thread(() -> {
                try {
                    fractalPanel.square.render();
                } catch (InterruptedException e) {
                    System.err.println("Interrupted");
                }
            });
            squareThread.start();
        }
    }
    
    class Fractal extends JComponent {
        final BufferedImage image;
        final Graphics2D offscreenGraphics;
    
        public Fractal(int width, int height) {
            setPreferredSize(new Dimension(width, height));
            image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            offscreenGraphics = image.createGraphics();
        }
    
        // Copy the offscreen image to the main graphics context
        @Override
        public void paint(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            synchronized (image) { // synchronize with the render thread
                g2.drawImage(image, 0, 0, null);
            }
        }
    }
    
    class FractalSquare extends Fractal {
        public FractalSquare(int width, int height) {
            super(width, height);
        }
    
        public void render() throws InterruptedException {
            drawSquares(getWidth() / 2, getHeight() / 2, 100, 7);
        }
    
        public void drawSquares(int x, int y, int side, int size) throws InterruptedException {
    
            // Sleep for 10ms between frames
            Thread.sleep(10);
    
            if (size > 2) {
                size--;
    
                synchronized (image) { // synchronize with the draw thread
                    offscreenGraphics.setColor(Color.BLUE);
                    System.out.printf("Filling [%d, %d, %d, %d]\n", x - side / 2, y - side / 2, side, side);
                    offscreenGraphics.fillRect(x - side / 2, y - side / 2, side, side);
                }
    
                // Tell Swing that we've updated the image and it needs to be redrawn
                repaint();
    
                side = side / 2;
                x = x - side;
                y = y - side;
                drawSquares(x, y, side, size);
                drawSquares(x + side * 2, y, side, size);
                drawSquares(x, y + side * 2, side, size);
                drawSquares(x + side * 2, y + side * 2, side, size);
            }
        }
    }