Hướng dẫn sử dụng các phép biến hình (Transformations) trong JavaFX

Xem thêm các chuyên mục:

1- Transformation là gì?

Transformation (Phép biến hình) là một khái niệm hình học, nó có nghĩa là thay đổi hình dạng của một vật thể để thành một hình dạng khác. Có một vài phép biến hình thông dụng như là:
  • Translation (Dịch chuyển)
  • Scale (Phóng to hoặc thu nhỏ)
  • Rotation (Xoay hình)
  • Shearing (Nghiêng hình)
  • ...

Translation (Dịch chuyển).

Reflection (Sự phản xạ)

Rotation (Xoay)

Shearing/Skewing (Xén, trượt)

Shear by x axis (Theo trục x):
Shear by y axis (Theo trục y)

2- Translation Transformation (Phép biến hình dịch chuyển)

Translation transformation (Phép biến hình dịch chuyển) sẽ di chuyển một đối tượng sang một vị trí khác theo một hướng cụ thể. Ví dụ đơn giản nhất chính là việc di chuyển một điểm (Point) sang một vị trí khác.
Tất cả các điểm trên đối tượng hình học di chuyển theo một hướng và di chuyển cùng một khoảng cách:

Ví dụ:

Ví dụ, có 2 hình chữ nhật (Rectangle) cùng vị trí và kích thước, chúng ta sẽ sử dụng phép biến hình dịch chuyển (Translation transformation) để di chuyển hình chữ nhật thứ 2. Và xem kết quả:
TranslationExample.java
package org.o7planning.javafx.transformation;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;

public class TranslationExample extends Application {

   @Override
   public void start(Stage stage) {

      final int x = 10;
      final int y = 20;
      final int width = 100;
      final int height = 130;

      // Rectangle1
      Rectangle rectangle1 = new Rectangle(x, y, width, height);

      // Rectangle2 (Cùng vị trí và kích thước với rectangle1)
      Rectangle rectangle2 = new Rectangle(x, y, width, height);

      rectangle1.setFill(Color.BROWN);
      rectangle1.setStrokeWidth(20);

      rectangle2.setFill(Color.CADETBLUE);
      rectangle2.setStrokeWidth(20);

      // Tạo Translation transformation
      Translate translate = new Translate();

      // Sét đặt các thông số cho sự dịch chuyển.
      translate.setX(200);
      translate.setY(50);
      translate.setZ(100);

      // Thêm phép biến hình vào cho rectangle2
      rectangle2.getTransforms().addAll(translate);

      Group root = new Group(rectangle1, rectangle2);

      Scene scene = new Scene(root, 450, 250);

      stage.setTitle("JavaFX Translation Transformation (o7planning.org)");
      stage.setScene(scene);
      stage.show();
   }

   public static void main(String args[]) {
      launch(args);
   }
}

3- Rotation Transformation (Phép biến hình xoay)

Rotation Transformation (Phép biến hình xoay), nó xoay một đối tượng hình học đi một góc, quanh một điểm cố định. Điểm cố định này được gọi là điểm pivot (điểm trục)

Ví dụ:

Ví dụ, có 2 hình chữ nhật (Rectangle) cùng vị trí và kích thước. Chúng ta sẽ sử dụng phép biến hình xoay (Rotation Transformation) để xoay hình chữ nhật thứ 2 một góc 20 độ, quanh điểm pivot (điểm trục). Và xem kết quả.
RotationExample.java
package org.o7planning.javafx.transformation;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;

public class RotationExample extends Application {
	@Override
	public void start(Stage stage) {

		final int x = 200;
		final int y = 10;
		final int width = 130;
		final int height = 170;
		int pivotX = 30;
		int pivotY = 50;

		// Rectangle1
		Rectangle rectangle1 = new Rectangle(x, y, width, height);
		rectangle1.setFill(Color.BLUE);
		rectangle1.setStroke(Color.BLACK);

		// Rectangle2
		Rectangle rectangle2 = new Rectangle(x, y, width, height);
		rectangle2.setFill(Color.BURLYWOOD);
		rectangle2.setStroke(Color.BLACK);

		Circle pivot = new Circle(pivotX, pivotY, 3);
		pivot.setFill(Color.RED);

		// Tạo phép biến hình xoay (Rotation Transformation)
		Rotate rotate = new Rotate();

		// Sét đặt góc quay (20 độ)
		rotate.setAngle(20);

		// Sét đặt 'trục xoay' (Pivot) cho phép xoay hình.
		rotate.setPivotX(pivotX);
		rotate.setPivotY(pivotY);

		// Thêm phép biến hình (transformation) vào cho rectangle2.
		rectangle2.getTransforms().addAll(rotate);

		Group root = new Group(rectangle1, rectangle2, pivot);

		Scene scene = new Scene(root, 450, 300);
		stage.setTitle("JavaFX Rotation Transformation (o7planning.org)");
		stage.setScene(scene);
		stage.show();
	}

