绘制递归雪花
Drawing a recursive snow flake
我有这个问题,我必须绘制一个递归的雪花,这样雪花有 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
}
}
除了绘制了更多分支外,最终结果应该是这样的。
这可以让您更接近您想要的东西
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);
}
结果是这样的..
不确定是什么级别 - 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)
。
还没有运行它,所以可能有一些错别字,但应该让你在正确的行上。
感谢您的帮助,下面的代码对递归有很大帮助。现在更有意义的是我必须将这些变量传递到方法中,以便它们实际上发生变化。另外,我注意到如果你只将长度除以二,它就会形成一个六边形,里面充满了三角形。所以弄乱那个和最小长度解决了这个问题。
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);
}
我有这个问题,我必须绘制一个递归的雪花,这样雪花有 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
}
}
除了绘制了更多分支外,最终结果应该是这样的。
这可以让您更接近您想要的东西
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);
}
结果是这样的..
不确定是什么级别 - 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)
。
还没有运行它,所以可能有一些错别字,但应该让你在正确的行上。
感谢您的帮助,下面的代码对递归有很大帮助。现在更有意义的是我必须将这些变量传递到方法中,以便它们实际上发生变化。另外,我注意到如果你只将长度除以二,它就会形成一个六边形,里面充满了三角形。所以弄乱那个和最小长度解决了这个问题。
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);
}