# Mandelbrot set explorer V0 - Super Zoom

**URL:** <https://discourse.processing.org/t/mandelbrot-set-explorer-v0-super-zoom/33487>\
**Category:** Gallery\
**Created:** [November 13, 2021, 10:14am UTC](https://discourse.processing.org/t/mandelbrot-set-explorer-v0-super-zoom/33487 "2021-11-13T10:14:56Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![CodeMasterX](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/codemasterx/32/2942_2.png) [@CodeMasterX](https://discourse.processing.org/u/CodeMasterX)\
**Post date:** [November 13, 2021, 10:14am UTC](https://discourse.processing.org/t/mandelbrot-set-explorer-v0-super-zoom/33487/1 "2021-11-13T10:14:56Z")

</div>

Hello everyone!  
After a long time of struggling with the scroll to zoom feature, I finally made it! This program can zoom into the mandelbrot set with huge accuracy. The largest zoom is 10^-17. That means that for every pixel we move on the screen, the coordinate changes by 10^-17. Beyond that, double reaches it’s limits and this appears:

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/8/877c68155d1f6b976158eab70695a65a767d6391.png)

I am still trying to shift the values used by double, so instead of using: x&y offset mostly between -2 and 2, and shift it into something like -2 \* 10^6 and 2 \* 10^6. Well it will take a while so for now, I will share this!

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/7/7d4ef8ca18f2c350a24f69f32b59d5dbdd8bb45c.png)  
 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/f/f50b2e354dc4e8e38d87f96409b59a1f9e35b92e.png)  
 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/2/2d6369f25c51e565a98dd27067ff9aeaf884707e.png)  
 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/e/ed5f251ada13ee38b371a340661fd9eacf458334.png)  
 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/f/f8af7fdaad015aa4966cc0970151ae74545a7782.png)  
And this is just one of the infinite voyages the mandelbrot set offers!

I haven’t added a limit to iterations when unzoomed, so it lags quite a bit. Try to avoid black areas, since they take the longest to calculate.

I’ll try to add a drag feature, as well as a control center so you don’t need to do everything with scrolling. Well enjoy!

> **Code**
>
> ```auto
> int iter = 64*3;
> double offx = -2, offy=-1.5, scale=1.0/200.0;
> color clr[] = new color[64]; //how many colors, excluding black. Any additional color just loop around
> color inside = #000000;
> double zoom = 0.9;
> void setup() {
> size(600,600);
> colorMode(HSB);
> for(int i = 0; i < 64; i++) clr[i] = color(i*4,255,255);
> }
> void mouseWheel(MouseEvent event) {
> float e = -event.getCount();
> float x = (float)mouseX/(float)width, y = (float)mouseY/(float)height;
> double px = x*(1-zoom)*width*e, py = y*(1-zoom)*height*e;
> offx+=px*scale;
> offy+=py*scale;
> if(e<0) scale/=zoom;
> else if(e>0) scale*=zoom;
> println(scale,1/scale);
> }
> void draw() {
> loadPixels();
> for(int i = 0; i < width; i++) for(int j = 0; j < height; j++) {
> complex c = getPosC((float)i,(float)j,offx,offy,scale), z = new complex(c.re,c.im);
> int it = 0;
> boolean loop = true;
> for(it = 0; it < iter-1 && loop; it++) {z.setValue(z2pc(z,c)); if(inBounds(z)==false) loop = false;}
> //if(i==mouseX&&j==mouseY) println(it);
> pixels[i+j*width] = (it==iter-1? inside : clr[it%63]);
> }
> updatePixels();
> if(mousePressed) getPosC(mouseX,mouseY,offx,offy,scale).printC();
> }
> 
> boolean inBounds(complex c) {
> return(c.re*c.re+c.im*c.im<4);
> }
> class complex {
> double re, im;
> complex(double re, double im) {
> this.re=re;
> this.im=im;
> }
> void setValue(complex c) {
> re = c.re;
> im = c.im;
> }
> void printC() {
> println(re+" + "+im+"i");
> }
> }
> //COMPLEX CALCULATIONS ----------------------------------------------------------------------
> complex csum(complex z, complex w) {
> return new complex(z.re+w.re,z.im+w.im);
> }
> complex cmult(complex z, complex w) {
> return new complex(w.re*z.re - w.im*z.im, w.re*z.im + z.re * w.im);
> }
> complex csq(complex z) {
> return cmult(z,z);
> }
> complex z2pc(complex z, complex c) { //z^2+c
> return csum((csq(z)),c);
> }
> //VALUE ASSIGNMENT ---------------------------------------------------------------------------
> complex getPosC(float x, float y, double xoff, double yoff, double scl) {
> return new complex(xoff+x*scl,yoff+y*scl);
> }
> 
> ```

