绘制递归雪花

时间:2015-03-14 21:12:54

标签: java recursion

我有这个问题,我必须绘制一个递归的雪花片,使得片状物有6条线来自一个中心点,每条线彼此相隔60度,然后每条线的端点是中心点另一片。每次分支到另一片时,长度减半。长度定义为薄片的一侧。这种递归继续发生,直到长度下降到20像素的距离,在那里你无法再区分不同的薄片。

我知道递归只是一种调用自身的方法,但我只是难以设置这个问题。到目前为止我得到的是绘制初始薄片的数学但我不知道如何设置递归来绘制薄片。

这是我到目前为止所拥有的。

import java.awt.*;
import java.util.Random;
import javax.swing.*;

public class SnowFlake extends JPanel {

    private MainWindow panel;
    private int x1OfFlake = 400;
    private int y1OfFlake = 400;
    private int maxLength = 200;  // this is length of, 1 0f 6 branches for each individual flake

    public SnowFlake() {
        // generateRandCoodinatesLength();
    }

    public void generateRandCoodinatesLength() {
        Random rn = new Random();
        maxLength = rn.nextInt(200) + 100;
        x1OfFlake = rn.nextInt(700) + 100;
        y1OfFlake = rn.nextInt(700) + 100;
    }


    public void paint(Graphics g) {
        drawFlake(levels, x1OfFlake, y1OfFlake, g);  // x1, y1, x2, y2
    }

    public void drawFlake(int level, int x1, int y1, Graphics g){
        //below was just how I made sure my picture was correct
        /*
          g.drawLine(x1, y1, 600, 400); //1
          g.drawLine(x1, y1, 500, 227); //2
          g.drawLine(x1, y1, 300, 227); //3
          g.drawLine(x1, y1, 200, 400); //4
          g.drawLine(x1, y1, 300, 573); //5
          g.drawLine(x1, y1, 500, 573); //6
        */
        g.drawLine(x1, y1, x1 + maxLength, y1);  // 1
        g.drawLine(x1, y1, x1 + (maxLength / 2), y1 - ((int) ((maxLength / 2) * Math.sqrt(3))));  // 2
        g.drawLine(x1, y1, x1 - (maxLength / 2), y1 - ((int) ((maxLength / 2) * Math.sqrt(3))));  // 3
        g.drawLine(x1, y1, x1 - maxLength, y1); // 4
        g.drawLine(x1, y1, x1 - (maxLength / 2), y1 + ((int) ((maxLength / 2) * Math.sqrt(3))));  // 5
        g.drawLine(x1, y1, x1 + (maxLength / 2), y1 + ((int) ((maxLength / 2) * Math.sqrt(3))));  // 6
    }
}

除了绘制更多分支外,最终结果应该是这样的。

picture

3 个答案:

答案 0 :(得分:1)

这可以让你更接近你想要的东西

public void drawFlake(int level, float angleDegrees, Graphics g) {
    /* 
     * Exit condition
     * If the max number of levels has been reached, 
     * or the maxLength is no longer visible when drawn
     */
    if (level >= MAX_LEVEL || maxLength == 0) {
        return;
    }

    /*
     * Secondary condition, increment the level if we've gone around the 
     * circle once
     */
    if (angleDegrees >= 360) {
        maxLength *= .9;
        drawFlake(level + 1, 0, g);
        return;
    }

    g.drawLine(
        centerX,
        centerY,
        centerX + (int) (maxLength * Math.sin(Math.toRadians(angleDegrees))),
        centerY + (int) (maxLength * Math.cos(Math.toRadians(angleDegrees))));

    int currentLevelAngleIncrement = 60 / (level + 1);
    drawFlake(level, angleDegrees + currentLevelAngleIncrement, g);
}

结束这样的事情...... enter image description here

答案 1 :(得分:0)

不确定是什么级别 - 似乎没有在drawFlake方法中使用...

我会改变你的递归函数来获取x和y坐标以及当前行的长度:

