Generating fractal Swirl [closed]
Asked Answered
R

3

9

I need to draw a fractal swirl using the algorithm Iterated Function System.

Targeted Fractal Image

There are coefficients for this fractal:

0.745455 -0.459091  0.406061  0.887121 1.460279 0.691072 0.912675
-0.424242 -0.065152 -0.175758 -0.218182 3.809567 6.741476 0.087325

And here is my code:

import java.awt.Graphics;
import javax.swing.JPanel;

public class Surface extends JPanel {
double a1 = 0.745455;
double b1 = -0.459091;
double d1 = 0.406061;
double e1 = 0.887121;
double c1 = 1.460279;
double f1 = 0.691072;
double p1 = 0.912675;

double a2 = -0.424242;
double b2 = -0.065152;
double d2 = -0.175758;
double e2 = -0.218182;
double c2 = 3.809567;
double f2 = 6.741476;
double p2 = 0.087325;

double x1(double x, double y) {
    return a1 * x + b1 * y + c1;
}

double y1(double x, double y) {
    return d1 * x + e1 * y + f1;
}

double x2(double x, double y) {
    return a2 * x + b2 * y + c2;
}

double y2(double x, double y) {
    return d2 * x + e2 * y + f2;
}

public void paint(Graphics g) {
    drawFractal(g);
}

void drawFractal(Graphics g) {
    double x1 = 300;
    double y1 = 300;
    double x2 = 0;
    double y2 = 0;
    g.fillOval(300 + (int) x1, 300 + (int) y1, 3, 3);
    for (int i = 0; i < 10000; i++) {
        double p = Math.random();
        if (p < 0.91675) {
            x2 = x1(x1, y1);
            y2 = y1(x1, y1);
            g.fillOval(300 + (int) x2, 300 + (int) y2, 3, 3);
            x1 = x2;
            y1 = y2;
        } else {
            x2 = x2(x1, y1);
            y2 = y2(x1, y1);
            g.fillOval(300 + (int) x2, 300 + (int) y2, 3, 3);
            x1 = x2;
            y1 = y2;
        }
    }
}
}

Unfortunately, with this code I get a wrong picture:

Current Fractal Image

It would be great if someone could point out my mistake.

Ruffina answered 23/12, 2012 at 12:5 Comment(18)
This is not so much a Java question as an algorithm question. What algorithm are you using? Can you link us to a reference to where you obtained this algorithm?Superabundant
It seems from the output that you're always using the same transformation or missing one.Chianti
Are the coefficients correct and complete?Chianti
The naming collision between a local variable and a method is probably a bad idea.Chianti
Hovercraft Full Of Eels, I'm using iterated function system. I've added linkRuffina
what happen when you iterate not only 10000 but 100K times or 1M timesBacciform
Jan Dvorak, I'm using first transformation if generated value is less then 0.91675, and second if its moreRuffina
Jan Dvorak, I can't change probabilities, they are stated coefficients for this fractalRuffina
UmNyobe, 100k - s14.postimage.org/eoweh1zkx/100000.png, 1M - s1.postimage.org/y9wpano3z/1000000.pngRuffina
I've got them from task at university, also I've seen it here fractalworld.xaoc.ru/IFS_collection (look for "swirl")Ruffina
@Ruffina on the above site the ordering seems to be "a1 b1 c1 d1 e1 f1 p1", however you seem to be listing them in a different order. Look at d1 and c1 for example.Sporting
cmh, but on that site there are formulas x = ax+by+e, y = cx+dy+f. I use x = ax+by+c , y = dx+ey+f;Ruffina
Try if renaming the methods to not collide with variable names helps.Chianti
Any chance the randomness generator is not too random?Chianti
Try printing the sequence of branches taken to see if it complies with expectations.Chianti
@JanDvorak I've found one mistake, instead of x1 = x2; y1 = y2; there should be x1 = x2 +300; y1 = y2 +300; because I start from point (300,300). Now it looks better, but it is still wrong s1.postimage.org/coh3wzaa7/…Ruffina
Why not stick to the letters and orders used on the site? It's hard for people to check the way it is and is very possibly the source of the error.Roof
@Ruffina thanks for the fractal collection, by the wayChianti
C
14

Your generation seems correct (i.e. don't do x1 = x2 +300; y1 = y2 +300;), but your problem is you're way off the scale for the purposes of rendering. This means there are very few points that fall outside very center of the image.

Your window is [0..600]x[0..600]. Try multiplying x2 and y2 with 50, so that you're rendering the [-6..6]x[-6..6] region instead of the [-300..300]x[-300..300] region of space.

Note that it should be sufficient to draw single pixels (as lines to itself) instead of 3x3 ovals.

int xp = 300 + (int) (x2 * scale);
int yp = 300 + (int) (y2 * scale);
g.drawLine(xp, yp, xp, yp);

Depending on what gets rendered, you might need to adjust the scale slightly to get the entire image with reasonable bounds. Note the second transformation offsets by -6.7, so a scale of 30 should be about right.

Also note that by using x1 = x2 +300; y1 = y2 +300; you change the transformations and get a different fractal (at a scale at which you expect).

Chianti answered 23/12, 2012 at 13:54 Comment(2)
Finally I got right fractal!! :) Thanks for explanation, now I see my mistakesRuffina
nice Jan! I thought about this too, but I made the mistake to keep using scaled values xp, yp for the fractal and gave up solving this :).Bacciform
W
4

