Welcome to Fractal Forums

Fractal Software => Programming => Topic started by: jwm-art on November 22, 2010, 02:28:02 PM




Title: Understanding the Mandelbox formula (for 2D)
Post by: jwm-art on November 22, 2010, 02:28:02 PM
Hi, I'm trying to understand the mandelbox formula, but not being good at maths makes it slightly tricky.

Code:
In fact it replaces the Mandelbrot equation z = z2 + c with:  
  v = s*ballFold(r, f*boxFold(v)) + c
where boxFold(v) means for each axis a:
  if v[a]>1          v[a] =  2-v[a]
  else if v[a]<-1 v[a] =-2-v[a]
and ballFold(r, v) means for v's magnitude m:
  if m<r         m = m/r^2
  else if m<1 m = 1/m

Which I've interpreted as follows:

Code:
    s = 1;
    f = 1.0;
    r = 0.5;

    for (z = 1; z <= depth; ++z) {
        if (x > 1.0) x = f * (2.0 - x);
        else if (x < -1.0) x = f * (-2.0 - x);

        if (y > 1.0) y = f * (2.0 - y);
        else if (y < -1.0) y = f * (-2.0 - y);

        if (x < r) x = x / (r * r);
        else if (x < 1.0) x = 1.0 / x;

        if (y < r) y = (y / (r * r));
        else if (y < 1.0) y = 1.0 / y;

        x *= s;
        y *= s;

        if (x * x + y * y > 4.0)
            return z;
    }
    return 0;

But I'm not quite convinced is correct, and it's far less than inspiring to zoom into. Can anyone see what's gone wrong here?


Title: Re: Understanding the Mandelbox formula (for 2D)
Post by: fractower on November 22, 2010, 05:19:19 PM
The problem seems to be in the ball fold step.

Code:
        if (x < r) x = x / (r * r);
        else if (x < 1.0) x = 1.0 / x;

        if (y < r) y = (y / (r * r));
        else if (y < 1.0) y = 1.0 / y;

While a potentially interesting line fold, it does not perform the mixing of the x and y cords that give rise to a lot of the complexity of the mandelbox.

Code:
        m = sqrt(x*x+y*y);
        if(m<r) {
                // scale small circle.
                x=x/(r*r);
                y=y/(r*r);
        }
        elsif(m<1.0){
                // First 1/m normalizes second makes m=1/m.
                x=x/(m*m);
                y=y/(m*m);
        }

I will probably try variations of your line fold  in the future.


Title: Re: Understanding the Mandelbox formula (for 2D)
Post by: jwm-art on November 22, 2010, 09:05:12 PM
Thanks fractower, that's definitely looking better. Is the scaling and the bailout condition technically correct?

Code:
        x *= s;
        y *= s;

        if (x * x + y * y > 4.0)
            return iter;

Anyway, here's some images created, parameters are:

Code:
    s = -1.3;
    r = 0.25;
    f = 1.35;

(http://nocache-nocookies.digitalgott.com/gallery/4/1095_22_11_10_8_54_28_0.png)
http://www.fractalforums.com/index.php?action=gallery;sa=view;id=4353

(http://nocache-nocookies.digitalgott.com/gallery/4/1095_22_11_10_8_54_28_1.png)
http://www.fractalforums.com/index.php?action=gallery;sa=view;id=4354

They are some of the more interesting images/parameters I've found, but I was expecting them to look more similar than this to the 3D Mandelbox. Using the Mandelbox 'defaults' where s = 1.0; f = 1.0; r = 0.5; produces even less interesting images. There's too much self-similarity and not enough variation amongst it.



Title: Re: Understanding the Mandelbox formula (for 2D)
Post by: fractower on November 22, 2010, 09:28:29 PM
I think your bail out is a bit on the low side. The code is considering an escape to be z*z>4 or |z|>2. The box fold will map values in this range back near the origin.




Title: Re: Understanding the Mandelbox formula (for 2D)
Post by: Tglad on November 23, 2010, 02:52:11 AM
For -ve s the radius of the box should be 2, however the iterations may go outside this a little (just like parts of the buddhabrot go outside the mandelbrot set shape), so I'd use double that, e.g. x*x + y*y > 16.
Otherwise the formula looks right.

You'll need a distance measure, rather than colouring based on if each single point goes outside. Otherwise higher iterations will cause the image to disappear.


Title: Re: Understanding the Mandelbox formula (for 2D)
Post by: jwm-art on November 23, 2010, 03:40:00 AM
For -ve s the radius of the box should be 2, however the iterations may go outside this a little (just like parts of the buddhabrot go outside the mandelbrot set shape), so I'd use double that, e.g. x*x + y*y > 16.
Otherwise the formula looks right.

You'll need a distance measure, rather than colouring based on if each single point goes outside. Otherwise higher iterations will cause the image to disappear.

Not sure I follow where you say the radius of the box should be 2.

Regarding the escape, I've been using a bailout of 6.0 (where I've been alternating iterations with the M-set), 16.0 seems too high and brings in absurd levels of aliasing, 12.0 seems reasonable - but that's all in the details :-)

I've not had any problems with iteration levels influencing the image beyond the way they do to the plain vanilla m-set (ie add more detail where there is detail to be added).


Title: Re: Understanding the Mandelbox formula (for 2D)
Post by: Tglad on November 23, 2010, 05:48:17 AM
16 isn't too high, the only disadvantage of a larger bailout is that you might have to do a couple more iterations.
e.g. you can render a mandelbrot set with bailout of 200 instead of 2... it just means you might require 3 more iterations or so.

I think the best way to render it is to use a distance measure... I've never tried programming it directly, but I think this could be how you do it:
It replaces each point with a small disk (e.g. each pixel is a little disk), so each point is x,y and d (the disk radius).

Code:
    
    s = 1;
    f = 1.0;
    r = 0.5;
    diskRadius = 0.001; // this should match the pixel radius for best results
    d = diskRadius; // separate d for each x,y point

    for (;;)  // infinite loop
    {
        if (x > 1.0) x = f * (2.0 - x);
        else if (x < -1.0) x = f * (-2.0 - x);

        if (y > 1.0) y = f * (2.0 - y);
        else if (y < -1.0) y = f * (-2.0 - y);

        m = sqrt(x*x+y*y);
        if(m<r) {
                // scale small circle.
                x=x/(r*r);
                y=y/(r*r);
                d=d/(r*r);
        }
        elsif(m<1.0){
                // First 1/m normalizes second makes m=1/m.
                x=x/(m*m);
                y=y/(m*m);
                d=d/(m*m);
        }

        x *= s;
        y *= s;
        d *= s;
        distance = sqrt(x*x + y*y);
        if (distance > 4.0-d) // this means we escape if ANY point in the disk escapes
            return iter;