AffineTransform 클래스는 2차원 그래픽의 "직진성"을 유지하면서 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 ]
몇 가지 일반적인 아핀 변환:
공개 정적 AffineTransform getTranslateInstance(double tx, double ty)
변환 변환, 각 점을 (x+tx, y+ty)로 이동하면 변환 행렬은 다음과 같습니다.
[ 1 0 tx ] [ 0 1 타이 ] [ 0 0 1 ]
(주석: 번역 변환은 일종의 "강체 변환"입니다. 중학교에서 물리학을 공부한 사람이라면 누구나 "강체"가 무엇인지 알 것입니다. 변형되지 않는 이상적인 객체입니다. 물론 번역은 변경되지 않습니다. 마찬가지로 아래의 '회전변환'도 강체변환이고, '스케일링'과 '크로스커팅'을 하면 그래픽의 모양이 바뀌게 됩니다.)
공개 정적 AffineTransform getScaleInstance(더블 sx, 더블 sy)
스케일링 변환은 각 점의 가로좌표를 sx배로 확대(축소)하고 세로좌표를 sy배로 확대(축소)합니다. 변환 행렬은 다음과 같습니다.
[ sx 0 0 ] [ 0 시 0 ] [ 0 0 1 ]
공개 정적 AffineTransform getShearInstance(더블 shx, 더블 부끄러움)
전단 변환, 변환 행렬은 다음과 같습니다.
[ 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 ]
(번역 참고: "전단 변형"은 "미스컷 변형"이라고도 하는데, 이는 사각형 불안정성과 유사한 특성을 나타냅니다. 길가의 작은 상점에서 철제 미닫이 문을 본 적이 있습니까? 위의 철창을 상상해 보십시오. 마름모의 과정 당기는 것은 "잘못된 절단" 과정입니다.)
공개 정적 AffineTransform getRotateInstance(더블 세타)
회전 변환, 대상 그래픽은 원점을 중심으로 시계 방향으로 세타 라디안을 회전하며 변환 행렬은 다음과 같습니다.
[ cos(세타) -sin(세타) 0 ] [ sin(세타) cos(세타) 0 ] [ 0 0 1 ]
공개 정적 AffineTransform getRotateInstance(더블 세타, 더블 x, 더블 y)
회전 변환, 대상 그래픽은 (x, y)를 축으로 하여 세타 라디안만큼 시계 방향으로 회전하며 변환 행렬은 다음과 같습니다.
[ cos(세타) -sin(세타) xx*cos+y*sin] [ sin(세타) cos(세타) yx*sin-y*cos ] [ 0 0 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는 행렬을 나타냅니다.
당분간은 이해하지 못하더라도 상관없습니다(저도 이해하지 못합니다^_^#). 문제가 되지 않습니다. 여기서는 몇 가지 특수한 경우인 이동 및 회전만 사용합니다. 변환.
평소처럼 아래에 전체 코드를 게시해 보겠습니다.
가져오기 java.applet.Applet;가져오기 java.awt.BorderLayout;가져오기 java.awt.Checkbox;가져오기 java.awt.CheckboxGroup;가져오기 java.awt.Color;가져오기 java.awt.Graphics;가져오기 java.awt.Graphics2D;가져오기 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 클래스 AffineTest 확장 Applet 구현 ItemListener{ private Rectangle2D ret; 체크박스 TranslationFirst; public void init() { setLayout(new BorderLayout()); CheckboxGroup cbg = new CheckboxGroup(); RotateFirst = new Checkbox("rotate, translate", cbg, true) p.add(rotateFirst); ("번역, 회전", cbg, false); translateFirst.addItemListener(this) p.add(translateFirst); BorderLayout.SOUTH); ret = new Rectangle2D.Float(-0.5f, -0.5f, 1.0f, 1.0f); } public void Paint(Graphics g) { Graphics2D g2d = (Graphics2D)g; final AffineTransform (); 부울 회전 = RotateFirst.getState(); Random r = new Random(); oneRadian = Math.toRadians(1.0); for(double radians = 0.0; radians < 2.0*Math.PI ; radians += oneRadian) { g2d.setTransform(identify); if(rotate) { g2d.translate(100, 100) ; g2d.rotate(라디안) } else { g2d.rotate(라디안); g2d.translate(100, 100); } g2d.scale(100, 100); g2d.setColor(new Color(r.nextInt()))) @Override public void itemStateChanged(ItemEvent) arg0) { // TODO 자동 생성된 메소드 스텁 repaint() }}import java.applet.Applet;가져오기 java.awt.BorderLayout;가져오기 java.awt.Checkbox;가져오기 java.awt.CheckboxGroup;가져오기 java.awt.Color;가져오기 java.awt.Graphics;가져오기 java.awt.Graphics2D;가져오기 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 클래스 AffineTest 확장 Applet 구현 ItemListener{ private Rectangle2D ret; 체크박스 TranslationFirst; public void init() { setLayout(new BorderLayout()); CheckboxGroup cbg = new CheckboxGroup(); RotateFirst = new Checkbox("rotate, translate", cbg, true) p.add(rotateFirst); ("번역, 회전", cbg, false); translateFirst.addItemListener(this) p.add(translateFirst); BorderLayout.SOUTH); ret = new Rectangle2D.Float(-0.5f, -0.5f, 1.0f, 1.0f); } public void Paint(Graphics g) { Graphics2D g2d = (Graphics2D)g; final AffineTransform (); 부울 회전 = RotateFirst.getState(); Random r = new Random(); oneRadian = Math.toRadians(1.0); for(double radians = 0.0; radians < 2.0*Math.PI ; radians += oneRadian) { g2d.setTransform(identify); if(rotate) { g2d.translate(100, 100) ; g2d.rotate(라디안) } else { g2d.rotate(라디안); g2d.translate(100, 100); } g2d.scale(100, 100); g2d.setColor(new Color(r.nextInt()))) @Override public void itemStateChanged(ItemEvent) arg0) { // TODO 자동 생성 메서드 스텁 repaint() }}
비교해보면 아핀변환의 순서를 임의로 바꿀 수 없음을 알 수 있다.