続・3次元グラフ

d:id:nattou_curry_2:20081005:1223214031の続きです。
パラメータをいじくって、グラフの見え方を変更できるようにしました。

操作できるパラメータは、以下の五つです。

  • X軸の倍率
  • Z軸の倍率
  • Y軸の倍率
  • ZX平面の傾き
  • ZY平面の傾き

初期状態

Y軸の倍率を操作

ZX平面の傾きを操作

ZY平面の傾きを操作


Javaソース

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ThreeDimensionGraph extends JFrame implements Parameter {
	public static void main( String arsg ) {
		new ThreeDimensionGraph();
	}
	
	private JTextField Xpower = new JTextField( "200" );
	private JTextField Zpower = new JTextField( "20" );
	private JTextField Ypower = new JTextField( "30" );
	private JTextField ZXtilt = new JTextField( "2" );
	private JTextField ZYtilt = new JTextField( "5" );
	private Canvas canvas = new Canvas();
	private GraphAlgorithm algorithm = new GraphAlgorithm().parameter( this ).canvas( canvas ).function( new Function() );
	
	public ThreeDimensionGraph() {
		setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
		setSize(400, 150);
		layoutContentPane( getContentPane() );
		setVisible( true );

		algorithm.draw();
	}

	public int Xpower() { return textFieldToInt( Xpower ); }
	public int Zpower() { return textFieldToInt( Zpower ); }
	public int Ypower() { return textFieldToInt( Ypower ); }
	public int ZXtilt() { return textFieldToInt( ZXtilt ); }
	public int ZYtilt() { return textFieldToInt( ZYtilt ); }
	
	public int textFieldToInt( JTextField textField ) {
		try {
			return Integer.parseInt( textField.getText() );
		} catch ( ArithmeticException e ) {
			return 0;
		}
	}
	
	private void layoutContentPane( Container container ) {
		JPanel panel = new JPanel();
		layoutInputForm( panel );
		
		container.setLayout( new BorderLayout() );
		container.add( canvas, BorderLayout.CENTER );
		container.add( panel, BorderLayout.EAST );
	}
	
	private void layoutInputForm( Container container ) {
		container.setLayout( new GridLayout( 0, 2, 0, 0 ) );
		container.add( new JLabel( "X軸の倍率" ) );
		container.add( Xpower );
		container.add( new JLabel( "Z軸の倍率" ) );
		container.add( Zpower );
		container.add( new JLabel( "Y軸の倍率" ) );
		container.add( Ypower );
		container.add( new JLabel( "ZX平面の傾き" ) );
		container.add( ZXtilt );
		container.add( new JLabel( "ZY平面の傾き" ) );
		container.add( ZYtilt );
		container.add( attachEvent( new JButton( "再描画" ) ) );
	}
		
	private JButton attachEvent( JButton button ) {
		button.addActionListener( new ActionListener() {
			public void actionPerformed( ActionEvent e ) {
				algorithm.draw();
			}
		} );
		return button;
	}
}

interface Parameter {
	public int Xpower();	// Xの倍率
	public int Zpower();	// Zの倍率
	public int Ypower();	// Yの倍率
	public int ZXtilt();	// Z軸とX軸のの傾き
	public int ZYtilt();	// Z軸とY軸の傾き
}

/**
 * 主要なアルゴリズム
 */
class GraphAlgorithm {

	private static final double Xmin = -1;
	private static final double Ymin = -1;
	private static final double Zmin = -1;
	private static final double Xmax = 1;
	private static final double Zmax = 1;
	private static final double Ymax = 1;
	
	private Parameter param;
	private int hoge;
	private Canvas canvas;
	private Function func;
	
	public GraphAlgorithm function( Function func ) {
		this.func = func;
		return this;
	}

	public GraphAlgorithm parameter( Parameter param ) {
		this.param = param;
		this.hoge = param.Xpower() + param.Zpower() * param.ZYtilt();
		return this;
	}

	public GraphAlgorithm canvas( Canvas canvas ) {
		this.canvas = canvas;
		return this;
	}

	public void draw() {
		double x, y, z;
		int i, ix, iz;
		boolean ok, ok1;
		double lowerhorizon = new double[hoge + 1];
		double upperhorizon[] = new double[hoge + 1];
		
		canvas.clear();
		
		for ( i = 0; i <= hoge; ++i ) {
			lowerhorizon[i] = Float.MAX_VALUE;
			upperhorizon[i] = Float.MIN_VALUE;
		}
		for ( iz = 0; iz <= param.Zpower(); ++iz ) {
			z = Zmin + ( Zmax - Zmin ) / param.Zpower() * iz;
			ok1 = false;
			for ( ix = 0; ix <= param.Xpower(); ++ix ) {
				x = Xmin + ( Xmax - Xmin ) / param.Xpower() * ix;
				i = ix + param.ZXtilt() * ( param.Zpower() - iz );
				y = param.Ypower() * ( func.func( x, z ) - Ymin ) / ( Ymax - Ymin ) + param.ZYtilt() * iz;
				
				ok = false;
				if ( y < lowerhorizon[i] ) {
					lowerhorizon[i] = y;
					ok = true;
				}
				if ( y > upperhorizon[i] ) {
					upperhorizon[i] = y;
					ok = true;
				}
				if ( ok && ok1 ) canvas.draw( i, y );
				else canvas.move_( i, y );
				ok1 = ok;
			}

			canvas.repaint();
		}
	}
}


/**
 * 描画する関数
 */
class Function {
	public double func( double x, double z ) {
		double r2;
		r2 = x * x + z * z;
		return Math.exp( -r2 ) * Math.cos( 10 * Math.sqrt( r2 ) );
	}
}	
	
class Canvas extends Panel {
	private Coordinate pen;
	private java.util.List lines = new ArrayList();
	
	public void paint( Graphics g ) {
		g.clearRect( 0, 0, getWidth(), getHeight() );
		for ( Line line : lines ) {
			g.drawLine( adjust( line.start().x() ), getHeight() - adjust( line.start().y() ), adjust( line.end().x() ),getHeight() -  adjust( line.end().y() ) );
		}
	}
	
	private int adjust( double d ) {
		return (int) d;
	}
	
	public void clear() {
		lines = new ArrayList();
		repaint();
	}
	
	public void draw( double x, double y ) {
		Coordinate temp = new Coordinate().x( x ).y( y );
		lines.add( new Line().start( pen ).end( temp ) );
		pen = new Coordinate().x( x ).y( y );
	}
	
	public void move_( double x, double y ) {
		pen = new Coordinate().x( x ).y( y );
	}
}

class Line {
	private Coordinate start;
	private Coordinate end;
	
	public Line start( Coordinate start ) {
		this.start = start;
		return this;
	}
	
	public Line end( Coordinate end ) {
		this.end = end;
		return this;
	}
	
	public Coordinate start() {
		return start;
	}
	
	public Coordinate end() {
		return end;
	}
}

class Coordinate {
	
	private double x;
	private double y;
	
	public Coordinate x( double x ) {
		this.x = x;
		return this;
	}
	
	public Coordinate y( double y ) {
		this.y = y;
		return this;
	}
	
	public double x() {
		return x;
	}
	
	public double y() {
		return y;
	}
}