放大 Java 中的 Mandelbrot 集分形

Posted

技术标签:

【中文标题】放大 Java 中的 Mandelbrot 集分形【英文标题】:Zooming in on Mandelbrot set fractal in Java 【发布时间】:2012-12-15 08:59:19 【问题描述】:

我开始制作曼德布罗集分形查看器。在放大分形时,我遇到了很多问题。如果您尝试缩放,查看器只会靠近中心。我已经尽我所能来理解这个困境。如何放大我的分形,当我放大时,它会放大屏幕的中心,而不是分形的中心?

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.awt.event.*;



public class Mandelbrot extends JFrame implements ActionListener 

    private JPanel ctrlPanel;
    private JPanel btnPanel;
    private int numIter = 50;
    private double zoom = 130;
    private double zoomIncrease = 100;
    private int colorIter = 20;
    private BufferedImage I;
    private double zx, zy, cx, cy, temp;
    private int xMove, yMove = 0;
    private JButton[] ctrlBtns = new JButton[9];
    private Color themeColor = new Color(150,180,200);

    public Mandelbrot() 
        super("Mandelbrot Set");
        setBounds(100, 100, 800, 600);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        plotPoints();

        Container contentPane = getContentPane();

        contentPane.setLayout(null);




        ctrlPanel = new JPanel();
        ctrlPanel.setBounds(600,0,200,600);
        ctrlPanel.setBackground(themeColor);
        ctrlPanel.setLayout(null);

        btnPanel = new JPanel();
        btnPanel.setBounds(0,200,200,200);
        btnPanel.setLayout(new GridLayout(3,3));
        btnPanel.setBackground(themeColor);

        ctrlBtns[1] = new JButton("up");
        ctrlBtns[7] = new JButton("down");
        ctrlBtns[3] = new JButton ("left");
        ctrlBtns[5] = new JButton("right");
        ctrlBtns[2] = new JButton("+");
        ctrlBtns[0] = new JButton("-");
        ctrlBtns[8] = new JButton(">");
        ctrlBtns[6] = new JButton("<");
        ctrlBtns[4] = new JButton();

        contentPane.add(ctrlPanel);
        contentPane.add(new imgPanel());
        ctrlPanel.add(btnPanel);

        for (int x = 0; x<ctrlBtns.length;x++)
            btnPanel.add(ctrlBtns[x]);
            ctrlBtns[x].addActionListener(this);
        

        validate();

    

    public class imgPanel extends JPanel
        public imgPanel()
            setBounds(0,0,600,600);

        

        @Override
        public void paint (Graphics g)
            super.paint(g);
            g.drawImage(I, 0, 0, this);
        
    

    public void plotPoints()
        I = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
        for (int y = 0; y < getHeight(); y++) 
            for (int x = 0; x < getWidth(); x++) 
                zx = zy = 0;
                cx = (x - 320+xMove) / zoom;
                cy = (y - 290+yMove) / zoom;
                int iter = numIter;
                while (zx * zx + zy * zy < 4 && iter > 0) 
                    temp = zx * zx - zy * zy + cx;
                    zy = 2 * zx * zy + cy;
                    zx = temp;
                    iter--;
                
                I.setRGB(x, y, iter | (iter << colorIter));
            
        
    

    public void actionPerformed(ActionEvent ae)
        String event = ae.getActionCommand();

        switch (event)
        case "up":
            yMove-=100;
            break;
        case "down":
            yMove+=100;
            break;
        case "left":
            xMove-=100;
            break;
        case "right":
            xMove+=100;
            break;
        case "+":
            zoom+=zoomIncrease;
            zoomIncrease+=100;
            break;
        case "-":
            zoom-=zoomIncrease;
            zoomIncrease-=100;
            break;
        case ">":
            colorIter++;
            break;
        case "<":
            colorIter--;
            break;
        



        plotPoints();
        validate();
        repaint();
    




    public static void main(String[] args) 
        new Mandelbrot().setVisible(true);
    

【问题讨论】:

【参考方案1】:

Mandelbrot 集存在于具有自然坐标的数学平面中。您使用 BufferedImage 我使用“视口”坐标“查看”它。这一切都在这些之间的映射中。您已将视口坐标标记为 x 和 y,将 Mandelbrot 空间中的“真实”坐标标记为 cx 和 cy。这些是公式:

        cx = (x - 320+xMove) / zoom;
        cy = (y - 290+yMove) / zoom;

为了放大和缩小特定的“真实”点,您希望位移量在缩放时保持不变。问题是位移量被缩放量缩放。记住 cx 和 cy 是 Mandelbrot 平面中的真实坐标,x & y 是视口坐标。因此,在查看视口中间时,当您更改缩放时,您希望 cx 和 cy 保持不变。

我的猜测是你想要这样的东西:

    cx = ((x - 320) / zoom) + xMove;
    cy = ((y - 290) / zoom) + yMove;

这将使 Mandelbrot 平面中的“运动”保持独立于缩放量。我假设 320 和 290 与视口大小有关,并在视口中间给你一个零。

您将希望 xMove 和 yMove 更改 在击键时的数量不是固定数量 (100),而是取决于缩放级别的数量。当您放大很多时,您希望真实 Mandelbrot 平面中每次击键的移动量更小。

【讨论】:

【参考方案2】:

我可以通过每次放大时进行额外的水平或垂直移动来解决这个问题。

因此,而不是:

case "+": //zooming in
zoom+=zoomIncrease;
zoomIncrease+=100;
break;

我现在有

case "+":
initialZoom = zoom;
zoom+=zoomIncrease;
zoomIncrease*=2;
xMove*=2;
yMove*=2;
break;

这基本上是重新定位已绘制的图像,方法是将其在 x 和 y 轴上的移动乘以缩放增加的因子(即两倍)。

【讨论】:

有机会请accept回答。很高兴你把事情解决了。 :) 将 xMove 乘以缩放,以便您以后可以除以缩放,基本上可以工作,但它似乎是一种过于复杂的方法。实际上,结果在数学上并不正确:zoom 从 130 开始,zoomIncrease 从 100 开始,当你将它们加在一起时,它并不等于精确的加倍,因此将 xMove 加倍并不完全正确。请记住,在所有编码中,简单总是更好。通过消除 zoomIncrease 并简单地使用 zoom *= 2; 来简化并使其在数学上正确

以上是关于放大 Java 中的 Mandelbrot 集分形的主要内容,如果未能解决你的问题,请参考以下文章

朱莉娅集分形

2022-03-29

143.Mandelbrot分形图案

Python 分形算法__代码里开出来的艺术之花

改进我的 Mandelbrot 集代码

MATLAB可视化实战系列(二十七)-MATLAB非线性可视化之Mandelbrot集与分形