This is great, I was wrong thinking that exponential runtime required! The fractals appeared more dimensional than my imagination!

Thanks @Jan Dvorak!

The following also works (in my coordinates, xcenter=300, ycenter=100 and radius=50 are global drawing parameters) and works faster:

void drawFractal2(Graphics g) {

        double x1 = 0;
        double y1 = 0;
        double x2 = 0;
        double y2 = 0;
        double p;

        g.fillOval(xcenter + (int) (x1 * radius), ycenter + (int) (y1 * radius), 3, 3);

        for(int i=0; i<100000; ++i) {
            p = Math.random();

            if (p < p1) {
                x2 = x1(x1, y1);
                y2 = y1(x1, y1);

            }
            else {
                x2 = x2(x1, y1);
                y2 = y2(x1, y1);

            }

            g.fillOval(xcenter + (int) (x2 * radius), ycenter + (int) (y2 * radius), 3, 3);
            x1 = x2;
            y1 = y2;
        }

    }

and the picture is better

enter image description here

Willpower answered 23/12, 2012 at 14:18 Comment(7)
Thanks for testing my fix, buddy :-)Chianti
Note that "tree-like runtime" is, technically, nonsense. You can have "tree-like recursion", which then experiences "exponential runtime" ;)Chianti
Would you mind giving me some credit in the answer?Chianti
Sure I have already put my plus to itWillpower
I meant, saying within the answer what the problem with asker's code actually is and who found the problem ;-)Chianti
@Jan I said thanks to you in the answer, but I don't want to make full explanation since this was your part. My part is working code. Let people plus me for code while your answer will be the winner.Willpower
@SuzanCioc Thanks for code example, it was easier understand what is wrong :)Ruffina
W
1

BELOW IS MY INCORRECT ANSWER

But it show how fractals are bigger than the intuition, so I keep it.

I guess your algorithm should be tree-like (recursive) while your one is linear. You are just drawing one chain of points, transforming it one after one. So you get some spiral-like chain. It can't generate any fractal picture in principle.

I GOT YOUR PICTURE

You have 2 mistakes:

1) you pass 300 both into iteration and as drawing shift. This is minor.

2) You algorithm is linear. Linear algorithm can't draw tree-like picture. If you use random values, you should run algorithm multiple times. One chain draws only one random portion of the picture.

I got your picture with following recursive algorithm. It works slow but you are to improve it.

  void drawFractal(Graphics g, double x1, double y1, int depth) {

        double x2 = 0;
        double y2 = 0;

        if( depth > 20 ) {
            return;
        }

        g.fillOval(xcenter + (int) (x1 * radius), ycenter + (int) (y1 * radius), 3, 3);

        x2 = x1(x1, y1);
        y2 = y1(x1, y1);
        drawFractal(g, x2, y2, depth+1);



        x2 = x2(x1, y1);
        y2 = y2(x1, y1);
        drawFractal(g, x2, y2, depth+1);






    }

to run it I used

    public void paint(Graphics g) {
        //drawFractal(g);
        drawFractal(g, 0, 0, 0);
    }

parameters are

    int xcenter = 300;
    int ycenter = 100;

    int radius = 50;

the picture is follows:

enter image description here

Willpower answered 23/12, 2012 at 13:35 Comment(12)
This is how IFS works. Note the transformation is chosen at random from a set of two - one transformation would, indeed, not be enough.Chianti
No, you are wrong. Choosing random won't help.Willpower
Read up on IFS or do some hand simulation. That's the beauty of Iterated Function Systems.Chianti
@Jan don't teach just solve the problem. I solved it, while you didn't. Practice is the criterion of truth.Willpower
"You algorithm is linear. Linear algorithm can't draw tree-like picture." -- still wrong.Chianti
You solved (or, more correctly, avoided) the issue but not in the way you think.Chianti
@Jan may be terms are wrong but idea is not. You won't jump with one "mandelobus" over entire complex picture.Willpower
@Jan what a problem? you can solve in the way YOU think!Willpower
Your claim that you need manual branching is incorrect. You solved the problem by applying the correct scale - which the asker didn't - not by switching to tree-like recursion.Chianti
Note that your drawing algorithm totally neglects the probability coefficient.Chianti
"you pass 300 both into iteration and as drawing shift. This is minor." -- This is not minor, nor does he do it (outside of the comments).Chianti
Hm, looks like you are right, this is great!Willpower

© 2022 - 2024 — McMap. All rights reserved.