	public static void main(String args[]) {
		launch(args);
	}
}

4- Scaling Transformation (Phép biến hình tỷ lệ)

Scaling Transformation (Phép biến hình tỷ lệ) được sử dụng để thay đổi kích thước của một đối tượng hình học. Bạn có thể sử dụng để co hoặc giãn các chiều (dimension) của đối tượng.
Một điểm sẽ được lấy làm gốc tọa độ. Scaling có thể đặt được bằng cách nhân các tọa độ của đối tượng ban đầu với thừa số co giãn (scaling factor) để có được kết quả mong muốn. Xem thêm hình minh họa phía dưới.

Ví dụ:

Có hai hình chữ nhật (Rectangle), cùng vị trí và kích thước, chọn một điểm làm gốc cho hệ tọa độ mới. Và sử dụng Scaling Transformation để co giãn tọa độ của vật thể theo trục X lên 2 lần, và co giãn tọa độ theo trục Y lên 4 lần.
ScalingExample.java
package org.o7planning.javafx.transformation;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Scale;
import javafx.stage.Stage;

public class ScalingExample extends Application {
   @Override
   public void start(Stage stage) {

      final int x = 80;
      final int y = 90;
      final int width = 100;
      final int height = 70;

      int pivotX = 30;
      int pivotY = 50;
      double scaleX = 2;
      double scaleY = 4;

      // Rectangle1
      Rectangle rectangle1 = new Rectangle(x, y, width, height);
      rectangle1.setFill(Color.BLUE);
      rectangle1.setStroke(Color.BLACK);

      // Rectangle2
      Rectangle rectangle2 = new Rectangle(x, y, width, height);
      rectangle2.setFill(Color.BURLYWOOD);
      rectangle2.setStroke(Color.BLACK);

      Circle pivot = new Circle(pivotX, pivotY, 3);
      pivot.setFill(Color.RED);

      // Tạo phép biến hình Scale (Scale Transformation)
      Scale scale = new Scale();

      // Sét đặt thừa số co giãn (Scaling factor)
      scale.setX(scaleX);
      scale.setY(scaleY);

      // Sét đặt gốc hệ tọa độ mới.
      scale.setPivotX(pivotX);
      scale.setPivotY(pivotY);

      // Thêm phép biến hình (transformation) vào cho rectangle2.
      rectangle2.getTransforms().addAll(scale);

      Group root = new Group(rectangle1, rectangle2, pivot);
      Scene scene = new Scene(root, 450, 500);
      stage.setTitle("JavaFX Scaling Transformation (o7planning.org)");
      stage.setScene(scene);

      stage.show();
   }

   public static void main(String args[]) {
      launch(args);
   }

}

5- Shearing Transformation (Biến dạng trượt)

Shearing - Làm biến dạng một đối tượng bằng cách đẩy nó theo một hướng cụ thể, hoặc trượt một đối tượng khác trên đối tượng này, làm biến dạng nó.
Có thể bạn biết đến "shear a sheep", đó là hành động chỉ việc xén lông một con cừu, Shearing Transformation không nhằm cắt một phần ra khỏi đối tượng hình học ban đầu. Nó chỉ làm biến dạng đối tượng hình gốc.
Shearing sử dụng một điểm làm mốc ( pivot) để làm biến dạng vật thể.
Nếu pivot đặt tại gốc của hệ tọa độ (Origin of the coordinate system). Thừa số shearing đối tượng theo chiều X, và Y lần lượt là shearX, shearY thì:
  • (x, y) ==> (x + y * shearY, y + x * shearX)

