diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/Axis.java b/core/src/net/sf/openrocket/file/wavefrontobj/Axis.java index 519278d02..4a57431da 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/Axis.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/Axis.java @@ -4,10 +4,46 @@ package net.sf.openrocket.file.wavefrontobj; * Representation of an axis in 3D space. */ public enum Axis { - X, - X_MIN, // Negative x - Y, - Y_MIN, // Negative y - Z, - Z_MIN // Negative z + X ("X"), + X_MIN ("-X"), + Y ("Y"), + Y_MIN ("-Y"), + Z ("Z"), + Z_MIN ("-Z"); + + private final String label; + + Axis(String label) { + this.label = label; + } + + @Override + public String toString() { + return label; + } + + public static Axis fromString(String label) { + for (Axis axis : values()) { + if (axis.label.equals(label)) { + return axis; + } + } + throw new IllegalArgumentException("Unknown axis: " + label); + } + + public boolean isSameAxis(Axis other) { + return this == other || this == getOppositeAxis(other); + } + + public static Axis getOppositeAxis(Axis axis) { + return switch (axis) { + case X -> X_MIN; + case X_MIN -> X; + case Y -> Y_MIN; + case Y_MIN -> Y; + case Z -> Z_MIN; + case Z_MIN -> Z; + default -> throw new IllegalArgumentException("Unknown axis: " + axis); + }; + } } diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/CoordTransform.java b/core/src/net/sf/openrocket/file/wavefrontobj/CoordTransform.java index 3472c71cc..762122046 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/CoordTransform.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/CoordTransform.java @@ -1,5 +1,6 @@ package net.sf.openrocket.file.wavefrontobj; +import com.sun.istack.NotNull; import de.javagl.obj.FloatTuple; import net.sf.openrocket.util.Coordinate; @@ -11,7 +12,73 @@ import net.sf.openrocket.util.Coordinate; * * @author Sibo Van Gool */ -public interface CoordTransform { +public class CoordTransform { + // OpenRocket coordinate system axes mapping + protected final Axis xAxis; + protected final Axis yAxis; + protected final Axis zAxis; + protected final Axis axialAxis; + + // Origin offsets + protected final double origXOffs; + protected final double origYOffs; + protected final double origZOffs; + + /** + * Create a new coordinate system converter. + * @param xAxis the OpenRocket axis that corresponds to the transformed x-axis + * @param yAxis the OpenRocket axis that corresponds to the transformed y-axis + * @param zAxis the OpenRocket axis that corresponds to the transformed z-axis + * Example: you want the transformed coordinate system to have the z-axis as the longitudinal axis (= OpenRocket x-axis) + * and want its direction to be from the bottom of the rocket to the tip of the rocket (opposite direction + * of the OpenRocket x-axis), then you must pass Axis.X_MIN as the xAxis parameter. + * You must also add an offset to the origin of the transformed coordinate system, so that it starts + * at the bottom of the rocket => set origZOffs to the length of the rocket. + * @param axialAxis the axial/longitudinal axis in the transformed coordinate system, with the direction + * relative to the OpenRocket x-axis !! + * From the previous example, the longitudinal axis would be Axis.Z_MIN. + * @param origXOffs the x-offset of the origin of the OBJ coordinate system, in the OpenRocket coordinate system + * @param origYOffs the y-offset of the origin of the OBJ coordinate system, in the OpenRocket coordinate system + * @param origZOffs the z-offset of the origin of the OBJ coordinate system, in the OpenRocket coordinate system + */ + public CoordTransform(@NotNull Axis xAxis, @NotNull Axis yAxis, @NotNull Axis zAxis, @NotNull Axis axialAxis, + double origXOffs, double origYOffs, double origZOffs) { + if (xAxis == null || yAxis == null || zAxis == null || axialAxis == null) { + throw new IllegalArgumentException("Axes cannot be null"); + } + + if (xAxis.isSameAxis(yAxis) || xAxis.isSameAxis(zAxis) || yAxis.isSameAxis(zAxis)) { + throw new IllegalArgumentException("Axes must be different"); + } + + this.xAxis = xAxis; + this.yAxis = yAxis; + this.zAxis = zAxis; + this.axialAxis = axialAxis; + + this.origXOffs = origXOffs; + this.origYOffs = origYOffs; + this.origZOffs = origZOffs; + } + + + private FloatTuple convertLoc(double x, double y, double z, + double origXOffs, double origYOffs, double origZOffs) { + final double xTrans = getTransformedCoordinate(xAxis, x, y, z); + final double yTrans = getTransformedCoordinate(yAxis, x, y, z); + final double zTrans = getTransformedCoordinate(zAxis, x, y, z); + + final double origXTrans = getTransformedOriginOffset(xAxis, origXOffs, origYOffs, origZOffs); + final double origYTrans = getTransformedOriginOffset(yAxis, origXOffs, origYOffs, origZOffs); + final double origZTrans = getTransformedOriginOffset(zAxis, origXOffs, origYOffs, origZOffs); + + return new DefaultFloatTuple( + (float) (xTrans + origXTrans), + (float) (yTrans + origYTrans), + (float) (zTrans + origZTrans) + ); + } + /** * Converts the location coordinates from OpenRocket to OBJ coordinates. * The returned coordinates will also be shifted towards the origin of the OBJ coordinate system. @@ -22,7 +89,9 @@ public interface CoordTransform { * @param z OpenRocket z-coordinate * @return the location coordinates in OBJ coordinates */ - FloatTuple convertLoc(double x, double y, double z); + public FloatTuple convertLoc(double x, double y, double z) { + return convertLoc(x, y, z, origXOffs, origYOffs, origZOffs); + } /** * Converts the location coordinates from OpenRocket to OBJ coordinates. @@ -32,7 +101,9 @@ public interface CoordTransform { * @param coordinate OpenRocket coordinate * @return the location coordinates in OBJ coordinates */ - FloatTuple convertLoc(Coordinate coordinate); + public FloatTuple convertLoc(Coordinate coordinate) { + return convertLoc(coordinate.x, coordinate.y, coordinate.z); + } /** * Converts the location coordinates from OpenRocket to OBJ coordinates, without the offset of the origin. @@ -49,16 +120,24 @@ public interface CoordTransform { * @param z OpenRocket z-coordinate * @return the location coordinates in OBJ coordinates, with the origin set to the OpenRocket origin (the tip of the rocket) */ - FloatTuple convertLocWithoutOriginOffs(double x, double y, double z); + public FloatTuple convertLocWithoutOriginOffs(double x, double y, double z) { + return convertLoc(x, y, z, 0, 0, 0); + } /** * Converts the rotation coordinates from OpenRocket to OBJ coordinates. - * @param x OpenRocket rotation in radians around the x-axis - * @param y OpenRocket rotation in radians around the y-axis - * @param z OpenRocket rotation in radians around the z-axis + * @param xRot OpenRocket rotation in radians around the x-axis + * @param yRot OpenRocket rotation in radians around the y-axis + * @param zRot OpenRocket rotation in radians around the z-axis * @return the rotation coordinates in OBJ coordinates */ - FloatTuple convertRot(double x, double y, double z); + public FloatTuple convertRot(double xRot, double yRot, double zRot) { + final double xRotTrans = getTransformedRotation(xAxis, xRot, yRot, zRot); + final double yRotTrans = getTransformedRotation(yAxis, xRot, yRot, zRot); + final double zRotTrans = getTransformedRotation(zAxis, xRot, yRot, zRot); + + return new DefaultFloatTuple((float) xRotTrans, (float) yRotTrans, (float) zRotTrans); + } /** * Returns the equivalent axis for the x-axis in the OpenRocket coordinate system (axial axis). @@ -67,5 +146,62 @@ public interface CoordTransform { * must return Axis.Z_MIN. * @return the equivalent axis for the x-axis in the OpenRocket coordinate system (axial axis) */ - Axis getAxialAxis(); + public Axis getAxialAxis() { + return axialAxis; + } + + /** + * Returns the transformed coordinate for the given axis. + * @param axis the OpenRocket axis to transform + * @param x the x-coordinate in the OpenRocket coordinate system + * @param y the y-coordinate in the OpenRocket coordinate system + * @param z the z-coordinate in the OpenRocket coordinate system + * @return the coordinate in the transformed OBJ coordinate system + */ + private double getTransformedCoordinate(Axis axis, double x, double y, double z) { + return switch (axis) { + case X -> x; + case X_MIN -> -x; + case Y -> y; + case Y_MIN -> -y; + case Z -> z; + case Z_MIN -> -z; + default -> throw new IllegalStateException("Unknown axis"); + }; + } + + /** + * Returns the offset of the origin of the OBJ coordinate system for the given axis. + * @param axis the axis to get the offset for + * @return the offset of the origin of the OBJ coordinate system for the given axis + */ + private double getTransformedOriginOffset(Axis axis, double origXOffs, double origYOffs, double origZOffs) { + return switch (axis) { + case X, X_MIN -> origXOffs; + case Y, Y_MIN -> origYOffs; + case Z, Z_MIN -> origZOffs; + default -> throw new IllegalStateException("Unknown axis"); + }; + } + + /** + * Returns the transformed rotation for the given axis. + * @param axis the OpenRocket axis to transform + * @param rotX the rotation in radians around the OpenRocket x-axis + * @param rotY the rotation in radians around the OpenRocket y-axis + * @param rotZ the rotation in radians around the OpenRocket z-axis + * @return the rotation in radians around the transformed OBJ axis + */ + private double getTransformedRotation(Axis axis, double rotX, double rotY, double rotZ) { + // OpenRocket uses left-handed coordinate system, we'll use right-handed + return switch (axis) { + case X -> -rotX; + case X_MIN -> rotX; + case Y -> -rotY; + case Y_MIN -> rotY; + case Z -> -rotZ; + case Z_MIN -> rotZ; + default -> throw new IllegalStateException("Unknown axis"); + }; + } } diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/DefaultCoordTransform.java b/core/src/net/sf/openrocket/file/wavefrontobj/DefaultCoordTransform.java index 78e4fd0ab..8055b1836 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/DefaultCoordTransform.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/DefaultCoordTransform.java @@ -1,8 +1,5 @@ package net.sf.openrocket.file.wavefrontobj; -import de.javagl.obj.FloatTuple; -import net.sf.openrocket.util.Coordinate; - /** * Default OpenRocket coordinate system to OBJ coordinate system converter. * OpenRocket uses a left-handed coordinate system with the y-axis pointing up, the z-axis pointing away from the viewer, @@ -12,59 +9,8 @@ import net.sf.openrocket.util.Coordinate; * - side view is in the z-x plane, with the x-axis pointing up * - y-axis is pointing away from the viewer */ -public class DefaultCoordTransform implements CoordTransform { - private final double rocketLength; - +public class DefaultCoordTransform extends CoordTransform { public DefaultCoordTransform(double rocketLength) { - this.rocketLength = rocketLength; - } - - /** - * Converts the location coordinates from OpenRocket to OBJ coordinates. - * @param x OpenRocket x-coordinate (! careful, when translating the component location, some components need an extra - * offset here, such as the component length !) - * @param y OpenRocket y-coordinate - * @param z OpenRocket z-coordinate - * @return the location coordinates in OBJ coordinates - */ - @Override - public FloatTuple convertLoc(double x, double y, double z) { - return convertLocToOBJCoord(x, y, z, this.rocketLength, 0, 0); - } - - @Override - public FloatTuple convertLoc(Coordinate coordinate) { - return convertLocToOBJCoord(coordinate.x, coordinate.y, coordinate.z, this.rocketLength, 0, 0); - } - - /** - * Converts the location coordinates from OpenRocket to OBJ coordinates, with the offset of the origin. - * @param x OpenRocket x-coordinate - * @param y OpenRocket y-coordinate - * @param z OpenRocket z-coordinate - * @param origXOffs the x-offset of the origin of the OBJ coordinate system, in the OpenRocket coordinate system - * @param origYOffs the y-offset of the origin of the OBJ coordinate system, in the OpenRocket coordinate system - * @param origZOffs the z-offset of the origin of the OBJ coordinate system, in the OpenRocket coordinate system - * @return the location coordinates in OBJ coordinates - */ - private FloatTuple convertLocToOBJCoord(double x, double y, double z, - double origXOffs, double origYOffs, double origZOffs) { - return new DefaultFloatTuple((float) (y + origYOffs), (float) (z + origZOffs), (float) (origXOffs - x)); - } - - @Override - public FloatTuple convertLocWithoutOriginOffs(double x, double y, double z) { - return convertLocToOBJCoord(x, y, z, 0, 0, 0); - } - - @Override - public FloatTuple convertRot(double x, double y, double z) { - // OpenRocket uses left-handed rotations, we need right-handed - return new DefaultFloatTuple((float) -y, (float) -z, (float) x); - } - - @Override - public Axis getAxialAxis() { - return Axis.Z_MIN; + super(Axis.Y, Axis.Z, Axis.X_MIN, Axis.Z_MIN, 0, 0, rocketLength); } }