Java 2D – Transformation

Phép biến đổi affine là kết hợp của 0 hoặc nhiều phép biến đổi tuyến tính (quay (rotation), phóng to nhỏ (scaling) hoặc làm biến hình(shear), tịnh tiến (translation )). Nhiều phép biến đổi tuyến tính có thể được kết hợp vào 1 ma trận. Phép quay là phép biến đổi quay 1 hình quay 1 điểm cố định. Phép phóng to/nhỏ ảnh là phép biến đổi mở rộng hoặc thu nhỏ đối tượng. Hệ số scale giống nhau theo tất cả các hướng. Phép tịnh tiến là phép biến đổi dịch tất cả các điểm đi 1 khoảng cách theo 1 hướng chỉ định. Phép biến hình là phép biến đổi di chuyển 1 vật vuông góc với 1 trục cố định.

AffineTransform là class trong Java 2D thực hiện phép biến đổi affine.

Phép tịnh tiến

TranslationEx.java

package net.vncoding;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;

class Surface extends JPanel {

    private void doDrawing(Graphics g) {
        
        Graphics2D g2d = (Graphics2D) g.create();

        g2d.setPaint(new Color(150, 150, 150));
        g2d.fillRect(20, 20, 80, 50);
        g2d.translate(150, 50);
        g2d.fillRect(20, 20, 80, 50);
        
        g2d.dispose();
    }

    @Override
    public void paintComponent(Graphics g) {
        
        super.paintComponent(g);
        doDrawing(g);
    }
}

public class TranslationEx extends JFrame {
    
    public TranslationEx() {
        
        initUI();
    }
    
    private void initUI() {
        
        add(new Surface());

        setTitle("Translation");
        setSize(300, 200);
        setLocationRelativeTo(null);        
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                TranslationEx ex = new TranslationEx();
                ex.setVisible(true);
            }
        });                    
    }
}

Giải thích:
Ví dụ này vẽ hình chữ nhât. Sau đó thực hiện phép tịnh tiến và vẽ hình chữ nhật tại vị trí mới.

g2d.translate(150, 50);

Dòng code này dịch điểm gốc của Graphics2D context tới vị trí mới.

Kết quả:

Java 2D - Phép tịnh tiến
Java 2D – Phép tịnh tiến

Phép quay

RotationEx.java

package net.vncoding;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;

class Surface extends JPanel {

    private void doDrawing(Graphics g) {
        
        Graphics2D g2d = (Graphics2D) g.create();

        g2d.setPaint(new Color(150, 150, 150));
        g2d.fillRect(20, 20, 80, 50);
        g2d.translate(180, -50);
        g2d.rotate(Math.PI/4);
        g2d.fillRect(80, 80, 80, 50);
        
        g2d.dispose();
    }

    @Override
    public void paintComponent(Graphics g) {
        
        super.paintComponent(g);
        doDrawing(g);
    }
}

public class RotationEx extends JFrame {
    
    public RotationEx() {
        
        initUI();
    }
    
    private void initUI() {
        
        setTitle("Rotation");

        add(new Surface());

        setSize(300, 200);
        setLocationRelativeTo(null);        
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                RotationEx ex = new RotationEx();
                ex.setVisible(true);
            }
        });           
    }
}

Giải thích:
Trong ví dụ này, chúng ta vẽ hình chữ nhật, thực hiện phép tịnh tiến và phép quay, sau đó vẽ hình chữ mới.

g2d.rotate(Math.PI/4);

Phương thức rotate() thực hiện phép quay. Chú ý: tham số truyền vào phải là radian

Kết quả:

Java 2D - Phép quay
Java 2D – Phép quay

Scaling image

Ví dụ tiếp theo minh họa việc scaling image. Scaling được thực hiện bởi phương thức scale(). Tham số truyền vào cho phương thức scale() là hệ số scale x và y.

package net.vncoding;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;

class Surface extends JPanel {

    private void doDrawing(Graphics g) {

        Graphics2D g2d = (Graphics2D) g.create();

        g2d.setColor(new Color(150, 150, 150));
        g2d.fillRect(20, 20, 80, 50);

        AffineTransform tx1 = new AffineTransform();
        tx1.translate(110, 22);
        tx1.scale(0.5, 0.5);

        g2d.setTransform(tx1);
        g2d.fillRect(0, 0, 80, 50);

        AffineTransform tx2 = new AffineTransform();
        tx2.translate(170, 20);
        tx2.scale(1.5, 1.5);

        g2d.setTransform(tx2);
        g2d.fillRect(0, 0, 80, 50);
        
        g2d.dispose();
    }

    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);
        doDrawing(g);
    }
}

public class ScalingEx extends JFrame {