public void drawFlake(int x1, int y1, int length, Graphics g) {
    // draw the current flake - exactly the same as your method except that it
    // uses the length passed not the maximum length
    g.drawLine(x1, y1, x1 + length, y1);  // 1
    g.drawLine(x1, y1, x1 + (length / 2), y1 - ((int) ((length / 2) * Math.sqrt(3))));  // 2
    g.drawLine(x1, y1, x1 - (length / 2), y1 - ((int) ((length / 2) * Math.sqrt(3))));  // 3
    g.drawLine(x1, y1, x1 - length, y1); // 4
    g.drawLine(x1, y1, x1 - (length / 2), y1 + ((int) ((length / 2) * Math.sqrt(3))));  // 5
    g.drawLine(x1, y1, x1 + (length / 2), y1 + ((int) ((length / 2) * Math.sqrt(3))));  // 6

    // recursion
    int newLength = length / 2;
    if (newLength >= MIN_LENGTH) {
        // this is the recursive bit - call the function again for each of the end points
        drawFlake(x1 + length, y1, newLength, g);
        drawFlake(x1 + (length / 2), y1 - ((int) ((length / 2) * Math.sqrt(3))), newLength, g);
        drawFlake(x1 - (length / 2), y1 - ((int) ((length / 2) * Math.sqrt(3))), newLength, g);
        drawFlake(x1 - length, y1, newLength, g);
        drawFlake(x1 - (length / 2), y1 + ((int) ((length / 2) * Math.sqrt(3))), newLength, g);
        drawFlake(x1 + (length / 2), y1 + ((int) ((length / 2) * Math.sqrt(3))), newLength, g);
    }
}

然后用起始值开始:

public void paint(Graphics g) {
    drawFlake(x1OfFlake, y1OfFlake, maxLength, g);
}

请注意,传递给递归drawFlake方法的坐标与drawLine调用的终点相同,因此您可以计算一次并重复使用它们。

另外,为了便于阅读(也许是性能),我只是在每次通话开始时计算一次(length / 2) * Math.sqrt(3)

没有运行它,所以可能是一些错别字,但应该让你走上正确的路线。

答案 2 :(得分:0)

感谢您的帮助,下面的代码对递归有很大帮助。现在我必须将这些变量传递给方法,因此它们实际上正在改变,这更有意义。还有这个,我注意到,如果你只将长度除以2,它只是形成一个六角形,填充三角形。所以搞乱那个,最小的长度解决了这个问题。

    public void drawFlake(int x1, int y1, int length, Graphics g){


    g.drawLine(x1, y1, x1 + length, y1);  // 1
    g.drawLine(x1, y1, x1 + (length / 2), y1 - ((int) ((length / 2) * Math.sqrt(3))));  // 2
    g.drawLine(x1, y1, x1 - (length / 2), y1 - ((int) ((length / 2) * Math.sqrt(3))));  // 3
    g.drawLine(x1, y1, x1 - length, y1); // 4
    g.drawLine(x1, y1, x1 - (length / 2), y1 + ((int) ((length / 2) * Math.sqrt(3))));  // 5
    g.drawLine(x1, y1, x1 + (length / 2), y1 + ((int) ((length / 2) * Math.sqrt(3))));  // 6

    //recursion
    int newLength = length/3; //changed this to 3 to make it more look more like a flake

    if(newLength >= minLength){
        drawFlake(x1 + length, y1, newLength, g);
        drawFlake(x1 + (length / 2), y1 - ((int) ((length / 2) * Math.sqrt(3))), newLength, g);
        drawFlake(x1 - (length / 2), y1 - ((int) ((length / 2) * Math.sqrt(3))), newLength, g);
        drawFlake(x1 - length, y1, newLength, g);
        drawFlake(x1 - (length / 2), y1 + ((int) ((length / 2) * Math.sqrt(3))), newLength, g);
        drawFlake(x1 + (length / 2), y1 + ((int) ((length / 2) * Math.sqrt(3))), newLength, g);
    }
相关问题