Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 35 additions & 27 deletions jme3-core/src/main/java/com/jme3/math/Transform.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2023 jMonkeyEngine
* Copyright (c) 2009-2025 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -31,17 +31,20 @@
*/
package com.jme3.math;

import com.jme3.export.*;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.export.Savable;
import com.jme3.util.TempVars;

import java.io.IOException;
import java.util.Locale;

/**
* A 3-D coordinate transform composed of translation, rotation, and scaling.
* The order of application is: scale, then rotate, then translate.
*
* <p>Started July 16, 2004
*
* @author Jack Lindamood
* @author Joshua Slack
*/
Expand Down Expand Up @@ -474,12 +477,14 @@ public int hashCode() {
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
if (!(obj instanceof Transform)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;

if (this == obj) {
return true;
}

final Transform other = (Transform) obj;
return this.translation.equals(other.translation)
&& this.scale.equals(other.scale)
Expand All @@ -490,19 +495,23 @@ public boolean equals(Object obj) {
* Returns a string representation of the transform, which is unaffected.
* For example, the identity transform is represented by:
* <pre>
* Transform[ 0.0, 0.0, 0.0]
* [ 0.0, 0.0, 0.0, 1.0]
* [ 1.0 , 1.0, 1.0]
* Transform[0.0, 0.0, 0.0]
* [0.0, 0.0, 0.0, 1.0]
* [1.0, 1.0, 1.0]
* </pre>
*
* @return the string representation (not null, not empty)
*/
@Override
public String toString() {
return getClass().getSimpleName()
+ "[ " + translation.x + ", " + translation.y + ", " + translation.z + "]\n"
+ "[ " + rot.x + ", " + rot.y + ", " + rot.z + ", " + rot.w + "]\n"
+ "[ " + scale.x + " , " + scale.y + ", " + scale.z + "]";
return String.format(Locale.US, "%s"
+ "[%.4f, %.4f, %.4f]%n"
+ "[%.4f, %.4f, %.4f, %.4f]%n"
+ "[%.4f, %.4f, %.4f]",
getClass().getSimpleName(),
translation.x, translation.y, translation.z,
rot.x, rot.y, rot.z, rot.w,
scale.x, scale.y, scale.z);
}

/**
Expand All @@ -522,31 +531,30 @@ public Transform set(Transform transform) {
* Serializes to the argument, for example when saving to a J3O file. The
* current instance is unaffected.
*
* @param e (not null)
* @param ex (not null)
* @throws IOException from the exporter
*/
@Override
public void write(JmeExporter e) throws IOException {
OutputCapsule capsule = e.getCapsule(this);
capsule.write(rot, "rot", Quaternion.IDENTITY);
capsule.write(translation, "translation", Vector3f.ZERO);
capsule.write(scale, "scale", Vector3f.UNIT_XYZ);
public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this);
oc.write(rot, "rot", Quaternion.IDENTITY);
oc.write(translation, "translation", Vector3f.ZERO);
oc.write(scale, "scale", Vector3f.UNIT_XYZ);
}

/**
* De-serializes from the argument, for example when loading from a J3O
* file.
*
* @param importer (not null)
* @param im (not null)
* @throws IOException from the importer
*/
@Override
public void read(JmeImporter importer) throws IOException {
InputCapsule capsule = importer.getCapsule(this);

rot.set((Quaternion) capsule.readSavable("rot", Quaternion.IDENTITY));
translation.set((Vector3f) capsule.readSavable("translation", Vector3f.ZERO));
scale.set((Vector3f) capsule.readSavable("scale", Vector3f.UNIT_XYZ));
public void read(JmeImporter im) throws IOException {
InputCapsule ic = im.getCapsule(this);
rot.set((Quaternion) ic.readSavable("rot", Quaternion.IDENTITY));
translation.set((Vector3f) ic.readSavable("translation", Vector3f.ZERO));
scale.set((Vector3f) ic.readSavable("scale", Vector3f.UNIT_XYZ));
}

/**
Expand Down
24 changes: 20 additions & 4 deletions jme3-core/src/test/java/com/jme3/math/TestTransform.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 jMonkeyEngine
* Copyright (c) 2009-2025 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -59,15 +59,31 @@ public void testTransformToString() {
* Verify that the result matches the javadoc
* and can be parsed using a regular expression.
*/
// --- Regex for matching the generated string ---
// Use \\R for platform-independent newline
Pattern pattern = Pattern.compile(
"^Transform\\[ (\\S+), (\\S+), (\\S+)\\]\\n"
+ "\\[ (\\S+), (\\S+), (\\S+), (\\S+)\\]\\n"
+ "\\[ (\\S+) , (\\S+), (\\S+)\\]$"
"^Transform\\[(\\S+), (\\S+), (\\S+)\\]\\R"
+ "\\[(\\S+), (\\S+), (\\S+), (\\S+)\\]\\R"
+ "\\[(\\S+), (\\S+), (\\S+)\\]$"
);

Matcher matcher = pattern.matcher(result);
boolean valid = matcher.matches();
Assert.assertTrue(valid);

// if (valid) {
// System.out.println("Group 1 (Translation X): " + matcher.group(1));
// System.out.println("Group 2 (Translation Y): " + matcher.group(2));
// System.out.println("Group 3 (Translation Z): " + matcher.group(3));
// System.out.println("Group 4 (Rotation X): " + matcher.group(4));
// System.out.println("Group 5 (Rotation Y): " + matcher.group(5));
// System.out.println("Group 6 (Rotation Z): " + matcher.group(6));
// System.out.println("Group 7 (Rotation W): " + matcher.group(7));
// System.out.println("Group 8 (Scale X): " + matcher.group(8));
// System.out.println("Group 9 (Scale Y): " + matcher.group(9));
// System.out.println("Group 10 (Scale Z): " + matcher.group(10));
// }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to commit this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I left them on purpose. The legend of the indices of the "groups" makes the test easier to understand; otherwise, it is difficult to understand the choice of those used later.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how they help with that. They seem like bits of commented out code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have replaced the bits of code with clearer comments. I hope you feel more confident now.

String txText = matcher.group(1);
float tx = Float.parseFloat(txText);
Assert.assertEquals(12f, tx, 1e-5f);
Expand Down