If you are curious how I made the zoom work, use this for reference:

> **Code**
>
> ```auto
> float zoom = 0.9;
> void setup() {
> size(600,600);
> stroke(255); noFill();
> }
> void draw() {
> background(0);
> float x = mouseX, y = mouseY;
> float nW = (float)width*zoom;
> float nx = map(x,0,width,0,1), ny = map(y,0,height,0,1);
>   
> float px = nx*(width-nW), py = ny*(height-nW);
> float npx = px+nW*nx, npy = py + nW*ny;
> circle(npx,npy,5);
> rect(px,py,nW,nW);
> }
> 
> ```
> 
> I am trying to make the mouse be on the same point even after zoom. I used desmos as inspiration and did all of the coding to mimic the zoom. After hours of failing, I finally succeeded, but I had to recode the entire program again.
> 
> So far, zoom is asymetric, so zooming out after zooming in doesn’t yield the same result. I will try to fix this in the next version.

Enjoy!

---

<div class="post-metadata">

**Author:** ![CodeMasterX](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/codemasterx/32/2942_2.png) [@CodeMasterX](https://discourse.processing.org/u/CodeMasterX)\
**Post date:** [November 13, 2021, 10:16am UTC](https://discourse.processing.org/t/mandelbrot-set-explorer-v0-super-zoom/33487/2 "2021-11-13T10:16:37Z")

</div>

This works just as well in full screen, just replace the size(600,600) with fullScreen()

If you want to explore different fractals, just adjust the formula in `z2pc()` right now it is z^2+c. If you want to make a julia set, just replace it with z^2+a; where a is a fixed complex number. I recommend to add a feature, where you can press any point on the screen and it will return the complex number and just plug that as A.

---

<div class="post-metadata">

**Author:** ![CodeMasterX](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/codemasterx/32/2942_2.png) [@CodeMasterX](https://discourse.processing.org/u/CodeMasterX)\
**Post date:** [November 13, 2021, 7:58pm UTC](https://discourse.processing.org/t/mandelbrot-set-explorer-v0-super-zoom/33487/3 "2021-11-13T19:58:57Z")

</div>

# Version 001

I made a follow up version V001, which has: faster approximate rendering, symmetric zoom and drag option.

At the start, with the ‘quality’ 4 it looks like this

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/b/bbbdeb0523f03d8a19900e380148d56850b8e124.png)  
It increases to 3  
 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/7/7721eae6bebafbb537c77f25a8850d75bc17c210.png)  
2  
 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/0/0dccbe719417114ac9ac1d601841a65d358d3008.png)  
1  
 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/3/3d9f938afe7d3ac7c06ad61010cdc5dff3158177.png)  
And finally 0, where each pixel is calculated  
 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/9/9a8c47e0887d7365e725e4413e32f9725b2c9053.png)

No previous pixel is calculated again, just ignored and left as it is (since calculating it again would yield the same results), which is optimized. It short, it does a bit more math and takes a few % longer, but in return, you can get an approximation almost instantly.

