คลาส AffineTransform อธิบายฟังก์ชันการแปลงความสัมพันธ์แบบสองมิติ ซึ่งเป็นการแปลงเชิงเส้นจากพิกัดสองมิติไปเป็นพิกัดสองมิติ โดยรักษา "ความตรง" ของกราฟิกสองมิติ (การแปล: ความตรง นั่นคือ เส้นตรง หลังการแปลงร่าง) ยังคงเป็นเส้นตรงไม่โค้งงอ และส่วนโค้งยังคงอยู่ ส่วนโค้ง) และ "ความขนาน" (คำอธิบายประกอบ: ความขนาน จริงๆ แล้วหมายถึงการรักษาความสัมพันธ์เชิงตำแหน่งสัมพัทธ์ระหว่างตัวเลขสองมิติไม่เปลี่ยนแปลง เส้นขนานยังคงเป็นเส้นขนาน และมุมตัดของเส้นตรงที่ตัดกันยังคงไม่เปลี่ยนแปลง ตัวแปรที่ซับซ้อนเรียนรู้ในปีที่สอง , " จำไว้ว่า "การแปลงร่าง/การแปลงร่าง" คณิตศาสตร์คือราชา!) การแปลง Affine สามารถทำได้โดยการรวมกันของชุดของการแปลงอะตอมมิก ซึ่งรวมถึง: Translation, Scale, Flip, Rotation และ Shear
การแปลงประเภทนี้สามารถแสดงได้ด้วยเมทริกซ์ขนาด 3×3 ซึ่งมีแถวสุดท้ายคือ (0, 0, 1) เมทริกซ์การแปลงนี้จะแปลงพิกัดดั้งเดิม (x, y) เป็นพิกัดใหม่ (x', y') ในที่นี้ พิกัดดั้งเดิมและพิกัดใหม่ถือเป็นเวกเตอร์คอลัมน์สามมิติของแถวสุดท้าย (1) เวกเตอร์คอลัมน์ดั้งเดิมถูกแปลงโดยการคูณทางซ้าย เมทริกซ์ได้รับเวกเตอร์คอลัมน์ใหม่:
[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 เท็กซัส ] [ 0 1 ถึง ] [ 0 0 1 ]
(คำอธิบายประกอบ: การแปลงร่างการแปลเป็น "การเปลี่ยนแปลงร่างกายแข็งเกร็ง" ชนิดหนึ่ง ใครก็ตามที่เคยเรียนฟิสิกส์ในโรงเรียนมัธยมต้นจะรู้ว่า "ร่างกายแข็งเกร็ง" คืออะไร มันเป็นวัตถุในอุดมคติที่จะไม่ทำให้เสียโฉม แน่นอนว่าการแปลจะไม่เปลี่ยนแปลง กราฟิกสองมิติ ในทำนองเดียวกัน "การเปลี่ยนแปลงการหมุน" ด้านล่างก็เป็นการเปลี่ยนแปลงร่างกายที่เข้มงวดเช่นกัน และ "การปรับขนาด" และ "การตัดขวาง" จะเปลี่ยนรูปร่างของกราฟิก)
AffineTransform getScaleInstance แบบคงที่สาธารณะ (double sx, double sy)
การแปลงสเกลจะขยาย (ลด) ค่า abscissa ของแต่ละจุดเป็น 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 แบบคงที่สาธารณะ (theta สองเท่า)
การแปลงแบบหมุน กราฟิกเป้าหมายจะหมุนทีต้าเรเดียนตามเข็มนาฬิการอบจุดกำเนิด เมทริกซ์การแปลงคือ:
[ cos(theta) -sin(theta) 0 ] [ บาป(theta) cos(theta) 0 ] [ 0 0 1 ]
AffineTransform getRotateInstance แบบคงที่สาธารณะ (theta สองเท่า, x สองเท่า, y สองเท่า)
การแปลงการหมุน กราฟิกเป้าหมายจะหมุนตามเข็มนาฬิกาด้วยทีต้าเรเดียนโดยมี (x, y) เป็นแกน และเมทริกซ์การแปลงคือ:
[ cos(theta) -sin(theta) xx*cos+y*sin] [ บาป(theta) cos(theta) yx*sin-y*cos ] [ 0 0 1 ]
ซึ่งเทียบเท่ากับการรวมการแปลงการแปลงสองครั้งและการแปลงการหมุนต้นทางหนึ่งครั้ง:
[1 0 -x][cos(ทีต้า) -sin(ทีต้า) 0][1 0 x] [0 1 -y][sin(ทีต้า) cos(ทีต้า) 0][0 1 ปี] [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;นำเข้า java.awt.geom.AffineTransform;นำเข้า java.awt.geom.Rectangle2D;นำเข้า java.util.Random;คลาสสาธารณะ AffineTest ขยาย Applet ใช้งาน ItemListener{ ส่วนตัวสี่เหลี่ยมผืนผ้า 2D ตรง; ช่องทำเครื่องหมาย TranslateFirst; โมฆะสาธารณะ init() { setLayout(new BorderLayout()); CheckboxGroup cbg = new CheckboxGroup () p.add (rotateFirst = new Checkbox ("แปล, หมุน", cbg, false); TranslateFirst.addItemListener(this); p.add(translateFirst); BorderLayout.SOUTH); rect = new Triangle2D.Float(-0.5f, -0.5f, 1.0f, 1.0f); } สีโมฆะสาธารณะ (กราฟิก g) { Graphics2D g2d = (Graphics2D)g สุดท้ายระบุ AffineTransform = ใหม่ (); หมุนบูลีน = rotFirst.getState (); สุ่ม r = สุ่มใหม่ (); oneRadian = Math.toRadians(1.0); for(double radians = 0.0; radians < 2.0*Math.PI ; radians += oneRadian) { g2d.setTransform(ระบุ) { g2d.translate(100, 100) ; g2d.rotate(เรเดียน); g2d.translate(100, 100); } g2d.scale(100, 100); g2d.setColor(สีใหม่(r.nextInt())); g2d.fill(rect); } } @แทนที่ สาธารณะ itemStateChanged(ItemEvent arg0) { // TODO วิธีการสร้าง stub ทาสีใหม่ (); }} 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;นำเข้า java.awt.geom.AffineTransform;นำเข้า java.awt.geom.Rectangle2D;นำเข้า java.util.Random;คลาสสาธารณะ AffineTest ขยาย Applet ใช้งาน ItemListener{ ส่วนตัวสี่เหลี่ยมผืนผ้า 2D ตรง; ช่องทำเครื่องหมาย TranslateFirst; โมฆะสาธารณะ init() { setLayout(new BorderLayout()); CheckboxGroup cbg = new CheckboxGroup () p.add (rotateFirst = new Checkbox ("แปล, หมุน", cbg, false); TranslateFirst.addItemListener(this); p.add(translateFirst); BorderLayout.SOUTH); rect = new Square2D.Float(-0.5f, -0.5f, 1.0f, 1.0f); } สีโมฆะสาธารณะ (กราฟิก g) { Graphics2D g2d = (Graphics2D)g สุดท้ายระบุ AffineTransform = ใหม่ (); หมุนบูลีน = rotFirst.getState (); สุ่ม r = สุ่มใหม่ (); oneRadian = Math.toRadians(1.0); for(double radians = 0.0; radians < 2.0*Math.PI ; radians += oneRadian) { g2d.setTransform(ระบุ) { g2d.translate(100, 100) ; g2d.rotate(เรเดียน); g2d.translate(100, 100); } g2d.scale(100, 100); g2d.setColor(สีใหม่(r.nextInt())); g2d.fill(rect); } } @แทนที่ สาธารณะ itemStateChanged(ItemEvent arg0) { // TODO วิธีการสร้างต้นขั้วทาสีใหม่ ();
จากการเปรียบเทียบ จะเห็นได้ว่าลำดับการเปลี่ยนแปลงความสัมพันธ์ไม่สามารถแลกเปลี่ยนกันได้โดยไม่ได้ตั้งใจ