AffineTransform クラスは、2 次元アフィン変換関数を記述します。これは、2 次元グラフィックスの「直線性」を維持しながら、2 次元座標から 2 次元座標への線形変換です。変形後)曲がらず直線のまま、弧も残っています。円弧)と「平行度」(注:平行とは、実際には二次元の図形間の相対的な位置関係が変わらないこと、平行線は平行線のまま、交差する直線の交角は変わらないことを指します。2年生で学習する複素変数) 、「「等角変換/共形変換」を覚えておいてください。数学は王様です!)。アフィン変換は、移動、スケール、反転、回転、剪断などの一連のアトミック変換を組み合わせることによって実現できます。
このタイプの変換は、最後の行が (0, 0, 1) である 3×3 行列で表すことができます。この変換行列は、元の座標 (x, y) を新しい座標 (x', y') に変換します。ここでは、元の座標と新しい座標を最後の行 (1) の 3 次元列ベクトルとみなします。元の列ベクトルは左乗算によって変換され、行列は新しい列ベクトルを取得します。
[x'] [m00 m01 m02] [x] [m00*x+m01*y+m02] [y'] = [m10 m11 m12] [y] = [m10*x+m11*y+m12] [1 ] [ 0 0 1 ] [1] [ 1 ]
いくつかの典型的なアフィン変換:
public static AffineTransform getTranslateInstance(double tx, double ty)
平行移動変換。各点を (x+tx, y+ty) に移動します。変換行列は次のとおりです。
[ 1 0 tx ] [ 0 1 ty ] [ 0 0 1 ]
(注:平行移動変換は「剛体変形」の一種です。中学校で物理を学んだ人なら誰でも知っている「剛体」です。変形しない理想的な物体です。もちろん、平行移動は変わりません) 2次元グラフィックスも同様に、以下の「回転変換」も剛体変換であり、「拡大縮小」や「横断」によりグラフィックスの形状が変化します。
パブリック静的 AffineTransform getScaleInstance(double sx, double sy)
スケーリング変換は、各点の横座標を sx 倍に拡大 (縮小) し、縦座標を sy 倍に拡大 (縮小) します。変換行列は次のとおりです。
[ sx 0 0 ] [ 0 sy 0 ] [ 0 0 1 ]
public static AffineTransform getShearInstance(double shx, double shy)
せん断変換の変換行列は次のとおりです。
[ 1 shx 0 ] [ シャイ 1 0 ] [ 0 0 1 ]
横せん断と縦せん断を組み合わせたものに相当
[ 1 0 0 ][ 1 shx 0 ] [ シャイ 1 0 ][ 0 1 0 ] [ 0 0 1 ][ 0 0 1 ]
(訳注:「せん断変形」は「ミスカット変形」とも呼ばれ、四角形の不安定性に似た性質のことを指します。 街中の小さなお店などで鉄の引き戸を見たことがあるでしょうか。上の鉄格子を想像してみてください。ひし形の加工引っ張ることは「間違った切断」のプロセスです)。
public static AffineTransform getRotateInstance(ダブルシータ)
回転変換。ターゲット グラフィックは原点を中心に時計回りにシータ ラジアン回転します。変換行列は次のとおりです。
[ cos(θ) -sin(θ) 0 ] [ sin(θ) cos(θ) 0 ] [ 0 0 1 ]
public static AffineTransform getRotateInstance(double theta、double x、double y)
回転変換。ターゲット グラフィックは (x, y) を軸としてシータ ラジアンだけ時計回りに回転します。変換行列は次のとおりです。
[ cos(θ) -sin(θ) xx*cos+y*sin] [ sin(θ) cos(θ) yx*sin-y*cos ] [ 0 0 1 ]
これは、2 つの平行移動変換と 1 つの原点回転変換の複合に相当します。
[1 0 -x][cos(θ) -sin(θ) 0][1 0 x] [0 1 -y][sin(θ) cos(θ) 0][0 1 y] [0 0 1 ] [0 0 1][0 0 1]
ジオメトリでは、ベクトル空間に線形変換が行われ、その後に変換が行われます。このプロセスはアフィン変換または放射状マッピングと呼ばれます。
これは、y = Ax + b のように簡単に表すことができます。ここで、下付き文字はベクトルを表し、太字の A は行列を表します。
当面は理解できなくても問題ありません (私も理解できません^_^#)、問題ありません。ここでは、変換と回転という特殊なケースをいくつかのみ使用します。変換。
いつものように、コード全体を以下に投稿しましょう。
import java.applet.Applet;import java.awt.BorderLayout;import java.awt.Checkbox;import java.awt.CheckboxGroup;import java.awt.Color;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.Panel;インポート java.awt.event.ItemEvent;インポートjava.awt.event.ItemListener;import java.awt.geom.AffineTransform;import java.awt.geom.Rectangle2D;import java.util.Random;public class AffineTest extends Appletimplements ItemListener{ private Rectangle2D rect;チェックボックス translationFirst; public void init() { setLayout(new BorderLayout());チェックボックスグループ cbg = 新しいチェックボックスグループ (); パネル p = 新しいパネル (); 回転ファースト = 新しいチェックボックス ("回転、変換"、cbg、true); p.add(回転ファースト); ("翻訳、回転"、cbg、false); p.add(translateFirst); BorderLayout.SOUTH); rect = new Rectangle2D.Float(-0.5f, -0.5f, 1.0f, 1.0f); } public void Pain(Graphics g) { Graphics2D g2d = (Graphics2D)g; (); ブール値の回転 =rotateFirst.getState(); oneRadian = Math.toRadians(1.0); for(double radians = 0.0; ラジアン < 2.0*Math.PI ; ラジアン += oneRadian) { g2d.setTransform(identify) { g2d.translate(100, 100); ; g2d.rotate(ラジアン); } else { g2d.rotate(ラジアン); g2d.translate(100, 100); g2d.scale(100, 100); g2d.fill(rect); arg0) { // TODO 自動生成されたメソッド スタブ repaint() }}import; java.applet.Applet;import java.awt.BorderLayout;import java.awt.Checkbox;import java.awt.CheckboxGroup;import java.awt.Color;import java.awt.Graphics;import java.awt.Graphics2D;import java .awt.Panel;インポート java.awt.event.ItemEvent;インポートjava.awt.event.ItemListener;import java.awt.geom.AffineTransform;import java.awt.geom.Rectangle2D;import java.util.Random;public class AffineTest extends Appletimplements ItemListener{ private Rectangle2D rect;チェックボックス translationFirst; public void init() { setLayout(new BorderLayout());チェックボックスグループ cbg = 新しいチェックボックスグループ (); パネル p = 新しいパネル (); 回転ファースト = 新しいチェックボックス ("回転、変換"、cbg、true); p.add(回転ファースト); ("翻訳、回転"、cbg、false); p.add(translateFirst); BorderLayout.SOUTH); rect = new Rectangle2D.Float(-0.5f, -0.5f, 1.0f, 1.0f); } public void Pain(Graphics g) { Graphics2D g2d = (Graphics2D)g; (); ブール値の回転 =rotateFirst.getState(); oneRadian = Math.toRadians(1.0); for(double radians = 0.0; ラジアン < 2.0*Math.PI ; ラジアン += oneRadian) { g2d.setTransform(identify) { g2d.translate(100, 100) ; g2d.rotate(ラジアン); } else { g2d.rotate(ラジアン); g2d.translate(100, 100); g2d.scale(100, 100); g2d.fill(rect); arg0) { // TODO 自動生成されたメソッド スタブ repaint(); }}
比較すると、アフィン変換の順序は気軽に入れ替えることができないことがわかります。