昨天晚上看了微分方程课程的视频,了解到了向量场的概念,所以产生了用Java来绘制向量场的想法。目前给出了初步的实现方案,程序有bug,回去继续改。
修改了一会,觉得太麻烦了
下面是代码:
package com.math;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
class PainterPanel extends JPanel {
private static final long serialVersionUID = 1L;
public PainterPanel() {
super(); // 调用父类构造函数
this.setBackground(Color.white); // 设置背景颜色
repaint();
}
public void paint(Graphics g) {
setSize(1000, 400);
g.translate(800, 200);
Range range = new Range(-200.0, 20.0);
List<Equipotent> el = new ArrayList<Equipotent>();
DirectorField df = new DirectorField(el);
addEp1(el, range);
addEp2(el, range);
addEp3(el, range);
addEp4(el, range);
df.paint(g);
}
private void addEp1(List<Equipotent> el, Range range){
Calculater director = new Calculater() {
public double getValue(Object[] val) { return 3; }};
Calculater equipotential = new Calculater() {
public double getValue(Object[] val) {
double x = (Double)val[0];
return x+5;
}
};
Calculater equipotential_1d = new Calculater() {
public double getValue(Object[] val) {
double x = (Double)val[0];
return 1;
}
};
Calculater equipotential_2d = new Calculater() {
public double getValue(Object[] val) {return 0;}};
Equipotent ep = new Equipotent(range, director, equipotential,
equipotential_1d, equipotential_2d);
el.add(ep);
}
private void addEp2(List<Equipotent> el, Range range){
Calculater director = new Calculater() {
public double getValue(Object[] val) { return 0; }};
Calculater equipotential = new Calculater() {
public double getValue(Object[] val) {
double x = (Double)val[0];
return x+1;
}
};
Calculater equipotential_1d = new Calculater() {
public double getValue(Object[] val) {
double x = (Double)val[0];
return 1;
}
};
Calculater equipotential_2d = new Calculater() {
public double getValue(Object[] val) {return 0;}};
Equipotent ep = new Equipotent(range, director, equipotential,
equipotential_1d, equipotential_2d);
el.add(ep);
}
private void addEp3(List<Equipotent> el, Range range){
Calculater director = new Calculater() {
public double getValue(Object[] val) { return 1; }};
Calculater equipotential = new Calculater() {
public double getValue(Object[] val) {
double x = (Double)val[0];
return x;
}
};
Calculater equipotential_1d = new Calculater() {
public double getValue(Object[] val) {
double x = (Double)val[0];
return 1;
}
};
Calculater equipotential_2d = new Calculater() {
public double getValue(Object[] val) {return 0;}};
Equipotent ep = new Equipotent(range, director, equipotential,
equipotential_1d, equipotential_2d);
el.add(ep);
}
private void addEp4(List<Equipotent> el, Range range){
Calculater director = new Calculater() {
public double getValue(Object[] val) { return 0; }};
Calculater equipotential = new Calculater() {
public double getValue(Object[] val) {
double x = (Double)val[0];
return x-1;
}
};
Calculater equipotential_1d = new Calculater() {
public double getValue(Object[] val) {
double x = (Double)val[0];
return 1;
}
};
Calculater equipotential_2d = new Calculater() {
public double getValue(Object[] val) {return 0;}};
Equipotent ep = new Equipotent(range, director, equipotential,
equipotential_1d, equipotential_2d);
el.add(ep);
}
}
class Point {
public double x, y;
public Point(){};
public Point(double _x, double _y) {
this.x = _x;
this.y = _y;
}
public String toString() {
return "<x:" + x + ", y:" + y + ">";
}
}
class Range {
public double x1, x2;
public Range(double _x1, double _x2) {
this.x1 = _x1;
this.x2 = _x2;
}
public String toString() {
return "<x1:" + x1 + ", x2:" + x2 + ">";
}
}
interface ICalculater {
public double getValue(Object[] val);
public double getValue(Object val);
}
abstract class Calculater implements ICalculater {
public double getValue(Object[] val){
return 0.0;
}
public double getValue(Object val) {
return getValue(new Object[] {val});
}
}
class DirectorField{
List<Equipotent> el;
public DirectorField(List<Equipotent> _el) {
this.el = _el;
}
public void paint(Graphics g) {
for(Equipotent e : el) {
e.paint(g);
}
}
}
class Equipotent {
Calculater director;
Calculater equipotential; // 等势线
Calculater equipotential_1d; // //等势线的向量
Calculater equipotential_2d;
Point first, current;
double distance = 0.3; // 间隔
double length = 20; // 向量的长度
double e = 0.0001;
Range range;
ArrayList<Point> pl;
int pos = -1;
public Equipotent(Range _range, Calculater _director,
Calculater _equipotential, Calculater _equipotential_1d,
Calculater _equipotential_2d) {
this.director = _director;
this.equipotential = _equipotential;
this.equipotential_1d = _equipotential_1d;
this.equipotential_2d = _equipotential_2d;
this.range = _range;
}
public void paint(Graphics g) {
try {
init();
} catch (Exception e) {
e.printStackTrace();
}
double px = length / (2 * Math.sqrt(1 + director.getValue(pos)));
double py = director.getValue(pos)*px;
int rate=100;
for (Point p : pl) {
p.x = p.x*rate;
p.y = p.y*rate;
g.drawLine((int) Math.round(p.x - px), (int) Math.round(p.y - py),
(int) Math.round(p.x + px), (int) Math.round(p.y + py));
}
}
private void init() throws Exception {
pl = calcPoint();
Collections.sort(pl, new Comparator<Point>() {
public int compare(Point o1, Point o2) {
return (int) (o1.x - o2.x) * 1000;
}
});
}
private ArrayList<Point> calcPoint() throws Exception {
ArrayList<Point> pl = new ArrayList<Point>();
double p;
try {
p = calcPoint(new Object[]{range.x1}, new Object[]{range.x2}, equipotential_1d, e);
ArrayList<Point> pl1 = calcXXX(new Range(range.x1, p),
equipotential_1d.getValue(range.x1),
equipotential_2d.getValue(range.x1));
ArrayList<Point> pl2 = calcXXX(new Range(p, range.x2),
equipotential_1d.getValue(range.x2),
equipotential_2d.getValue(range.x2));
pl.addAll(pl1);
pl.addAll(pl2);
} catch (Exception e) {
pl = calcXXX(new Range(range.x1, range.x2),
equipotential_1d.getValue(range.x1),
equipotential_2d.getValue(range.x1));
}
return pl;
}
private ArrayList<Point> calcXXX(Range range, double e1d, double e2d) {
Calculater upper = new Calculater() {
public double getValue(Object[] val) {
double x = (Double)val[0];
double b = (Double)val[1];
return equipotential.getValue(x)
- (equipotential.getValue(b)+Math.sqrt(distance*distance - (x-b)*(x-b)));
}
};
Calculater down = new Calculater() {
public double getValue(Object[] val) {
double x = (Double)val[0];
double b = (Double)val[1];
return equipotential.getValue(x)
- (equipotential.getValue(b)-Math.sqrt(distance*distance - (x-b)*(x-b)));
}
};
Calculater calc = e2d > 0 ? upper : down;
boolean isLeft = e1d * e2d > 0;
ArrayList<Point> pl = new ArrayList<Point>();
try {
double b = isLeft ? range.x1 : range.x2;
double t = calcTmp(b, isLeft);
int i = 0;
while (isLeft ? t <= range.x2 : t >= range.x1) {
if(i++%30==0) {
System.out.print("" + i);
}
if(isLeft){
if(t<b-distance){
t = b-distance;
}
}else{
if(t>b+distance){
t = b+distance;
}
}
double x = calcPoint(new Object[]{b, b}, new Object[]{t, b}, calc, this.e);
pl.add(new Point(x, equipotential.getValue(x)));
b = x;
t = calcTmp(b, isLeft);
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return pl;
}
private double calcTmp(double x, boolean isLeft) {
double v = equipotential_1d.getValue(x);
double t = isLeft ? x + distance / Math.sqrt(1 + v * v)
: x - distance / Math.sqrt(1 + v * v);
return t;
}
// 高斯逼近法的变种
private double calcPoint(Object[] params1, Object[] params2, Calculater c, double e)
throws Exception {
double xa = (Double)params1[0], xb = (Double)params2[0];
double ya = c.getValue(params1);
double yb = c.getValue(params2);
if(ya<=e) {
return xa;
}else if(yb<=e) {
return xb;
}
if (!isNeg(ya, yb)) {
throw new Exception("there is no result exists");
}
Object[] params = new Object[params1.length];
System.arraycopy(params1, 0, params, 0, params1.length);
double x = (xa + xb) / 2;
params[0] = x;
double y = c.getValue(params);
int i = 0;
while (abs(y) >= e) {
if(i%30==0){
System.out.println("hhh");
}
if (isNeg(y, ya)) {
xb = x;
yb = y;
} else {
xa = x;
ya = y;
}
x = (xa + xb) / 2;
params[0] = x;
y = c.getValue(params);
}
return x;
}
private double abs(double v) {
return v > 0 ? v : -v;
}
private boolean isNeg(double a, double b) {
return a * b <= 0;
}
}
public class PainterDemo extends JFrame {
JToggleButton[] button = new JToggleButton[3]; // 按钮组
PainterPanel painter = new PainterPanel(); // 绘图面板
public PainterDemo() {
super("Java 向量场"); // 调用父类构造函数
Container container = getContentPane(); // 得到窗口容器
container.add(painter, BorderLayout.CENTER);
setSize(1000, 600); // 设置窗口尺寸
setVisible(true); // 设置窗口为可视
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭窗口时退出程序
}
public static void main(String[] args) {
new PainterDemo();
System.out.println("Hello World");
}
}