用Java实现一个向量场


在学习微分方程的时候,以前也写过类似的文章,可是效果不行,前几天写了一个,感觉不错,分享之。

先看效果(x*x -y -2):


再来代码:

  1. package com.math.slopfields;  
  2.   
  3. import java.awt.Color;  
  4. import java.awt.Graphics;  
  5.   
  6. import javax.swing.JFrame;  
  7.   
  8. public class SlopFields  extends JFrame {  
  9.     protected static final int WIDTH = 800;  
  10.     protected static final int HEIGHT = 600;  
  11.     private java.awt.Dimension dimension = java.awt.Toolkit.getDefaultToolkit().  
  12.             getScreenSize();  
  13.       
  14.       
  15.     public SlopFields(String title, Grid g) {  
  16.         super(title);  
  17.         this.setSize(WIDTH, HEIGHT);  
  18.         this.setLocation((dimension.width - WIDTH) / 2,  
  19.                          (dimension.height - HEIGHT) / 2);  
  20.           
  21.         HeartCanvas panel = new HeartCanvas(g);  
  22.         this.add(panel);  
  23.     }  
  24.       
  25.     public static void main(String[] args) {  
  26.         double scale = 80;  
  27.         double aa = 3;  
  28.         double dd = 0.15;  
  29.           
  30.         Area area = new Area(Vector.build(-aa, aa), Vector.build(aa, -aa));  
  31.         Vector grid = Vector.build(dd, dd);  
  32.         CanCalc c = new CanCalc(){  
  33.             public double doCalc(Vector v) {  
  34.                 return v.x*v.x - v.y - 2;  
  35.             }  
  36.               
  37.         };  
  38.         Grid g  = new Grid(area, grid, c, scale);  
  39.   
  40.         SlopFields hart = new SlopFields("向量场", g);  
  41.         hart.setVisible(true);  
  42.         hart.setDefaultCloseOperation(hart.EXIT_ON_CLOSE);  
  43.     }  
  44.       
  45. }  
  46.   
  47.   
  48. class HeartCanvas extends javax.swing.JPanel {  
  49.   
  50.     private Grid grid;  
  51.       
  52.     public HeartCanvas(Grid g) {  
  53.         this.grid = g;  
  54.         this.grid.calcGrids();  
  55.         this.grid.preDraw();  
  56.     }  
  57.       
  58.     public void paintComponent(Graphics g) {  
  59.         setBackground(Color.BLACK);  
  60.         super.paintComponent(g);  
  61.         g.setColor(Color.GREEN);  
  62.         this.grid.draw(g);  
  63.     }  
  64. }  
  65.   
  66.   
  67. class Grid {  
  68.     public double scale = 100;  
  69.     public double padding = 0.2;  
  70.     public Vector offect = Vector.build(0.250.25);  
  71.       
  72.     public Area area;  
  73.     public Area[][] areas;  
  74.       
  75.     public Vector grid;  
  76.     public int nx, ny;  
  77.       
  78.     private CanCalc calc;  
  79.       
  80.     public Grid(Area _area, Vector _grid, CanCalc _calc, double _scale) {  
  81.         this.area = _area;  
  82.         this.grid = _grid;  
  83.         this.calc = _calc;  
  84.         this.scale = _scale;  
  85.     }  
  86.       
  87.     public void draw(Graphics g) {  
  88.           
  89.         int x = (int)area.ld.x;  
  90.         int y = (int)area.ld.y;  
  91.         Vector t = area.ru.add(area.ld.neg());  
  92.         int width = (int)t.x;  
  93.         int height = (int)t.y;  
  94.           
  95.           
  96.         g.drawRect(x, y, width, height);  
  97.         g.drawLine(x, (int)offect.y, x+width, (int)offect.y);  
  98.         g.drawLine((int)offect.x, y, (int)offect.x, y+height);  
  99.         for(Area[] al : areas) {  
  100.             for(Area a : al) {  
  101.                 g.drawLine((int)a.ld.x, (int)a.ld.y, (int)a.ru.x, (int)a.ru.y);  
  102.             }  
  103.         }  
  104.     }  
  105.       
  106.     public void preDraw() {  
  107.         offect = offect.dotMul(this.scale).add(Vector.build(-area.ld.x*scale, area.ru.y*scale));  
  108.         area = new Area(Vector.build(area.ld.x, -area.ru.y).dotMul(this.scale).add(offect),   
  109.                 Vector.build(area.ru.x, -area.ld.x).dotMul(this.scale).add(offect));  
  110.         for(int i=0; i<ny; i++){  
  111.             for(int j=0; j<nx; j++) {  
  112.                 Area tmp = areas[i][j];  
  113.                 Vector va = Vector.build(tmp.ld.x, -tmp.ld.y).dotMul(this.scale).add(offect);  
  114.                 Vector vb = Vector.build(tmp.ru.x, -tmp.ru.y).dotMul(this.scale).add(offect);  
  115.                 areas[i][j] = new Area(va, vb);   
  116.             }  
  117.         }  
  118.     }  
  119.       
  120.       
  121.     private void fixArea() {  
  122.         Vector tn1 = area.ld.dotDiv(grid).intVal().abs();  
  123.         area.ld = grid.dotMul(tn1).neg();  
  124.           
  125.         Vector tn2 = area.ru.dotDiv(grid).intVal().abs();  
  126.         area.ru = grid.dotMul(tn2);  
  127.           
  128.         tn1 = tn1.add(tn2);  
  129.         nx = (int)tn1.x;  
  130.         ny = (int)tn1.y;  
  131.     }  
  132.       
  133.     private Slop[][] initSlop(CanCalc calc) {  
  134.         fixArea();  
  135.         Slop[][] slops = new Slop[nx][ny];  
  136.           
  137.         Vector now = area.ld.clone();  
  138.         now.y += grid.y/2;  
  139.         for(int i=0; i<ny; i++) {  
  140.             now.x = area.ld.x + grid.x/2;  
  141.             for(int j=0; j<nx; j++) {  
  142.                 slops[i][j] = new Slop(now.clone(), calc.doCalc(now));  
  143.                 now.x += grid.x;  
  144.             }  
  145.             now.y += grid.y;  
  146.         }  
  147.         return slops;  
  148.     }  
  149.       
  150.     public Area[][] calcGrids() {  
  151.         Slop[][] slops = initSlop(calc);  
  152.         areas = new Area[nx][ny];  
  153.         for(int i=0; i<nx; i++) {  
  154.             for(int j=0; j<ny; j++) {  
  155.                 Vector tmp = null;  
  156.                 Slop s = slops[i][j];  
  157.                 if(s.slop == grid.slop()) {  
  158.                     tmp = grid.dotDiv(2);  
  159.                 }else if(s.slop == -grid.slop()){  
  160.                     tmp = grid.dotDiv(2).dotMul(Vector.dr);  
  161.                 }else if(s.slop==0){  
  162.                     tmp = Vector.build(grid.x/20);  
  163.                 }else if(s.slop<grid.slop() && s.slop>-grid.slop()) {  
  164.                     tmp = Vector.build(grid.x/2, (grid.x/2)*s.slop);  
  165.                 }else {  
  166.                     tmp = Vector.build((grid.y/2)/s.slop, grid.y/2);  
  167.                 }  
  168.                 tmp = tmp.dotMul(1-this.padding);  
  169.                   
  170.                 areas[i][j] = new Area(s.point.add(tmp.neg()), s.point.add(tmp));  
  171.             }  
  172.         }  
  173.         return areas;  
  174.     }  
  175. }  
  176.   
  177. interface CanCalc {  
  178.     public double doCalc(Vector v);  
  179. }  
  180.   
  181. class Slop{  
  182.     public Vector point;  
  183.     public double slop;  
  184.     public Slop(Vector _point, double _slop) {  
  185.         this.point = _point;  
  186.         this.slop = _slop;  
  187.     }  
  188.     public String toString() {  
  189.         return String.format("{%s, %.2f}", point, slop);  
  190.     }  
  191. }  
  192.   
  193. class Area {  
  194.     public Vector ld;  
  195.     public Vector ru;  
  196.       
  197.     public Area(Vector _ld, Vector _ru) {  
  198.         this.ld = _ld;  
  199.         this.ru = _ru;  
  200.     }  
  201.   
  202.     public String toString() {  
  203.         return String.format("[%s-%s]"this.ld, this.ru);  
  204.     }  
  205.       
  206.     public Area scale(double d) {  
  207.         return new Area(this.ld.dotMul(d), this.ru.dotMul(d));  
  208.     }  
  209.       
  210.     public Area add(Vector v) {  
  211.         return new Area(this.ld.add(v), this.ru.add(v));  
  212.     }  
  213. }  
  214.   
  215.   
  216.   
  217. class Vector {  
  218.     public static final double infinite = Double.MAX_VALUE;  
  219.       
  220.     public double x;  
  221.     public double y;  
  222.   
  223.     public static final Vector zero = Vector.build(00);  
  224.     public static final Vector up = Vector.build(01);  
  225.     public static final Vector down = Vector.build(0, -1);  
  226.     public static final Vector left = Vector.build(-10);  
  227.     public static final Vector right = Vector.build(10);  
  228.     public static final Vector ul = Vector.build(-11);  
  229.     public static final Vector ur = Vector.build(11);  
  230.     public static final Vector dl = Vector.build(-1, -1);  
  231.     public static final Vector dr = Vector.build(1, -1);  
  232.       
  233.     public static Vector build(double x, double y) {  
  234.         return new Vector(x, y);  
  235.     }  
  236.       
  237.     public Vector clone() {  
  238.         return Vector.build(this.x, this.y);  
  239.     }  
  240.       
  241.     public double slop() {  
  242.         if(this.x == 0) {  
  243.             return Vector.infinite;  
  244.         }  
  245.         return this.y / this.x;  
  246.     }  
  247.       
  248.     public Vector(double _x, double _y) {  
  249.         this.x = _x;  
  250.         this.y = _y;  
  251.     }  
  252.       
  253.     public Vector intVal() {  
  254.         return new Vector((int)this.x, (int)this.y);  
  255.     }  
  256.       
  257.     public Vector abs() {  
  258.         return Vector.build((x>=0?x:-x), (y>=0?y:-y));  
  259.     }  
  260.       
  261.     public Vector add(Vector v) {  
  262.         return new Vector(this.x+v.x, this.y+v.y);  
  263.     }  
  264.       
  265.     public Vector neg() {  
  266.         return new Vector(-this.x, -this.y);  
  267.     }  
  268.       
  269.     public Vector mul(double m) {  
  270.         return new Vector(m*this.x, m*this.y);  
  271.     }  
  272.       
  273.     public Vector dotMul(Vector m) {  
  274.         return new Vector(this.x * m.x, this.y * m.y);  
  275.     }  
  276.     public Vector dotMul(double m) {  
  277.         return Vector.build(this.x*m, this.y*m);  
  278.     }  
  279.       
  280.     public Vector dotDiv(Vector m) {  
  281.         return new Vector(this.x/m.x, this.y/m.y);  
  282.     }  
  283.       
  284.     public Vector dotDiv(double d) {  
  285.         return Vector.build(this.x/d, this.y/d);  
  286.     }  
  287.       
  288.     public String toString() {  
  289.         return String.format("<%.2f, %.2f>", x, y);  
  290.     }  
  291.       
  292. }  

配置代码,可以查看不同的效果:

  1.       double scale = 80;  
  2.     double aa = 3;  
  3.     double dd = 0.15;  
  4.       
  5. Area area = new Area(Vector.build(-aa, aa), Vector.build(aa, -aa));  
  6. Vector grid = Vector.build(dd, dd);  
  7. CanCalc c = new CanCalc(){  
  8.     public double doCalc(Vector v) {  
  9.         return v.x*v.x - v.y - 2;  
  10.     }  
  11.       
  12. };  

相关内容