Nếu điểm pivot nằm tại tọa độ ( pivotX, pivotY), và thừa số shearing theo chiều X, Y lần lượt là shearX, shearY thì:
  • (x, y) ===> (X", Y")

  • X" =  pivotX + (x-pivotX) + (y-pivotY) * shearY

  • Y" =  pivotY + (y-pivotY) + (x-pivotX) * shearX


 

Ví dụ:

Hãy xem hình minh họa dưới đây:
  1. Giả sử rằng điểm pivot nằm tại gốc tọa độ.
  2. Thừa số shearing theo trục X là shearX = 2.
  3. Thừa số shearing theo trục Y là shearY = 0.
Chúng ta sẽ có kết quả:
  • xA" = xA + shearY * yA = 1 + 2 * 1 = 3

  • yA" = yA + shearX * xA = 1 + 0 * 1 = 1

  • xB" = xB + shearY * yB = 3 + 2 * 4 = 11

  • yB" = yB + shearX + yB = 4 + 0 * 4 = 4

Ví dụ JavaFX:

Có hai hình chữ nhật (Rectangle), cùng vị trí và kích thước, chọn một điểm pivot. Và sử dụng Shearing Transformation cho hình chữ nhật 2, và xem kết quả:
ShearingExample.java
package org.o7planning.javafx.transformation;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Shear;
import javafx.stage.Stage;

public class ShearingExample extends Application {
	
	@Override
	public void start(Stage stage) {
		final int x = 120;
		final int y = 80;
		final int width = 150;
		final int height = 100;

		int pivotX = 40;
		int pivotY = 50;
		double shearX = 0.2;
		double shearY = 0.5;

		// (all)
		// Rectangle1
		Rectangle rectangle1 = new Rectangle(x, y, width, height);
		rectangle1.setFill(Color.BLUE);
		rectangle1.setStroke(Color.BLACK);

		// (all)
		// Rectangle2
		Rectangle rectangle2 = new Rectangle(x, y, width, height);
		rectangle2.setFill(Color.BURLYWOOD);
		rectangle2.setStroke(Color.BLACK);

		Circle pivot = new Circle(pivotX, pivotY, 3);
		pivot.setFill(Color.RED);

		// Tạo phép biến hình Shearing (Shearing Transformation)
		Shear shear = new Shear();

		// Sét đặt điểm pivot.
		shear.setPivotX(pivotX);
		shear.setPivotY(pivotY);

		// Sét đặt các thừa số shearing
		shear.setX(shearX);
		shear.setY(shearY);

		// Thêm phép biến hình (transformation) vào cho rectangle2.
		rectangle2.getTransforms().addAll(shear);

		Group root = new Group(rectangle1, rectangle2, pivot);
		Scene scene = new Scene(root, 450, 300);
		stage.setTitle("Shearing Transformation (o7planning.org)");
		stage.setScene(scene);
		stage.show();
	}

	public static void main(String args[]) {
		launch(args);
	}
}
Chạy ví dụ:
Sửa lại ví dụ trên với:
  • double shearX = 0;
  • double shearY = 0.5;
Sửa lại ví dụ trên với các giá trị:
  • double shearX = 0.2;
  • double shearY = 0;

6- Affine Transformation (Phép biến hình Affine)

Affine là một phép biến hình tuyến tính (Linear transformation), nó biến đổi một đối tượng từ một không gian 2 hoặc 3 chiều, vào một không gian 2 hoặc 3 chiều khác. Đồng thời vẫn giữ nguyên tính thẳng hàng (straightness) và song song (parallelness) của các đường thẳng (lines).
Một điểm A có tọa độ (x, y, z) trong không gian 3 chiều sẽ chuyển tới vị trí A" có tọa độ (x", y", z") theo một phép nhân ma trận (matrix):
Lớp Affine trong JavaFX có một vài Constructor, dưới đây là các structructor thông dụng:
// Contructor để tạo một Affine 2 chiều (2D)
public Affine(double mxx, double mxy, double tx,
                  double myx, double myy, double ty);


// Contructor để tạo một Affine 3 chiều (3D)
public Affine(double mxx, double mxy, double mxz, double tx,
          double myx, double myy, double myz, double ty,
          double mzx, double mzy, double mzz, double tz) ;

Ví dụ:

