MyTransクラス

座標の変換を考えます。

はじめに

グラフィックス画面の座標は、左上が原点です。 また、y座標は下向きに増えます。 画面サイズが width = 400, height = 200 の場合、次のようになります。

下の図は、左下が原点y座標は上向きに増える(数学的)画面です。 1メモリを50ドットにすれば、次のようになります。


今回は、グラフィック画面を意識した座標変換を考えていきます。

MyTrans2D クラス

ソース MyTrans2D.java

package myMath;

// 座標変換
//   (1, 0) -> (a, b)    (0, 1) -> (c, d)    (0, 0) -> (p, q)
public class MyTrans2D {

	public double x, y;
	public double x1, y1, x2, y2;
	public double k;
	MyPoint2D e0 = new MyPoint2D();
	MyPoint2D e1 = new MyPoint2D();
	MyPoint2D e2 = new MyPoint2D();

	// コンストラクタ
	public MyTrans2D() {
		x = y = 0;
		x1 = y1 = x2 = y2 = 0;
		k = 1;
		e0.set(0, 0);
		e1.set(1, 0);
		e2.set(0, 1);
	}

	// 変数代入
	public void set(double a, double b, double c, double d) {
		e1.set(a, b);
		e2.set(c, d);
	}

	// 座標を変換
	public void p(double x, double y) {
		this.x = e1.x * x + e2.x * y + e0.x;
		this.y = e1.y * x + e2.y * y + e0.y;
	}

	public void p(double x1, double y1, double x2, double y2) {
		p(x1, y1);
		this.x1 = x;
		this.y1 = y;
		p(x2, y2);
		this.x2 = x;
		this.y2 = y;
	}

	// 拡大・原点移動
	public void scale(double k) {
		this.k = k;
		e1.scale(k);
		e2.scale(k);
	}

	public void move(double p, double q) {
		p(p, q);
		e0.move(x, y);
	}

	public void rotate(double angle) {
		angle *= Math.signum(e1.x * e2.y - e1.y * e2.x);
		e1.rotate(angle);
		e2.rotate(angle);
	}
	
	////////////////////////////////////////////////////////////
	MyShape sp = new MyShape();
	
	// 直線
	public Line2D Line(double x1, double y1, double x2, double y2) {
		p(x1, y1, x2, y2);
		return sp.Line(this.x1, this.y1, this.x2, this.y2);
	}

	public Line2D Line(MyPoint2D p1, MyPoint2D p2) {
		return Line(p1.x, p1.y, p2.x, p2.y);
	}

	// 軸
	public Line2D LineX() {
		return Line(-10, 0, 10, 0);
	}

	public Line2D LineY() {
		return Line(0, -10, 0, 10);
	}

	// 円
	public Ellipse2D Circle(double x, double y, double r) {
		p(x, y);
		return sp.Circle(this.x, this.y, r * this.k);
	}

	// 点
	int PointSize = 2;

	public Ellipse2D Point(double x, double y) {
		p(x, y);
		return sp.Point(this.x, this.y);
	}

	public void setPointSize(int size) {
		PointSize = size;
	}
}

解説

考え方は簡単です。 点 (1, 0) は点 (a, b) に、点 (0, 1) は点 (c, d) に、原点 (0, 0) は点 (p, q) に移ると考えるだけです。 これで、拡大、縮小、平行移動、回転ができます。 次が座標変換のための計算式です。

x' = ax + cy + p
y' = bx + dy + q

クラス名は、MyTrans2D とします。 後は、{ } の中に書いていきます。

// 座標変換
public class MyTrans2D {
}

メンバーです。 x, y は、変換後の座標を保存するためです。 それと、変換に必要な a, b, c, d, p, q です。 すべて実数値にします。 そのため、double 型とします。

public double x, y;
double a, b, c, d, p, q;

コンストラクタです。 コンストラクタでは、メンバーの初期化ができます。 最初は、変換していない状態です。

// コンストラクタ
public MyTrans2D() {
	a = d = 1;
	b = c = p = q = 0;
	x = y = 0;
}

メンバーに値を代入するメソッド set です。
また、メソッド定義の引数に a を使いました。 そうすると、外にある a が見えなくなります。 そんなとき、this を付けます。 this を付けたものは、メンバーを指します。
値は返さないので、void を付けます。

// 変数代入
public void set(double a, double b, double c, double d) {
	this.a = a;
	this.b = b;
	this.c = c;
	this.d = d;
}

座標変換のためのメソッドです。

// 座標を変換
public void p(double x, double y) {
	this.x = k * (a * x + c * y) + p;
	this.y = k * (b * x + d * y) + q;
}

また、2点を同時に変換できるメソッドも用意しました。

あと、拡大、平行移動、回転のためのメッソドを作成しました。

[前へ] [戻る] [次へ]