`
mmdev
  • 浏览: 12927010 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

用Java实现一个向量场

 
阅读更多

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

先看效果(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;
			}
			
		};

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics