HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Creation of Queen Ann's Lace fractal

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
fractalqueenanncreationlace

Problem

I've created a program which recreates the Queen Ann's Lace fractal. However, when the amount of points that are being plotted increases, the points are plotted way slower. Is there any way to make it so that I only add a point, instead of adding a point and repainting all of the others? I've looked everywhere for an answer, and nothing has made sense to me. An explanation would be very helpful.

```
import javax.swing.*; //JFrame and JPanel
import java.awt.*; //Color and Container
import javax.swing.JOptionPane;
import java.awt.event.*;
import java.util.Scanner;
import java.io.*;
import java.util.Random;
import java.util.ArrayList;
import java.util.List;

/**
* Write a description of class ChaosGame here.
*
* @author (your name)
* @version (a version number or a date)
*/
public class QueensLaceFractal
{
public static void main(String[] args) { //main method
Dimension d = new Dimension(700, 700);
JFrame theGUI = new JFrame("Queens Lace Fractal");
ColorPanel panel = new ColorPanel(Color.white);
theGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setPreferredSize(d);
Container pane = theGUI.getContentPane();
pane.add(panel);
theGUI.pack();
theGUI.setVisible(true);
}
}
class ColorPanel extends JPanel implements MouseMotionListener, MouseListener{ //colorpanel class
private boolean followMouse = true;
private int x, y;
private int seedx, seedy;
private int pointx, pointy;
private int i;
private int dotcounter;
private int newx, newy;

private Random random = new Random();
private javax.swing.Timer timer;
private javax.swing.Timer arraytimer;
private EndPoint[] EP = new EndPoint[8];
private Seed seed;
private Point[] p = new Point[50000];
private Color yellow = new Color(255, 255, 1);
private Color yellowOrange = new Color(255, 195, 0);
private Color orangeRed = new Color(255, 83, 0);
private Color violetRed =

Solution

The reason your current code will eventually slow down is because you are drawing every previously calculated pixel, every millisecond. So towards the end of your drawing, you're trying to plot 500,000 pixels in every paintComponent invocation.

To fix this, create yourself a transparent buffered image which you will paint your pixels onto. Then, in your repaint method, you can:

  • wipe the panel



  • paint your seed image



  • paint the coloured circles



  • add one more dot to your buffered image



  • paint the buffered image on top



Here's a modified version of your code that does exactly that. I also made a few edits along the way, some of which I'm afraid I've forgotten as I chased after the main prize. However, here's a few things I changed:

  • Used adaptor classes rather than implementing the mouse listeners in the panel itself. The adaptor classes (MouseAdapter and MouseMotionAdapter) conveniently have empty implementations for all methods in the equivalent listener interfaces.



  • No need to do if(foo == true). It should just be if (foo). There is also no need for empty else{} clauses; they can be removed.



Here's the final code:

```
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension; //Color and Container
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import java.util.Random;

import javax.swing.JFrame; //JFrame and JPanel
import javax.swing.JPanel;
import javax.swing.Timer;

/**
* Write a description of class ChaosGame here.
*
* @author (your name)
* @version (a version number or a date)
*/
public class QueensLaceFractal {
public static void main(String[] args) { // main method
Dimension d = new Dimension(700, 700);
JFrame theGUI = new JFrame("Queens Lace Fractal");

ColorPanel panel = new ColorPanel(Color.white);
theGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setPreferredSize(d);
Container pane = theGUI.getContentPane();
pane.add(panel);
theGUI.pack();

// Must be called after pack() so that size of panel is known
panel.startRendering();

theGUI.setVisible(true);

}
}

