Generate fractals in the complex plane

86 Views Asked by At

I was looking at this bunch of fractals from the Wikipedia page "Frattale" (just the italian for Fractal).

z = z^2 + c

z = z^3 +c

z = z^4 +c

So I thought "Hey, I should write a program that lets me generate every fractal I want in the complex plane!!" and, after a few weeks of coding, here I am, asking for help... kinda/ish.

The results look like this:

ow0 my z=z^2 + c

ow0 my z=z^3 + c

ow0 my z=z^4 + c

ow0 my z=z^15 + c

The results are "meh" though they are kinda right: notice there's the similar "hole" in the real z=z^2 + c and in mine. Take a look at this

You can see the two results are kinda similar

I don't really know if this is a mathematical issue or a programming one so I'll post this both on mathematics and Stack Overflow.

uh and here's my code in Processing 3 (Java):

( the mathematical part is inside the void draw's while. Don't bother about the interface part. In the code I :

  1. compute the magnitude / modulus of a complex number number and its relative phase
  2. take the power of the complex number
  3. Check if it is greater the 2 (if it's greater than 2 then the number tends towards infinity)
  4. Recompute the x and y component of the number
  5. Iterate

**** WARNING CRITICAL PART ****

I think the program breaks when I add x and y to, respectively the x and y component of the number, though I am not that sure. Please let me know if I am stupid.

**** WARNING CRITICAL PART ****

)


int COLORS = 1;
int ITERATIONS = 100;

GUIController guiController;
IFTextField textField;
IFLabel ifLabel;
Button drawButton;
CloseButton exitButton;
boolean render=false;
float writtenPower;

void setup() {
  //fullScreen();
  size(1280,720);
  colorMode(RGB, COLORS);
  guiController = new GUIController(this);
  textField = new IFTextField("Text Field", 25, 30, 150);
  ifLabel = new IFLabel("", 25, 70);
  drawButton = new Button(width-40,10);
  exitButton = new CloseButton(width-85,10);

  guiController.add(textField);
  guiController.add(ifLabel);

  textField.addActionListener(this);
}


void draw() {
  stroke(0,0,0);
  drawButton.display();
  exitButton.display();
  if(render){
  // Establish a range of values on the complex plane
  // A different range will allow us to "zoom" in or out on the fractal

  // It all starts with the width, try higher or lower values
    float w = 4;
    float h = (w * height) / width;

  // Start at negative half the width and height
    float xmin = -w/2;
    float ymin = -h/2;

  // Make sure we can write to the pixels[] array.
  // Only need to do this once since we don't do any other drawing.
    loadPixels();

  // x goes from xmin to xmax
    float xmax = xmin + w;
  // y goes from ymin to ymax
    float ymax = ymin + h;

  // Calculate amount we increment x,y for each pixel
    float dx = (xmax - xmin) / (width);
    float dy = (ymax - ymin) / (height);
    float y = ymin;
    for (int j = 0; j < height; j++) {

    // Start x
      float x = xmin;
      for (int i = 0; i < width; i++) {

      // Now we test, as we iterate z = z^2 + cm does z tend towards infinity?
        float modulus;
        float phase = arctan(x,y);
        float a = x;
        float b = y;
        int n=0;
        while (n < ITERATIONS) {
          modulus = sqrt(pow(a,2) + pow(b,2));
          phase *= writtenPower;
          modulus = pow(modulus,writtenPower);
          if (modulus > 2) 
            break;  // Bail
          a=modulus*cos(phase) + x;
          b=modulus*sin(phase) + y;
          n++;          
        }

      // We color each pixel based on how long it takes to get to infinity
        if (n == ITERATIONS) {
          pixels[i+j*width] = color(0);
        } else {
          pixels[i+j*width] = color(sqrt(float(n) / ITERATIONS));
        }
        x += dx;
      }
      y += dy;
    }
    updatePixels();
  }else{
    stroke(0);
    textSize(16);
    background(cos(2*PI*0.001*mouseX),0.8,sin(2*PI*0.001*mouseY));
    text("KALEIODOSCIENZA",width/2,height/2);
    drawButton.display();
    exitButton.display();
  }
}

void actionPerformed(GUIEvent e) {
  if (e.getMessage().equals("Completed")) {
    ifLabel.setLabel(textField.getValue());
    writtenPower=Float.valueOf(textField.getValue());
  }
}

void mousePressed() {
  if (exitButton.isClicked(mouseX, mouseY))
     exit();
  if (drawButton.isClicked(mouseX, mouseY)){
    if(render){
      render=false;
    }
    else
      render=true;
    }
  }

float arctan(float a, float b){
  float processingIsStupid = b/a;
  if(a<0 && b>0 || a<0 && b<0){
    return PI + atan(processingIsStupid);
  } else{
  return atan(processingIsStupid);
  }
}

// a button with side equal to 30 pixels

class Button 
{
  int minX, minY, side;

  Button(int x1, int y1)
 {
    minX = x1; minY = y1; side = 30; 
 } 

  boolean isClicked( int x, int y)
  {
   if (( x >= minX) && (x <= (minX+side)) && ( y >= minY) && (y <= (minY+side)))
     return true;
   else
     return false;
  }

  void display()
   {
     rectMode(CORNER); 
     rect( minX, minY, side, side);
   } 

}

class CloseButton extends Button
{

  CloseButton(int x1, int y1)
  {
      super(x1, y1);
   }

   void display()
   {
      super.display();
      strokeWeight(2);
      ellipse(minX+15,minY+15,20,20);
      strokeWeight(1);
   }
}

So yeah, I don't really know what I should do. Let me know if you didn't really get something (or if I didn't).

To test the code Download Processing 3 and paste both snippets in two different tabs (i.e. in two different files in the project folder)

Thanks in advance !!

1

There are 1 best solutions below

0
On BEST ANSWER

https://processing.org/reference/atan2_.html can replace your arctan.

The issue with your code is that you need to recalculate the phase inside the loop:

...
while (n < ITERATIONS) {
  modulus = sqrt(pow(a,2) + pow(b,2));
  phase = atan2(b, a);                       // you need to add this line
  modulus = pow(modulus, writtenPower);
  phase *= writtenPower;
  ...
}
...