AffineExample.java
package org.o7planning.javafx.transformation;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Affine;
import javafx.stage.Stage;

public class AffineExample extends Application {
	
	@Override
	public void start(Stage stage) {

		final int x = 80;
		final int y = 90;
		final int width = 100;
		final int height = 70;

		double mxx = 0.2;
		double mxy = 1.5;
		double myx = 1.5;
		double myy = 0.5;

		double tx = 40;
		double ty = 50;

		// Rectangle1
		Rectangle rectangle1 = new Rectangle(x, y, width, height);
		rectangle1.setFill(Color.BLUE);
		rectangle1.setStroke(Color.BLACK);

		// Rectangle2
		Rectangle rectangle2 = new Rectangle(x, y, width, height);
		rectangle2.setFill(Color.BURLYWOOD);
		rectangle2.setStroke(Color.BLACK);

		Circle pivot = new Circle(tx, ty, 3);
		pivot.setFill(Color.RED);

		// Tạo phép biến hình Affine 2 Chiều (2D Affine Transformation)
		Affine affine = new Affine(mxx, mxy, tx, myx, myy, ty);

	 

		// Thêm phép biến hình (transformation) vào cho rectangle2.
		rectangle2.getTransforms().addAll(affine);

		Group root = new Group(rectangle1, rectangle2, pivot);
		Scene scene = new Scene(root, 450, 500);
		stage.setTitle("JavaFX Affine Transformation (o7planning.org)");
		stage.setScene(scene);

		stage.show();
	}

	public static void main(String args[]) {
		launch(args);
	}

}
Chạy ví dụ:

7- Kết hợp các phép biến hình

Bạn có thể áp dụng nhiều phép biến hình cho một đối tượng hình học:

Ví dụ:

Trong ví dụ này, bạn có 3 hình chữ nhật (Rectangle) cùng vị trí và kích thước, tạo 2 phép biến hình là Rotation (Xoay) và Translation (Dịch chuyển). Thêm phép biến hình Rotation vào cho hình chữ nhật 2, và cả 2 phép biến hình trên vào cho hình chữ nhật 3. Và xem kết quả.
MultipleTransformationsExample.java
package org.o7planning.javafx.transformation;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;

public class MultipleTransformationsExample extends Application {
	@Override
	public void start(Stage stage) {

		final int x = 200;
		final int y = 10;
		final int width = 130;
		final int height = 170;
		int pivotX = 30;
		int pivotY = 50;

		// Rectangle1
		Rectangle rectangle1 = new Rectangle(x, y, width, height);
		rectangle1.setFill(Color.BLUE);
		rectangle1.setStroke(Color.BLACK);

		// Rectangle2
		Rectangle rectangle2 = new Rectangle(x, y, width, height);
		rectangle2.setFill(Color.BURLYWOOD);
		rectangle2.setStroke(Color.BLACK);

		// Rectangle3
		Rectangle rectangle3 = new Rectangle(x, y, width, height);
		rectangle3.setFill(Color.BISQUE);
		rectangle3.setStroke(Color.BLACK);

		Circle pivot = new Circle(pivotX, pivotY, 3);
		pivot.setFill(Color.RED);

		// Tạo phép biến hình xoay (Rotation Transformation)
		Rotate rotate = new Rotate();

		// Sét đặt góc quay (20 độ)
		rotate.setAngle(20);

		// Sét đặt điểm pivot (trục xoay) cho phép xoay hình.
		rotate.setPivotX(pivotX);
		rotate.setPivotY(pivotY);

		// Thêm phép biến hình (transformation) vào cho rectangle2.
		rectangle2.getTransforms().addAll(rotate);

		// Tạo phép biến hình dịch chuyển (Translation Transformation).
		Translate translate = new Translate(100, 150);

		// Thêm 2 phép biến hình cho rectangle3.
		rectangle3.getTransforms().addAll(rotate, translate);
 

		Group root = new Group(rectangle1, rectangle2,rectangle3, pivot);

		Scene scene = new Scene(root, 450, 500);
		stage.setTitle("JavaFX Multi Transformations (o7planning.org)");
		stage.setScene(scene);
		stage.show();
	}

	public static void main(String args[]) {
		launch(args);
	}
}

Xem thêm các chuyên mục: