1 package demo; 2 3 import java.awt.Color; 4 import java.awt.Graphics; 5 6 import javax.swing.JFrame; 7 import javax.swing.JPanel; 8 9 /** 10 * Java Cardioid 心脏形曲线 (整理) 11 * 这是以前看到有关Cardioid一个故事之后,觉得好玩,那时把它实现了。 12 * 13 * 2016-1-2 深圳 南山平山村 曾剑锋 14 */ 15 public class Cardioid extends JPanel{ 16 /** 17 * <ol> 18 * <li>centerX:代表x轴中心点坐标 19 * <li>centerY:代表y轴中心店坐标 20 * </ol> 21 * 整个窗口的长、宽等于2*centerX、2*centerY,这么做的目的是保证数据的统一性修改 22 * 当然你也可以考虑使用长、宽来表示,然后对他们进行取一半得到中心店坐标。 23 * 24 */ 25 static int centerX = 600/2; 26 static int centerY = 600/2; 27 /** 28 * angle:主要用于角度计算,下面程序中的for循环里的变量,360一个周期 29 */ 30 int angle; 31 /** 32 * <ol> 33 * <li>a:窗口中有2个心形图,a是其中一个的幅值 34 * <li>b:窗口中有2个心形图,b是其中一个的幅值 35 * </ol> 36 * 2个心形图,2个幅值,但初始值是不一样的。 37 */ 38 int a = 0; 39 int b = 50; 40 /** 41 * 构造函数调用start()函数。<br> 42 * 作用:开启一个线程,主要用于调整a、b的值,并刷新界面。 43 */ 44 public Cardioid() { 45 start(); 46 } 47 /** 48 * 重写paint()<br> 49 * 程序流程:<ol> 50 * <li>调用父类paint方法、并设置背景颜色为黑色 51 * <li>用for循环画两个发散的心形图 52 * </ol> 53 */ 54 @Override 55 public void paint(Graphics graphics) { 56 super.paint(graphics); 57 this.setBackground(Color.black); 58 graphics.setColor(Color.red); 59 /* 60 * 这里是难点,主要是因为需要对坐标进行定位,下面是获取x、y的坐标公式,你可以在网上查到 61 * x=a*(2*sin(t)-sin(2*t)) 62 * y=a*(2*cos(t)-cos(2*t)) 63 * 这里的x、y和网上的公式对调了,主要是因为需要进行y=x对称,网上的图是横着的,这个图是正着的。 64 * sin()函数传入的是弧度制,所以需要通过angle*Math.PI/180,将角度值换成幅度值 65 * 其中的500主要是用于坐标调整的,没有理由,是我自己试出来的,我也没有去深究为什么,因为功能完成了。 66 */ 67 for (angle = 0; angle < 360; angle++) { 68 graphics.drawLine( 69 centerY+(int)(a*(2*Math.sin(angle*Math.PI/180)-Math.sin(2*angle*Math.PI/180))), 70 500 -(centerX+(int)(a*(2*Math.cos(angle*Math.PI/180)-Math.cos(2*angle*Math.PI/180)))), 71 centerY+(int)((a+3)*(2*Math.sin((angle)*Math.PI/180)-Math.sin(2*(angle)*Math.PI/180))), 72 500 -(centerX+(int)((a+3)*(2*Math.cos((angle)*Math.PI/180)-Math.cos(2*(angle)*Math.PI/180))))); 73 } 74 for (angle = 0; angle < 360; angle++) { 75 graphics.drawLine( 76 centerY+(int)(b*(2*Math.sin(angle*Math.PI/180)-Math.sin(2*angle*Math.PI/180))), 77 500 -(centerX+(int)(b*(2*Math.cos(angle*Math.PI/180)-Math.cos(2*angle*Math.PI/180)))), 78 centerY+(int)((b+3)*(2*Math.sin((angle)*Math.PI/180)-Math.sin(2*(angle)*Math.PI/180))), 79 500 -(centerX+(int)((b+3)*(2*Math.cos((angle)*Math.PI/180)-Math.cos(2*(angle)*Math.PI/180))))); 80 } 81 } 82 /** 83 * 创建一个匿名线程,线程主要完成以下事情:<ol> 84 * <li>改变a、b的值,相当于改变心形线的幅值; 85 * <li>延时20ms; 86 * <li>刷新界面repaint(); 87 * </ol> 88 */ 89 public void start() { 90 new Thread(new Runnable() { 91 92 @Override 93 public void run() { 94 while (true) { 95 try { 96 if (a++ >100) { 97 a = 0; 98 } 99 if (b++ >100) { 100 b = 0; 101 } 102 Thread.sleep(20); 103 repaint(); 104 } catch (InterruptedException e) { 105 e.printStackTrace(); 106 } 107 } 108 109 } 110 }).start(); 111 } 112 /** 113 * 主函数完成以下内容:<ol> 114 * <li>初始化jframe窗口; 115 * <li>创建cardioid,并将cardioid填充到jFrame中; 116 * <li>设置jFrame可见。 117 * </ol> 118 */ 119 public static void main(String[] args) { 120 JFrame jFrame = new JFrame(); 121 jFrame.setTitle("Cardioid"); 122 jFrame.setSize(centerX*2, centerY*2); 123 jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 124 jFrame.setLocationRelativeTo(null); 125 126 Cardioid cardioid = new Cardioid(); 127 jFrame.add(cardioid); 128 jFrame.setVisible(true); 129 } 130 }