class ColorPanel extends JPanel {

private static final long serialVersionUID = 1L;

private boolean followMouse = true;
private int x, y;
private int seedx, seedy;
private int pointx, pointy;
private int dotcounter = 1;
private int newx, newy;

private Random random = new Random();
private javax.swing.Timer timer;
private EndPoint[] EP = new EndPoint[8];
private Seed seed;
private Color yellow = new Color(255, 255, 1);
private Color yellowOrange = new Color(255, 195, 0);
private Color orangeRed = new Color(255, 83, 0);
private Color violetRed = new Color(215, 0, 46);
private Color violet = new Color(129, 0, 127);
private Color violetBlue = new Color(44, 48, 156);
private Color blueGreen = new Color(0, 101, 87);
private Color yellowGreen = new Color(85, 171, 0);

private BufferedImage fractalImage;

public ColorPanel(Color backcolor) {
setBackground(backcolor);
setDoubleBuffered(true);
// constructor
addMouseListener(new SeedMouseListener());
addMouseMotionListener(new SeedMouseMotionListener());
this.setFocusable(true);
seed = new Seed(350, 350, Color.BLACK);
EP[0] = new EndPoint(350, 50, yellow);
EP[1] = new EndPoint(562, 138, yellowOrange);
EP[2] = new EndPoint(650, 350, orangeRed);
EP[3] = new EndPoint(562, 562, violetRed);
EP[4] = new EndPoint(350, 650, violet);
EP[5] = new EndPoint(138, 562, violetBlue);
EP[6] = new EndPoint(50, 350, blueGreen);
EP[7] = new EndPoint(138, 138, yellowGreen);
}

public void startRendering() {
// Create a buffered image to hold the fractal. Make the background
// transparent

fractalImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = fractalImage.createGraphics();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));

timer = new Timer(1, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
repaint();
}
});

timer.start();
}

private class SeedMouseMotionListener extends MouseMotionAdapter {
@Override
public void mouseMoved(MouseEvent e) {
// gets x and y of the mouse at all times
x = e.getX();
y = e.getY();
}
}

private class SeedMouseListener extends MouseAdapter {
@Override
public void mouseMoved(MouseEvent e) {
// gets x and y of the mouse at all times
x = e.getX();
y = e.ge

Code Snippets

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension; //Color and Container
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import java.util.Random;

import javax.swing.JFrame; //JFrame and JPanel
import javax.swing.JPanel;
import javax.swing.Timer;

/**
 * Write a description of class ChaosGame here.
 * 
 * @author (your name)
 * @version (a version number or a date)
 */
public class QueensLaceFractal {
  public static void main(String[] args) { // main method
    Dimension d = new Dimension(700, 700);
    JFrame theGUI = new JFrame("Queens Lace Fractal");

    ColorPanel panel = new ColorPanel(Color.white);
    theGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    panel.setPreferredSize(d);
    Container pane = theGUI.getContentPane();
    pane.add(panel);
    theGUI.pack();

    // Must be called after pack() so that size of panel is known
    panel.startRendering();

    theGUI.setVisible(true);

  }
}

class ColorPanel extends JPanel {

  private static final long serialVersionUID = 1L;

  private boolean followMouse = true;
  private int x, y;
  private int seedx, seedy;
  private int pointx, pointy;
  private int dotcounter = 1;
  private int newx, newy;

  private Random random = new Random();
  private javax.swing.Timer timer;
  private EndPoint[] EP = new EndPoint[8];
  private Seed seed;
  private Color yellow = new Color(255, 255, 1);
  private Color yellowOrange = new Color(255, 195, 0);
  private Color orangeRed = new Color(255, 83, 0);
  private Color violetRed = new Color(215, 0, 46);
  private Color violet = new Color(129, 0, 127);
  private Color violetBlue = new Color(44, 48, 156);
  private Color blueGreen = new Color(0, 101, 87);
  private Color yellowGreen = new Color(85, 171, 0);

  private BufferedImage fractalImage;

  public ColorPanel(Color backcolor) {
    setBackground(backcolor);
    setDoubleBuffered(true);
    // constructor
    addMouseListener(new SeedMouseListener());
    addMouseMotionListener(new SeedMouseMotionListener());
    this.setFocusable(true);
    seed = new Seed(350, 350, Color.BLACK);
    EP[0] = new EndPoint(350, 50, yellow);
    EP[1] = new EndPoint(562, 138, yellowOrange);
    EP[2] = new EndPoint(650, 350, orangeRed);
    EP[3] = new EndPoint(562, 562, violetRed);
    EP[4] = new EndPoint(350, 650, violet);
    EP[5] = new EndPoint(138, 562, violetBlue);
    EP[6] = new EndPoint(50, 350, blueGreen);
    EP[7] = new EndPoint(138, 138, yellowGreen);
  }

  public void startRendering() {
    // Create a buffered image to hold the fractal. Make the background
    // transparent

    fractalImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 = f

Context

StackExchange Code Review Q#82408, answer score: 6

Revisions (0)

No revisions yet.