座標の変換を考えます。
グラフィックス画面の座標は、左上が原点です。 また、y座標は下向きに増えます。 画面サイズが width = 400, height = 200 の場合、次のようになります。
下の図は、左下が原点、 y座標は上向きに増える(数学的)画面です。 1メモリを50ドットにすれば、次のようになります。
今回は、グラフィック画面を意識した座標変換を考えていきます。
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点を同時に変換できるメソッドも用意しました。
あと、拡大、平行移動、回転のためのメッソドを作成しました。