    public ScalingEx() {

        initUI();
    }

    private void initUI() {

        add(new Surface());

        setTitle("Scaling");
        setSize(330, 160);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                ScalingEx ex = new ScalingEx();
                ex.setVisible(true);
            }
        });
    }
}

Giải thích:
Trước tiên, chúng ta vẽ hình chữ nhật, sau đó thu nhỏ (scale down) và phóng to (scale up).

AffineTransform tx2 = new AffineTransform();
tx2.translate(170, 20);
tx2.scale(1.5, 1.5);

Tạo object AffineTransform, thực hiện phép tịnh tiến, sau đó scale object.

Kết quả:

Java 2D - Scaling image
Java 2D – Scaling image

Phép biến hình

Trong ví dụ tiếp theo, chúng ta thực hiện phép biến hình với việc sử dụng phương thức shear().

package net.vncoding;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;

class Surface extends JPanel {

    private void doDrawing(Graphics g) {

        Graphics2D g2d = (Graphics2D) g.create();

        AffineTransform tx1 = new AffineTransform();
        tx1.translate(50, 90);

        g2d.setTransform(tx1);
        g2d.setPaint(Color.green);
        g2d.drawRect(0, 0, 160, 50);

        AffineTransform tx2 = new AffineTransform();
        tx2.translate(50, 90);
        tx2.shear(0, 1);

        g2d.setTransform(tx2);
        g2d.setPaint(Color.blue);

        g2d.draw(new Rectangle(0, 0, 80, 50));

        AffineTransform tx3 = new AffineTransform();
        tx3.translate(130, 10);
        tx3.shear(0, 1);

        g2d.setTransform(tx3);
        g2d.setPaint(Color.red);
        g2d.drawRect(0, 0, 80, 50);
        
        g2d.dispose();
    }

    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);
        doDrawing(g);
    }
}

public class ShearingEx extends JFrame {

    public ShearingEx() {

        initUI();
    }

    private void initUI() {

        add(new Surface());

        setTitle("Shearing");
        setSize(330, 270);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                ShearingEx ex = new ShearingEx();
                ex.setVisible(true);
            }
        });
    }
}

Giải thích:
Trong ví dụ, chúng ta vẽ 3 hình chữ nhật với 3 màu khác nhau.
2 hình chữ (red và blue) bị biến hình.

tx2.shear(0, 1);

Sử dụng phương thức shear() để biến hình.
Trong đó, 2 tham số là hệ số nhân mà hệ trục tọa độ được dịch đi theo hướng x, y

Kết quả:

Java 2D - Phép biến hình
Java 2D – Phép biến hình

Hình 3D

Trong ví dụ này, chúng ta tạo 1 hình 3D bằng việc xoay hình elip.

package net.vncoding;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;

class Surface extends JPanel {

    private void doDrawing(Graphics g) {

        Graphics2D g2d = (Graphics2D) g.create();

        RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        rh.put(RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_QUALITY);

        g2d.setRenderingHints(rh);

        Dimension size = getSize();
        double w = size.getWidth();
        double h = size.getHeight();

        Ellipse2D e = new Ellipse2D.Double(0, 0, 80, 130);
        g2d.setStroke(new BasicStroke(1));
        g2d.setPaint(Color.gray);

        for (double deg = 0; deg < 360; deg += 5) {
            AffineTransform at =
                    AffineTransform.getTranslateInstance(w / 2, h / 2);
            at.rotate(Math.toRadians(deg));
            g2d.draw(at.createTransformedShape(e));
        }
    }

    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);
        doDrawing(g);
    }
}

public class DonutEx extends JFrame {

    public DonutEx() {

        initUI();
    }

    private void initUI() {

        add(new Surface());

        setTitle("Donut");
        setSize(370, 320);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                DonutEx ex = new DonutEx();
                ex.setVisible(true);
            }
        });
    }
}

Giải thích:
Trong ví dụ này, chúng ta tạo ra hình “bánh rán”

Ellipse2D e = new Ellipse2D.Double(0, 0, 80, 130);
g2d.setStroke(new BasicStroke(1));
g2d.setPaint(Color.gray);

Tạo 1 hình elip.

for (double deg = 0; deg < 360; deg += 5) {
    AffineTransform at =
            AffineTransform.getTranslateInstance(w / 2, h / 2);
    at.rotate(Math.toRadians(deg));
    g2d.draw(at.createTransformedShape(e));
}

Sau đó, thực hiện phép quay. Chúng ta thu được hình “bánh rán”

Kết quả:

Java 2D - Vẽ hình phức tạp
Java 2D – Vẽ hình phức tạp

Be the first to comment

Leave a Reply