一个递归分形搞得我心态爆炸
于是
我一定要写个博客祭奠一下!!!!!!
首先回顾一下递归的几个要素:
1、return:往上回溯
2、调用自身:往下挖掘
3、设置条件:防止无限递归
4、递归操作:分析什么操作可以重复
先实现我们的窗体,以便于我们的画画
Windows.java
package divisions;
import java.awt.Graphics;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
public class windows {
public static void showUI(){
//设置窗体
JFrame win = new JFrame();
win.setSize(1200, 1000);
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
win.setLocationRelativeTo(null);
win.setVisible(true);
//设置监听器
mouse m = new mouse();
win.addMouseListener(m);
//设置画布
Graphics graphics = win.getGraphics();
m.setGraphics(graphics);
}
public static void main(String[] args) {
showUI();
}
}
package divisions;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class mouse implements MouseListener{
public void setGraphics(Graphics g){
this.g = g;
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
下面我们就来实现一下谢尔宾斯基三角形和勾股树的实现
首先是谢尔宾斯基三角形
首先我们要想
递归的重复操作是什么?
以我拙见,大概是这个图形:
这样我们可以想到:每次画六个线画出这个形状,然后转到三个角的位置来继续重复操作就ok
这样,我们可以首先获取三个点的坐标,存到数组中,设置递归次数
int[][] points = new int[3][2];
//不要设置过大,这样电脑反应会有点慢,例如我的破电脑哈哈哈哈哈哈
int length = 10;
获取成功后可以就可以进行draw操作,其中draw函数是一个递归函数,传参传进去的是最外层三角的坐标和递归控制数
public void mousePressed(MouseEvent e) {
points[temp][0] = e.getX();
points[temp][1] = e.getY();
temp++;
if(temp == 3){
int x1 = points[0][0];
int y1 = points[0][1];
int x2 = points[1][0];
int y2 = points[1][1];
int x3 = points[2][0];
int y3 = points[2][1];
draw(x1, y1, x2, y2, x3, y3, length);
}
}
再转到draw函数:
public void draw(int x1,int y1,int x2,int y2,int x3,int y3,int num){
//画图
g.drawLine(x1, y1, x2, y2);
g.drawLine(x2, y2, x3, y3);
g.drawLine(x3, y3, x1, y1);
g.drawLine((x1+x2)/2,(y1+y2)/2,(x1+x3)/2,(y1+y3)/2);
g.drawLine((x2+x3)/2,(y2+y3)/2,(x2+x1)/2,(y2+y1)/2);
g.drawLine((x3+x1)/2,(y3+y1)/2,(x3+x2)/2,(y3+y2)/2);
//递归判断
if(num <= 0)return;
num--;
//定义中点
int tx1 = (x1+x2)/2;
int ty1 = (y1+y2)/2;
int tx2 = (x2+x3)/2;
int ty2 = (y2+y3)/2;
int tx3 = (x3+x1)/2;
int ty3 = (y3+y1)/2;
//转到三个角递归调用
draw(x1, y1, tx1, ty1, tx3, ty3, num);
draw(tx1, ty1, x2, y2, tx2, ty2, num);
draw(tx3, ty3, tx2, ty2, x3, y3, num);
}
看下效果:
大成功!
带着三角形做出来的心情我们转到可爱的勾股树
同样的,我们分析一下这个图形的递归图像:
很容易发现:就是一个个的正方形
首先先解决一个大难题:正方形在知道对角线坐标的时候可以进行公式计算算出另外两个坐标的公式:
(引用于百度)
我们设确定的点的坐标是(x1,y1),(x3,y3),公式出来的为(x2,y2),(x4,y4)
下面需要确定的是三个正方形夹住的三角形的一个角度:
可以定义一个arg = PI / 4;
然后再根据公式计算出以(x1,y1),(x2,y2)为三角形两点的另外一个点的坐标:
其中A1 = arg,A2 = PI / 2 - arg;
代入确认一点为(x,y)
然后在左树:根据上式,未知点为1点,已知点为(x1,y1)为4点,(x,y)为3点
解方程得1点
在右树:根据上式,未知点为1点,已知点为(x,y)为4点,(x2,y2)为3点
解方程再得1点
(注意:上面左右树有不同点,请注意)
然后递归调用即可(代码见下)
代码(其中注释掉的是谢尔宾斯基三角形的代码)
package divisions;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class mouse implements MouseListener{
// int[][] points = new int[3][2];
int[][] points = new int[2][2];
int temp = 0;
double arg = Math.PI / 3;
int length = 15;
Graphics g;
public void setGraphics(Graphics g){
this.g = g;
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
// points[temp][0] = e.getX();
// points[temp][1] = e.getY();
// temp++;
// if(temp == 3){
// int x1 = points[0][0];
// int y1 = points[0][1];
// int x2 = points[1][0];
// int y2 = points[1][1];
// int x3 = points[2][0];
// int y3 = points[2][1];
// draw(x1, y1, x2, y2, x3, y3, length);
// }
// }
points[temp][0] = e.getX();
points[temp][1] = e.getY();
temp++;
if(temp == 2){
int x1 = points[0][0];
int y1 = points[0][1];
int x2 = points[1][0];
int y2 = points[1][1];
draw(x1,y1,x2,y2,length);
}
}
// public void draw(int x1,int y1,int x2,int y2,int x3,int y3,int num){
// g.drawLine(x1, y1, x2, y2);
// g.drawLine(x2, y2, x3, y3);
// g.drawLine(x3, y3, x1, y1);
// g.drawLine((x1+x2)/2,(y1+y2)/2,(x1+x3)/2,(y1+y3)/2);
// g.drawLine((x2+x3)/2,(y2+y3)/2,(x2+x1)/2,(y2+y1)/2);
// g.drawLine((x3+x1)/2,(y3+y1)/2,(x3+x2)/2,(y3+y2)/2);
// if(num <= 0)return;
// num--;
// int tx1 = (x1+x2)/2;
// int ty1 = (y1+y2)/2;
// int tx2 = (x2+x3)/2;
// int ty2 = (y2+y3)/2;
// int tx3 = (x3+x1)/2;
// int ty3 = (y3+y1)/2;
// draw(x1, y1, tx1, ty1, tx3, ty3, num);
// draw(tx1, ty1, x2, y2, tx2, ty2, num);
// draw(tx3, ty3, tx2, ty2, x3, y3, num);
//
// }
public void draw(int x1,int y1,int x3,int y3,int num){
int x4 = (x1 + y1 + x3 - y3)/2;
int y4 = (-x1 + y1 + x3 + y3)/2;
int x2 = (x1 - y1 + x3 + y3)/2;
int y2 = (x1 + y1 - x3 + y3)/2;
g.drawLine(x1, y1, x2, y2);
g.drawLine(x2, y2, x3, y3);
g.drawLine(x3, y3, x4, y4);
g.drawLine(x4, y4, x1, y1);
num--;
if(num <= 0)return;
double r = Math.sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)) / 2;
int x = (int) ((x1 * (1 / Math.tan(Math.PI / 2 - arg)) + x2 * (1 / Math.tan(arg)) + y2 - y1) / ((1 / Math.tan(arg)) + (1 / Math.tan(Math.PI / 2 - arg))));
int y = (int) ((y1 * (1 / Math.tan(Math.PI / 2 - arg)) + y2 * (1 / Math.tan(arg)) + x1 - x2) / ((1 / Math.tan(arg)) + (1 / Math.tan(Math.PI / 2 - arg))));
int tx1 = x1 - y1 + y;
int ty1 = x1 + y1 - x;
int tx2 = x - y + y2;
int ty2 = x + y - x2;
draw(tx1, ty1, x, y, num);
draw(tx2, ty2, x2, y2,num);
}
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}