生成分形漩涡

9

我需要使用迭代函数系统算法(Iterated Function System)绘制一个分形漩涡。

目标分形图像

这个分形有一些系数:

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

以下是我的代码:

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;
        }
    }
}
}

很遗憾,使用这段代码我得到了一张错误的图片:

当前分形图像

如果有人能指出我的错误就太好了。


2
系数是否正确和完整? - John Dvorak
2
本地变量和方法之间的命名冲突可能不是一个好主意。 - John Dvorak
2
当您迭代不仅10000次,而是100K次或1M次时会发生什么? - UmNyobe
2
UmNyobe,100k - http://s14.postimage.org/eoweh1zkx/100000.png,1M - http://s1.postimage.org/y9wpano3z/1000000.png - Nostia
2
在上述网站@Nostia中,排序似乎是“a1 b1 c1 d1 e1 f1 p1”,但您似乎按不同的顺序列出它们。例如,请查看d1和c1。 - cmh
显示剩余13条评论
3个回答

14

你的计算方式似乎正确(即不要做 x1 = x2 +300; y1 = y2 +300;),但是问题在于渲染的目的地太偏了。这意味着只有很少的点会落在图片的中心以外。

你的窗口大小是 [0..600]x[0..600]。试着将 x2y2 都乘以 50,这样你就可以渲染[-6..6]x[-6..6] 区域而不是空间的 [-300..300]x[-300..300] 区域。

请注意,只需要绘制单个像素(作为自身的线)而不是3x3的椭圆。

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

根据所呈现的内容,您可能需要微调比例以获得整个图像并保持合理的边界。请注意第二个变换偏移了-6.7,因此缩放系数为30应该是正确的。

还要注意,通过使用x1 = x2 +300; y1 = y2 +300;您可以更改转换并获得不同的分形(在您期望的比例下)。


最终我得到了正确的分形图像!! :) 感谢您的解释,现在我看到了我的错误。 - Nostia
不错的Jan!我也考虑过这个问题,但是我犯了一个错误,一直在使用缩放值“xp,yp”来制作分形图像,并放弃了解决它 :)。 - UmNyobe

4

这真是太棒了,我之前错误地认为指数时间复杂度才能实现!这些分形看起来比我的想象中更有维度感!

谢谢@Jan Dvorak!

以下内容同样可行(在我的坐标系中,xcenter=300ycenter=100radius=50是全局绘图参数),并且速度更快:

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;
        }

    }

图片质量更好了

输入图片描述


感谢您测试我的修复,伙计 :-) - John Dvorak
请注意,“类似树状的运行时”在技术上讲是无意义的。您可以使用“类似树状的递归”,然后会遇到“指数级运行时” ;) - John Dvorak
你介意在答案中给我一些信用吗? - John Dvorak
当然,我已经给它投了赞成票。 - Suzan Cioc
我的意思是,在答案中说出提问者代码的问题实际上是什么,以及是谁发现了这个问题;-) - John Dvorak
显示剩余2条评论

1

以下是我的错误答案

但它展示了分形比直觉更大,所以我保留它。

我猜你的算法应该是树形(递归),而你的算法是线性的。你只是画出一条点链,一个接一个地变换它。所以你得到了一些螺旋状的链。原则上它不能生成任何分形图片。

我得到了你的图片

你有两个错误:

1)你将300传递到迭代和绘图移位中。这是小问题。

2)你的算法是线性的。线性算法无法绘制树状图片。如果你使用随机值,你应该多次运行算法。一条链只绘制图片的一个随机部分。

我用以下递归算法得到了你的图片。它运行缓慢,但你可以改进它。

  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);






    }

我使用以下方法来运行它

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

参数为:

    int xcenter = 300;
    int ycenter = 100;

    int radius = 50;

图片如下:

enter image description here


不,你错了。随机选择不会有帮助。 - Suzan Cioc
阅读关于IFS的相关内容或进行手动模拟。这就是“迭代函数系统”的美妙之处。 - John Dvorak
1
你的算法是线性的。线性算法无法绘制树状图像。——仍然不正确。 - John Dvorak
@Jan,有什么问题吗?你可以用你认为合适的方式来解决! - Suzan Cioc
1
你声称需要手动分支是不正确的。你通过应用正确的比例解决了问题 - 而提问者没有 - 而不是切换到树形递归。 - John Dvorak
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接