Search code examples
graphicsinfinitefractals

Fractal generation from infinite sum


I found a project description on a course website for computer graphics. I am trying to complete the project for fun.

Here is the link to the problem description:

http://www.pdfhost.net/index.php?Action=Download&File=901bc7785bef41364b3a40f6f4493926

Below is my code. The problem I am running in to is that the terms of the series grow so fast I can't map the points to the screen correctly. From the problem description it says the points will be mappable within a -2 - 2 square but the difference in value between the points is so huge that normalizing by the largest would collapse most of the points to a single pixel.

I assume I have a fundamental misunderstanding that I can't identify. Any help or insight would be appreciated!

int w = 800, h = 600;
int numTimes = 10, cSize = 5;
float xr = 2, yr = 2;

void setup() {
  size(w,h);
}

void draw() {
  background(255);

  Complex v = new Complex(mouseX*(xr/w) - (xr/2), mouseY*(yr/h) - (yr/2));  
  Complex[] exps = new Complex[numTimes];

  for (int i = 0; i < numTimes; i++) {
    exps[i] = complexExp(v,i);
  }

  ellipse(w/2, h/2, cSize, cSize);
  for (int i = 0; i < numTimes; i++) {
    drawSeries(new Complex(0,0), exps, i, i);
  }
}

void drawSeries(Complex vToDraw, Complex[] exps, int count, int clrTrunc) {
  if (count == 0) {
    Complex v = exps[0];   

    float progress = float(clrTrunc) / float(numTimes);
    fill(255*progress, 180, 255 - 255*progress);

    vToDraw.add(v);
    ellipse(vToDraw.r*(w/xr) + (w/2), vToDraw.i*(h/xr) + h/2, cSize, cSize);
    vToDraw.sub(v);
    vToDraw.sub(v);
    ellipse(vToDraw.r*(w/xr) + (w/2), vToDraw.i*(h/xr) + h/2, cSize, cSize);
  } else {
    Complex v = exps[count];

    vToDraw.add(v);
    drawSeries(vToDraw, exps, count - 1, clrTrunc );
    vToDraw.sub(v);
    vToDraw.sub(v);
    drawSeries(vToDraw, exps, count - 1,clrTrunc );
  }
}

Complex complexExp(Complex v, int times) {
  if (times == 0) {
    return new Complex(1, 1);
  } else if ( times == 1) {
    return new Complex( v.r*v.r - v.i*v.i, 2*v.r*v.i );
  } else {
    return complexExp( new Complex( v.r*v.r - v.i*v.i, 2*v.r*v.i ), times - 1 );
  }
}

class Complex {
  float r, i;

  Complex() {
    this.r = 0;
    this.i = 0;
  } 

  Complex(float r, float i) {
    this.r = r;
    this.i = i;
  }

  void add(Complex nv) {
      this.r += nv.r;
      this.i += nv.i;
  }

  void sub(Complex nv) {
      this.r -= nv.r;
      this.i -= nv.i;
  }
}

Solution

  • I think you can make the code cleaner if you write a more complete Complex class.

    int w = 800, h = 600;
    int numTimes = 10, cSize = 5;
    float xr = 3, yr = 3;
    
    void setup() {
      size(w,h);
      noLoop();
    }
    void mousePressed() {
      redraw();
    }
    
    void draw() {
      background(255);
    
      Complex v = new Complex(mouseX*(xr/w) - (xr/2), mouseY*(yr/h) - (yr/2));  
      Complex[] exps = new Complex[numTimes];
    
      for (int i = 0; i < numTimes; i++) {
        exps[i] = v.raisedTo(i);
        print(exps[i]);
      }
    
      ellipse(w/2, h/2, cSize, cSize);
      print(exps);
      drawSerie(exps, numTimes);
    }
    
    void drawSerie(Complex[] exps, int total)
    {
      Complex partial = new Complex(0, 0);
      drawPartial(exps, total -1, partial);
    }
    
    void drawFinal(Complex toDraw)
    {
       point(toDraw.r*(w/xr) + (w/2), toDraw.i*(h/xr) + h/2);
    }
    
    void drawPartial(Complex [] exps, int depth, Complex partial)
    {
      if (depth == -1)
      {
        drawFinal(partial);
        return;
      }
      int nextDepth = depth -1;
      drawPartial(exps, nextDepth, partial);
      Complex element = exps[depth];
      drawPartial(exps, nextDepth, partial.add(element));
      drawPartial(exps, nextDepth, partial.sub(element));
    }
    
    
    class Complex {
      float r, i;
    
      Complex() {
        this.r = 0;
        this.i = 0;
      } 
    
      Complex(float r, float i) {
        this.r = r;
        this.i = i;
      }
    
      Complex(Complex other)
      {
        this.r = other.r;
        this.i = other.i;
      }
    
      Complex mult(Complex other)
      {
        return new Complex(this.r*other.r - this.i*other.i, this.r*other.i + this.i*other.r);
      }
    
      Complex add(Complex nv) {
          return new Complex(this.r + nv.r, this.i + nv.i);
      }
    
      Complex sub(Complex nv) {
          return new Complex(this.r - nv.r,  this.i - nv.i);
      }
    
      Complex raisedTo(int n) {
      if (n == 0) {
        return new Complex(1, 0);
      }
        else if (n % 2 == 0)
      {
        return (this.mult(this)).raisedTo(n/2);
      } 
      else 
      {
        return this.mult(this.raisedTo(n - 1 ));
      }
    
    }
      String  toString()
      {
        return "real: " + this.r + " imaginary: " + this.i;
      }
    }
    

    The computation of the series is not efficient but, I think, it is clear