In this post, we implement the Homogeneous Coordinate Transformation Matrix (HCTM) in Java. HCTM is a fundamental concept in robotics and computer graphics for representing rotation and translation of a coordinate frame in 3D space. Using a 4×4 matrix allows both rotation and translation to be combined into a single matrix multiplication, making it efficient to apply multiple transformations in sequence.
What is HCTM?
A Homogeneous Coordinate Transformation Matrix extends a standard 3D rotation matrix to 4×4 by appending a translation vector and a homogeneous row [0 0 0 1]. This program implements three rotations (Yaw around X-axis, Pitch around Y-axis, Roll around Z-axis) and one translation. Given a rotation angle (in degrees) and a 4-element coordinate frame vector, the program computes the transformed frame using matrix–vector multiplication.
Java Code Implementation
// ============================================================
// Homogeneous Coordinate Transformation Matrix (HCTM) in Java
// Supports: Yaw (X-axis), Pitch (Y-axis), Roll (Z-axis), Translation
// Input: rotation angle (degrees) + 4-element coordinate frame
// Output: transformed coordinate frame after matrix multiplication
// ============================================================
import java.io.*;
// Main class: reads user choice and delegates to rotation or translation
public class HCTM {
public static void main(String[] args) throws IOException {
BufferedReader obj = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Which operation do you want to perform?");
System.out.println("1. Rotation - Yaw (rotation about X-axis)");
System.out.println("2. Rotation - Pitch (rotation about Y-axis)");
System.out.println("3. Rotation - Roll (rotation about Z-axis)");
System.out.println("4. Translation");
int choice = Integer.parseInt(obj.readLine());
Rotation rot = new Rotation(); // Create rotation handler
switch (choice) {
case 1: rot.yaw(); break;
case 2: rot.pitch(); break;
case 3: rot.roll(); break;
case 4: new Translation(); break;
default: System.out.println("Invalid option");
}
}
}
// Rotation class: implements Yaw, Pitch, and Roll rotation matrices
class Rotation {
// Yaw: rotation about the X-axis
// Rotation matrix:
// [1, 0, 0, 0]
// [0, cos(a), -sin(a), 0]
// [0, sin(a), cos(a), 0]
// [0, 0, 0, 1]
public void yaw() throws IOException {
BufferedReader obj = new BufferedReader(new InputStreamReader(System.in));
System.out.println("\nEnter angle (degrees):");
double angleDeg = Double.parseDouble(obj.readLine());
double a = angleDeg * 3.14159265 / 180; // Convert degrees to radians
double[][] rotMatrix = {
{1, 0, 0, 0},
{0, Math.cos(a), -Math.sin(a), 0},
{0, Math.sin(a), Math.cos(a), 0},
{0, 0, 0, 1}
};
int[] frame = readFrame(obj); // Read the 4-element coordinate frame
printResult(rotMatrix, frame); // Multiply and print result
}
// Pitch: rotation about the Y-axis
// Rotation matrix:
// [ cos(a), 0, sin(a), 0]
// [ 0, 1, 0, 0]
// [-sin(a), 0, cos(a), 0]
// [ 0, 0, 0, 1]
public void pitch() throws IOException {
BufferedReader obj = new BufferedReader(new InputStreamReader(System.in));
System.out.println("\nEnter angle (degrees):");
double angleDeg = Double.parseDouble(obj.readLine());
double a = angleDeg * 3.14159265 / 180;
double[][] rotMatrix = {
{ Math.cos(a), 0, Math.sin(a), 0},
{ 0, 1, 0, 0},
{-Math.sin(a), 0, Math.cos(a), 0},
{ 0, 0, 0, 1}
};
int[] frame = readFrame(obj);
printResult(rotMatrix, frame);
}
// Roll: rotation about the Z-axis
// Rotation matrix:
// [ cos(a), -sin(a), 0, 0]
// [ sin(a), cos(a), 0, 0]
// [ 0, 0, 1, 0]
// [ 0, 0, 0, 1]
public void roll() throws IOException {
BufferedReader obj = new BufferedReader(new InputStreamReader(System.in));
System.out.println("\nEnter angle (degrees):");
double angleDeg = Double.parseDouble(obj.readLine());
double a = angleDeg * 3.14159265 / 180;
double[][] rotMatrix = {
{Math.cos(a), -Math.sin(a), 0, 0},
{Math.sin(a), Math.cos(a), 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1}
};
// Roll accepts double-precision frame values
BufferedReader obj2 = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter mobile coordinate frame (4 values, one per line):");
double[] frameD = new double[4];
for (int idx = 0; idx < 4; idx++) {
frameD[idx] = Double.parseDouble(obj2.readLine());
}
// Matrix-vector multiplication: result[i] = sum of rotMatrix[i][j] * frameD[j]
double[] result = new double[4];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
result[i] += rotMatrix[i][j] * frameD[j];
}
}
System.out.println("Answer: " + result[0] + " " + result[1] + " " + result[2] + " " + result[3]);
}
// Helper: read 4 integer frame values from stdin
private int[] readFrame(BufferedReader obj) throws IOException {
System.out.println("Enter mobile coordinate frame (4 values, one per line):");
int[] frame = new int[4];
for (int idx = 0; idx < 4; idx++) {
frame[idx] = Integer.parseInt(obj.readLine());
}
return frame;
}
// Helper: multiply 4x4 matrix by 4-element int vector and print result
private void printResult(double[][] matrix, int[] frame) {
double[] result = new double[4];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
result[i] += matrix[i][j] * frame[j];
}
}
System.out.println("Answer: " + result[0] + " " + result[1] + " " + result[2] + " " + result[3]);
}
}
// Translation class: applies a pure translation matrix
// Translation matrix:
// [1, 0, 0, tx]
// [0, 1, 0, ty]
// [0, 0, 1, tz]
// [0, 0, 0, w]
class Translation {
public Translation() throws IOException {
BufferedReader obj = new BufferedReader(new InputStreamReader(System.in));
// Read translation vector [tx, ty, tz, w]
System.out.println("Enter Transformation vector (4 values: tx, ty, tz, w):");
int[] t = new int[4];
for (int idx = 0; idx < 4; idx++) {
t[idx] = Integer.parseInt(obj.readLine());
}
// Build the 4x4 translation matrix
double[][] transMatrix = {
{1, 0, 0, t[0]},
{0, 1, 0, t[1]},
{0, 0, 1, t[2]},
{0, 0, 0, t[3]}
};
// Read the mobile coordinate frame
System.out.println("Enter mobile coordinate frame (4 values, one per line):");
int[] frame = new int[4];
for (int idx = 0; idx < 4; idx++) {
frame[idx] = Integer.parseInt(obj.readLine());
}
// Apply translation: result = transMatrix * frame
double[] result = new double[4];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
result[i] += transMatrix[i][j] * frame[j];
}
}
System.out.println("Answer: " + result[0] + " " + result[1] + " " + result[2] + " " + result[3]);
}
}
Explanation of the Code
- Menu and Dispatch — The
main()method presents a numbered menu and reads the user’s choice. Aswitchstatement delegates to the appropriate method in theRotationclass or instantiates theTranslationclass. - Rotation Matrices — Each rotation method builds a 4×4 homogeneous rotation matrix using
Math.cos()andMath.sin(). The angle is converted from degrees to radians before use. All rotation matrices include a homogeneous row[0, 0, 0, 1]so that they can be multiplied with homogeneous coordinate vectors. - Matrix–Vector Multiplication — The transformed coordinate is computed via the standard formula:
result[i] = Σ matrix[i][j] * frame[j]for j = 0..3. This is the core operation that applies the rotation or translation to the input frame. - Translation Matrix — The
Translationclass builds an identity matrix with the translation vector inserted in the last column. When multiplied with a homogeneous coordinate[x, y, z, 1], this adds the translation offsets to each axis.
Sample Input and Output
Yaw (Rotation about X-axis), Angle = 60°, Frame = [2, 0, 3, 1]
Which operation do you want to perform?
1. Rotation - Yaw (rotation about X-axis)
2. Rotation - Pitch (rotation about Y-axis)
3. Rotation - Roll (rotation about Z-axis)
4. Translation
1
Enter angle (degrees): 60
Enter mobile coordinate frame (4 values, one per line):
2
0
3
1
Answer: 2.0 -2.598 1.500 1.0
Pitch (Rotation about Y-axis), Angle = 60°, Frame = [2, 0, 3, 1]
2
Enter angle (degrees): 60
Enter mobile coordinate frame (4 values, one per line):
2
0
3
1
Answer: 3.598 0.0 -0.232 1.0
Roll (Rotation about Z-axis), Angle = 45°, Frame = [0.5, 1.5, 0.6, 1]
3
Enter angle (degrees): 45
Enter mobile coordinate frame (4 values, one per line):
0.5
1.5
0.6
1
Answer: -0.707 1.414 0.6 1.0
Translation, Vector = [3, 0, 5, 1], Frame = [0, 0, 1, 1]
4
Enter Transformation vector (4 values: tx, ty, tz, w):
3
0
5
1
Enter mobile coordinate frame (4 values, one per line):
0
0
1
1
Answer: 3.0 0.0 6.0 1.0
Step-by-Step Output Explanation
- Yaw at 60°: Rotates the frame around the X-axis by 60°. The X component (2.0) is unchanged. The Y and Z components are a linear combination of the original Y and Z values using cos(60°)=0.5 and sin(60°)≈0.866.
- Pitch at 60°: Rotates around the Y-axis. The Y component (0.0) stays zero. X and Z components combine via the pitch rotation matrix.
- Roll at 45°: Rotates around the Z-axis. The Z component (0.6) is unchanged. X and Y components rotate by 45° (cos(45°)≈0.707).
- Translation [3,0,5,1]: Adds tx=3 to X and tz=5 to Z. Starting frame [0,0,1,1] becomes [0+3, 0+0, 1+5, 1] = [3, 0, 6, 1]. The homogeneous coordinate w remains 1.
See Also
Conclusion
Homogeneous Coordinate Transformation Matrices are a cornerstone of robotics forward kinematics. By representing rotation and translation in a single 4×4 matrix, you can chain multiple transformations simply by multiplying their matrices together. This program covers the three fundamental rotation axes (Yaw/Pitch/Roll) and pure translation. The natural next step from HCTM is to chain these matrices across multiple robot links to compute the end-effector position, which is exactly what Direct Kinematics does.
No Comments yet!