一些有趣的分形
DrawUI
首先还是创建一个界面,这里我们都很熟悉,创建一个界面类
public class DrawUI(){
public void showUI(){
//创建窗体
JFrame drawFrame = new JFrame("画板");
drawFrame.setSize(1000,1000);
drawFrame.setLocationRelativeTo(null);
drawFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
//设置布局
JPanel north = new JPanel();
north.setPreferredSize(new Dimension(0,30));
drawFrame.add(north,BorderLayout.NORTH);
JPanel center = new JPanel();
drawFrame.add(center,BorderLayout.CENTER);
center.setBackground(Color.WHITE);
//设置窗体可见
drawFrame.setVisible(true);
}
public static void main (String[] args){
DrawUI ui = new DrawUI();
ui.showUI();
}
界面完成以后,我们在上面添加一些按钮,当然这里的按钮的名字我们可以随意,我随便设置了几个名字
//north是我们的北部边界,上面设置了的,把按钮放在上面比较美观,
//不设置北部边界直接界面的流式布局也可以,
// 这里主要是为了熟练JPanel的应用
JButton btn1 = new JButton("蛋");
north.add(btn1);
JButton btn2 = new JButton("乱");
north.add(btn2);
JButton btn3 = new JButton("心");
north.add(btn3);
JButton btn4 = new JButton("树");
north.add(btn4);
JButton btn5 = new JButton("三角");
north.add(btn5);
然后运行,我们就可以得到这样一个界面了
IFS
建一个IFS类来写我们的分形的方法
所谓的分形,就是通过数学公式计算出点的坐标,然后再用计算机画出来
例如这个
公式代入计算很简单,只有一个地方要注意到就是我们会用到一个缓存画布,因为我们经过了几万次的画点,如果一个一个点画,会很难看,所以我们用到缓存画布
public class IFS {
//A按钮定义
public void drawA(Graphics g) {
double x = 0f;
double y = 0f;
double a = -1.8, b = -2.8, c = -0.5, d = -0.9;
// 缓存画布
BufferedImage ig = new BufferedImage(1000, 600, BufferedImage.TYPE_INT_ARGB);
Graphics nb = ig.getGraphics();
g.setColor(Color.BLACK);
for (; a < 1; a -= 0.001) {
nb.setColor(Color.BLACK);
nb.fillRect(0, 0, 1000, 600);
nb.setColor(new Color(Color.HSBtoRGB((float) (a + 1), (float) (a + 2), 3)));
for (int i = 0; i < 20000; i++) {
double temx = Math.sin(a * y) + c * Math.cos(a * x);
double temy = Math.sin(b * x) + d * Math.cos(b * y);
int x1 = (int) (temx * 100 + 300);
int y1 = (int) (temy * 100 + 300);
nb.drawLine(x1, y1, x1, y1);
x = temx;
y = temy;
}
g.drawImage(ig,0,0,null);
}
}
//B按钮定义
public void drawB(Graphics g) {
double x = 0f;
double y = 0f;
double a;
double b ;
double c ;
double d ;
if (Math.random()<0.5 ){
a = 1.641;
b = 1.902;
c = 0.316;
d = 1.525;
} else {
a = 0.970;
b = -1.899;
c = 1.381;
d = -1.506;
}
// 缓存画布
BufferedImage ig = new BufferedImage(1000, 600, BufferedImage.TYPE_INT_ARGB);
Graphics nb = ig.getGraphics();
g.setColor(Color.BLACK);
for (; a > 1; a += 0.001) {
nb.setColor(Color.BLACK);
nb.fillRect(0, 0, 1000, 600);
nb.setColor(new Color(Color.HSBtoRGB((float) (a + 2), (float) (a + 3), 1)));
for (int i = 0; i < 10000; i++) {
double temx = Math.sin(a * y) - Math.cos(b * x);
double temy = Math.sin(c * x) - Math.cos(d * y);
int x1 = (int) (temx * 100 + 300);
int y1 = (int) (temy * 100 + 300);
nb.drawLine(x1, y1, x1, y1);
x = temx;
y = temy;
}
g.drawImage(ig, 0, 0, null);
}
}
//C按钮定义
public void drawC(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(0, 0, 1000, 600);
for(int i=0;i<=180;i++){
for(int j=0;j<=180;j++){
double r=Math.PI/45*i*(1-Math.sin(Math.PI/45*j))*20;
double x=r*Math.cos(Math.PI/45*j)*Math.sin(Math.PI/45*i)+300;
double y=-r*Math.sin(Math.PI/45*j)+200;
Color c=Color.getHSBColor(i*j/8100.0f, 0.9999f,0.9999f);
g.setColor(c);
g.drawOval((int)x, (int)y, 1,1);
try{
Thread.sleep(1);
}
catch(Exception e){}
}
}
}
//D按钮定义
public void drawD(Graphics g) {
double x=200,y=200;
double[][] array={
{0.05,0.0,0.0,0.4,-0.06,-0.47},
{-0.05,0.0,0.0,-0.4,-0.06,-0.47},
{0.03,-0.14,0.0,0.26,-0.16,-0.01},
{-0.03,0.14,0.0,-0.26,-0.16,-0.01},
{0.56,0.44,-0.37,0.51,0.3,0.15},
{0.19,0.07,-0.1,0.15,-0.2,0.28},
{-0.33,-0.34,-0.33,0.34,-0.54,0.39}
};
//随机数
Random r=new Random(0);
// Random k=new Random(0);
g.setColor(Color.BLACK);
g.fillRect(0, 0, 1000, 400);
Color headColor = new Color(89,139,137);
g.setColor(headColor);
g.fillRect(0, 400, 1000, 600);
for(int i=0;i<25500;i++){
int j=r.nextInt(7);
double a=array[j][0],b=array[j][1],c=array[j][2],
d=array[j][3],e=array[j][4],f=array[j][5];
double tempx=a*x+b*y+e;
double tempy=c*x+d*y+f;
int showx=(int)(tempx*200+400);
int showy=(int)(tempy*200+550);
//倒影
g.setColor(new Color(20,21,25));
if(i%2==0)g.drawLine(showx,showy,showx+4,showy);
else g.drawLine(showx-4, showy, showx, showy);
//正向树
int changey=790-showy;
g.setColor(new Color(i/100,138,207));
g.drawLine(showx,changey,showx,changey);
//迭代
x=tempx;
y=tempy;
}
g.setColor(new Color(95,129,19));
g.drawOval(60, 400, 500, 5);
try{
Thread.sleep(100);
}
catch(Exception e){}
}
//E按钮定义
//这里是我后来加的,画的递归的三角形,也还挺好看,就放上去了
public void drawE(Graphics g,int n,int d,int x0,int y0) {
if(n==0) {
}
else {
//画出一个大三角形
double x1=x0+d;
double y1=y0+Math.sqrt(3)*d;
double x2=x0-d;
double y2=y0+Math.sqrt(3)*d;
g.drawLine(x0,y0,(int)x1,(int)y1 );
g.drawLine((int)x1, (int)y1,(int)x2 ,(int)y2 );
g.drawLine((int)x2,(int)y2,x0 ,y0 );
//取三边中点
double x3=(x0+x1)/2;
double y3=(y0+y1)/2;
double x4=(x1+x2)/2;
double y4=(y1+y2)/2;
double x5=(x0+x2)/2;
double y5=(y0+y2)/2;
//中点再连线
g.drawLine((int)x3,(int)y3,(int)x4,(int)y4);
g.drawLine((int)x3,(int)y3,(int)x5 ,(int)y5);
g.drawLine((int)x4,(int)y4,(int)x5 ,(int)y5);
//再取中点连线
double x6=(x3+x5)/2;
double y6=(y3+y5)/2;
double x7=(x3+x4)/2;
double y7=(y3+y4)/2;
double x8=(x4+x5)/2;
double y8=(y4+y5)/2;
g.drawLine((int)x6,(int)y6,(int)x7 ,(int)y7);
g.drawLine((int)x6,(int)y6,(int)x8 ,(int)y8);
g.drawLine((int)x7,(int)y7,(int)x8 ,(int)y8);
//递归
drawE(g,n-1,d/2,x0,y0);
drawE(g,n-1,d/2,(int)x3,(int)y3);
drawE(g,n-1,d/2,(int)x5,(int)y5);
}
}
}
DrawListener
接下来写我们的监听器类
public class DrawListener implements ActionListener{
String cmd="0";
Graphics g;
cmd = e.getActionCommand();//获得按钮上的内容然后调用IFS类里的方法
if(cmd.equals("蛋")) {
IFS ifs= new IFS();
ifs.drawA(g);
}
if(cmd.equals("乱")) {
IFS ifs= new IFS();
ifs.drawB(g);
}
if(cmd.equals("心")) {
IFS ifs= new IFS();
ifs.drawC(g);
}
if(cmd.equals("树")) {
IFS ifs= new IFS();
ifs.drawD(g);
}
if(cmd.equals("三角")) {
IFS ifs= new IFS();
ifs.drawE(g,5,400,400,200);
}
}
}
然后就可以了,最后一步在界面里加上我们的监听器
//创建监听器
DrawListener drawL = new DrawListener();
//获取窗体的画布
drawL.g= center.getGraphics();
//创建Button监听器
btn1.addActionListener(drawL);
btn2.addActionListener(drawL);
btn3.addActionListener(drawL);
btn4.addActionListener(drawL);
btn5.addActionListener(drawL);
结束!看看效果
over~