座標の変換を考えます。
グラフィックス画面の座標は、左上が原点です。 また、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点を同時に変換できるメソッドも用意しました。
あと、拡大、平行移動、回転のためのメッソドを作成しました。