> **Version 001**
>
> ```auto
> int iter = 64*3;
> double offx = -2, offy=-1.28, scale=1.0/200.0;
> color clr[] = new color[64]; //how many colors, excluding black. Any additional color just loop around
> color inside = #000000;
> double zooms[] = {0.9,1,1/0.9};
> boolean update = true;
> int lastUpdate = 0;
> int quality = 3, desiredQuality = 0; //lower the quality, better image (grid size 2^quality)
> void setup() {
> fullScreen();
> 
> //size(512, 512);
> colorMode(HSB);
> for (int i = 0; i < 64; i++) clr[i] = color(i*4, 255, 255);
> }
> void mouseWheel(MouseEvent event) {
> update = true;
> int e = event.getCount();
> double zoom = zooms[e+1];
> float x = (float)mouseX/(float)width, y = (float)mouseY/(float)height;
> double px = -x*abs(1-(float)zoom)*width*e, py = -y*abs(1-(float)zoom)*height*e;
> offx+=px*scale;
> offy+=py*scale;
> scale*=zoom;
> println(scale, 1/scale);
> }
> void mouseDragged() {
> offx -= (double)((double)mouseX-(double)pmouseX)*scale;
> offy -= (double)((double)mouseY-(double)pmouseY)*scale;
> update=true;
> }
> 
> void draw() {
> if(update) partialGen(offx, offy, scale, iter, 4, false);
> else if(millis()-lastUpdate>100) partialGen(offx,offy,scale,iter,constrain(quality-1,desiredQuality,100),true);
> if (mousePressed) getPosC(mouseX, mouseY, offx, offy, scale).printC();
> }
> void partialGen(double Xoff, double Yoff, double Scl, int Iter, int acc, boolean increase) {
> int accuracy = (int)pow(2,acc);
> loadPixels();
> for (int i = 0; i < width; i+=accuracy) for (int j = 0; j < height; j+=accuracy) {
> if( increase == false || (i/accuracy)%4!=0||(j/accuracy)%4!=0) {
> complex c = getPosC((float)i, (float)j, Xoff, Yoff, Scl), z = new complex(c.re, c.im);
> int it = 0;
> boolean loop = true;
> for (it = 0; it < Iter-1 && loop; it++) {
> z.setValue(z2pc(z, c)); 
> if (inBounds(z)==false) loop = false;
> }
> color endClr = (it == iter-1? inside : clr[it%63]);
>     
> for (int a = 0; a < accuracy; a++) for (int b = 0; b < accuracy; b++) {
> pixels[constrain(i+a,0,width-1)+constrain(j+b,0,height-1)*width] = endClr;
> }
> }
> }
> updatePixels();
> update = false;
> lastUpdate=millis();
> quality = acc;
> }
> 
> void generate(double Xoff, double Yoff, double Scl, int Iter) {
> loadPixels();
> for (int i = 0; i < width; i++) for (int j = 0; j < height; j++) {
> complex c = getPosC((float)i, (float)j, Xoff, Yoff, Scl), z = new complex(c.re, c.im);
> int it = 0;
> boolean loop = true;
> for (it = 0; it < Iter-1 && loop; it++) {
> z.setValue(z2pc(z, c)); 
> if (inBounds(z)==false) loop = false;
> }
> pixels[i+j*width] = (it==iter-1? inside : clr[it%63]);
> }
> updatePixels();
> update = false;
> lastUpdate=millis();
> quality = 0;
> }
> 
> boolean inBounds(complex c) {
> return(c.re*c.re+c.im*c.im<4);
> }
> class complex {
> double re, im;
> complex(double re, double im) {
> this.re=re;
> this.im=im;
> }
> void setValue(complex c) {
> re = c.re;
> im = c.im;
> }
> void printC() {
> println(re+" + "+im+"i");
> }
> }
> //COMPLEX CALCULATIONS ----------------------------------------------------------------------
> complex csum(complex z, complex w) {
> return new complex(z.re+w.re, z.im+w.im);
> }
> complex cmult(complex z, complex w) {
> return new complex(w.re*z.re - w.im*z.im, w.re*z.im + z.re * w.im);
> }
> complex csq(complex z) {
> return cmult(z, z);
> }
> complex z2pc(complex z, complex c) { //z^2+c
> return csum((csq(z)), c);
> }
> //VALUE ASSIGNMENT ---------------------------------------------------------------------------
> complex getPosC(float x, float y, double xoff, double yoff, double scl) {
> return new complex(xoff+x*scl, yoff+y*scl);
> }
> 
> ```
