在学习微分方程的时候,以前也写过类似的文章,可是效果不行,前几天写了一个,感觉不错,分享之。
先看效果(x*x -y -2):
再来代码:
package com.math.slopfields; import java.awt.Color; import java.awt.Graphics; import javax.swing.JFrame; public class SlopFields extends JFrame { protected static final int WIDTH = 800; protected static final int HEIGHT = 600; private java.awt.Dimension dimension = java.awt.Toolkit.getDefaultToolkit(). getScreenSize(); public SlopFields(String title, Grid g) { super(title); this.setSize(WIDTH, HEIGHT); this.setLocation((dimension.width - WIDTH) / 2, (dimension.height - HEIGHT) / 2); HeartCanvas panel = new HeartCanvas(g); this.add(panel); } public static void main(String[] args) { double scale = 80; double aa = 3; double dd = 0.15; Area area = new Area(Vector.build(-aa, aa), Vector.build(aa, -aa)); Vector grid = Vector.build(dd, dd); CanCalc c = new CanCalc(){ public double doCalc(Vector v) { return v.x*v.x - v.y - 2; } }; Grid g = new Grid(area, grid, c, scale); SlopFields hart = new SlopFields("向量场", g); hart.setVisible(true); hart.setDefaultCloseOperation(hart.EXIT_ON_CLOSE); } } class HeartCanvas extends javax.swing.JPanel { private Grid grid; public HeartCanvas(Grid g) { this.grid = g; this.grid.calcGrids(); this.grid.preDraw(); } public void paintComponent(Graphics g) { setBackground(Color.BLACK); super.paintComponent(g); g.setColor(Color.GREEN); this.grid.draw(g); } } class Grid { public double scale = 100; public double padding = 0.2; public Vector offect = Vector.build(0.25, 0.25); public Area area; public Area[][] areas; public Vector grid; public int nx, ny; private CanCalc calc; public Grid(Area _area, Vector _grid, CanCalc _calc, double _scale) { this.area = _area; this.grid = _grid; this.calc = _calc; this.scale = _scale; } public void draw(Graphics g) { int x = (int)area.ld.x; int y = (int)area.ld.y; Vector t = area.ru.add(area.ld.neg()); int width = (int)t.x; int height = (int)t.y; g.drawRect(x, y, width, height); g.drawLine(x, (int)offect.y, x+width, (int)offect.y); g.drawLine((int)offect.x, y, (int)offect.x, y+height); for(Area[] al : areas) { for(Area a : al) { g.drawLine((int)a.ld.x, (int)a.ld.y, (int)a.ru.x, (int)a.ru.y); } } } public void preDraw() { offect = offect.dotMul(this.scale).add(Vector.build(-area.ld.x*scale, area.ru.y*scale)); area = new Area(Vector.build(area.ld.x, -area.ru.y).dotMul(this.scale).add(offect), Vector.build(area.ru.x, -area.ld.x).dotMul(this.scale).add(offect)); for(int i=0; i<ny; i++){ for(int j=0; j<nx; j++) { Area tmp = areas[i][j]; Vector va = Vector.build(tmp.ld.x, -tmp.ld.y).dotMul(this.scale).add(offect); Vector vb = Vector.build(tmp.ru.x, -tmp.ru.y).dotMul(this.scale).add(offect); areas[i][j] = new Area(va, vb); } } } private void fixArea() { Vector tn1 = area.ld.dotDiv(grid).intVal().abs(); area.ld = grid.dotMul(tn1).neg(); Vector tn2 = area.ru.dotDiv(grid).intVal().abs(); area.ru = grid.dotMul(tn2); tn1 = tn1.add(tn2); nx = (int)tn1.x; ny = (int)tn1.y; } private Slop[][] initSlop(CanCalc calc) { fixArea(); Slop[][] slops = new Slop[nx][ny]; Vector now = area.ld.clone(); now.y += grid.y/2; for(int i=0; i<ny; i++) { now.x = area.ld.x + grid.x/2; for(int j=0; j<nx; j++) { slops[i][j] = new Slop(now.clone(), calc.doCalc(now)); now.x += grid.x; } now.y += grid.y; } return slops; } public Area[][] calcGrids() { Slop[][] slops = initSlop(calc); areas = new Area[nx][ny]; for(int i=0; i<nx; i++) { for(int j=0; j<ny; j++) { Vector tmp = null; Slop s = slops[i][j]; if(s.slop == grid.slop()) { tmp = grid.dotDiv(2); }else if(s.slop == -grid.slop()){ tmp = grid.dotDiv(2).dotMul(Vector.dr); }else if(s.slop==0){ tmp = Vector.build(grid.x/2, 0); }else if(s.slop<grid.slop() && s.slop>-grid.slop()) { tmp = Vector.build(grid.x/2, (grid.x/2)*s.slop); }else { tmp = Vector.build((grid.y/2)/s.slop, grid.y/2); } tmp = tmp.dotMul(1-this.padding); areas[i][j] = new Area(s.point.add(tmp.neg()), s.point.add(tmp)); } } return areas; } } interface CanCalc { public double doCalc(Vector v); } class Slop{ public Vector point; public double slop; public Slop(Vector _point, double _slop) { this.point = _point; this.slop = _slop; } public String toString() { return String.format("{%s, %.2f}", point, slop); } } class Area { public Vector ld; public Vector ru; public Area(Vector _ld, Vector _ru) { this.ld = _ld; this.ru = _ru; } public String toString() { return String.format("[%s-%s]", this.ld, this.ru); } public Area scale(double d) { return new Area(this.ld.dotMul(d), this.ru.dotMul(d)); } public Area add(Vector v) { return new Area(this.ld.add(v), this.ru.add(v)); } } class Vector { public static final double infinite = Double.MAX_VALUE; public double x; public double y; public static final Vector zero = Vector.build(0, 0); public static final Vector up = Vector.build(0, 1); public static final Vector down = Vector.build(0, -1); public static final Vector left = Vector.build(-1, 0); public static final Vector right = Vector.build(1, 0); public static final Vector ul = Vector.build(-1, 1); public static final Vector ur = Vector.build(1, 1); public static final Vector dl = Vector.build(-1, -1); public static final Vector dr = Vector.build(1, -1); public static Vector build(double x, double y) { return new Vector(x, y); } public Vector clone() { return Vector.build(this.x, this.y); } public double slop() { if(this.x == 0) { return Vector.infinite; } return this.y / this.x; } public Vector(double _x, double _y) { this.x = _x; this.y = _y; } public Vector intVal() { return new Vector((int)this.x, (int)this.y); } public Vector abs() { return Vector.build((x>=0?x:-x), (y>=0?y:-y)); } public Vector add(Vector v) { return new Vector(this.x+v.x, this.y+v.y); } public Vector neg() { return new Vector(-this.x, -this.y); } public Vector mul(double m) { return new Vector(m*this.x, m*this.y); } public Vector dotMul(Vector m) { return new Vector(this.x * m.x, this.y * m.y); } public Vector dotMul(double m) { return Vector.build(this.x*m, this.y*m); } public Vector dotDiv(Vector m) { return new Vector(this.x/m.x, this.y/m.y); } public Vector dotDiv(double d) { return Vector.build(this.x/d, this.y/d); } public String toString() { return String.format("<%.2f, %.2f>", x, y); } }
配置代码,可以查看不同的效果:
double scale = 80; double aa = 3; double dd = 0.15; Area area = new Area(Vector.build(-aa, aa), Vector.build(aa, -aa)); Vector grid = Vector.build(dd, dd); CanCalc c = new CanCalc(){ public double doCalc(Vector v) { return v.x*v.x - v.y - 2; } };