1 package net.sf.openrocket.util;
6 * Defines an affine transformation of the form A*x+c, where x and c are Coordinates and
9 * The Transformations are immutable. All modification methods return a new transformation.
11 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
14 public class Transformation implements java.io.Serializable {
17 public static final Transformation IDENTITY =
20 public static final Transformation PROJECT_XY =
21 new Transformation(new double[][]{{1,0,0},{0,1,0},{0,0,0}});
22 public static final Transformation PROJECT_YZ =
23 new Transformation(new double[][]{{0,0,0},{0,1,0},{0,0,1}});
24 public static final Transformation PROJECT_XZ =
25 new Transformation(new double[][]{{1,0,0},{0,0,0},{0,0,1}});
27 private static final int X = 0;
28 private static final int Y = 1;
29 private static final int Z = 2;
31 private final Coordinate translate;
32 private final double[][] rotation = new double[3][3];
35 * Create identity transformation.
37 public Transformation() {
38 translate = new Coordinate(0,0,0);
45 * Create transformation with only translation.
46 * @param x Translation in x-axis.
47 * @param y Translation in y-axis.
48 * @param z Translation in z-axis.
50 public Transformation(double x,double y,double z) {
51 translate = new Coordinate(x,y,z);
58 * Create transformation with only translation.
59 * @param translation The translation term.
61 public Transformation(Coordinate translation) {
62 this.translate = translation;
69 * Create transformation with given rotation matrix and translation.
73 public Transformation(double[][] rotation, Coordinate translation) {
74 for (int i=0; i<3; i++)
75 for (int j=0; j<3; j++)
76 this.rotation[i][j] = rotation[i][j];
77 this.translate = translation;
82 * Create transformation with given rotation matrix and translation.
86 public Transformation(double[][] rotation) {
87 for (int i=0; i<3; i++)
88 for (int j=0; j<3; j++)
89 this.rotation[i][j] = rotation[i][j];
90 this.translate = Coordinate.NUL;
98 * Transform a coordinate according to this transformation.
100 * @param orig the coordinate to transform.
101 * @return the result.
103 public Coordinate transform(Coordinate orig) {
106 x = rotation[X][X]*orig.x + rotation[X][Y]*orig.y + rotation[X][Z]*orig.z + translate.x;
107 y = rotation[Y][X]*orig.x + rotation[Y][Y]*orig.y + rotation[Y][Z]*orig.z + translate.y;
108 z = rotation[Z][X]*orig.x + rotation[Z][Y]*orig.y + rotation[Z][Z]*orig.z + translate.z;
110 return new Coordinate(x,y,z,orig.weight);
115 * Transform an array of coordinates. The transformed coordinates are stored
116 * in the same array, and the array is returned.
118 * @param orig the coordinates to transform.
119 * @return <code>orig</code>, with the coordinates transformed.
121 public Coordinate[] transform(Coordinate[] orig) {
122 for (int i=0; i < orig.length; i++) {
123 orig[i] = transform(orig[i]);
129 * Transforms all coordinates in a Collection. The original coordinate elements are
130 * removed from the set and replaced with the transformed ones. The Collection given
131 * must implement the .clear() and .addAll() methods.
133 * @param set Collection of coordinates to transform.
135 public void transform(Collection<Coordinate> set) {
136 ArrayList<Coordinate> temp = new ArrayList<Coordinate>(set.size());
137 Iterator<Coordinate> iter = set.iterator();
138 while (iter.hasNext())
139 temp.add(this.transform(iter.next()));
145 * Applies only the linear transformation A*x
146 * @param orig Coordinate to transform.
148 public Coordinate linearTransform(Coordinate orig) {
151 x = rotation[X][X]*orig.x + rotation[X][Y]*orig.y + rotation[X][Z]*orig.z;
152 y = rotation[Y][X]*orig.x + rotation[Y][Y]*orig.y + rotation[Y][Z]*orig.z;
153 z = rotation[Z][X]*orig.x + rotation[Z][Y]*orig.y + rotation[Z][Z]*orig.z;
155 return new Coordinate(x,y,z,orig.weight);
159 * Applies the given transformation before this tranformation. The resulting
160 * transformation result.transform(c) will equal this.transform(other.transform(c)).
162 * @param other Transformation to apply
163 * @return The new transformation
165 public Transformation applyTransformation(Transformation other) {
168 // C(Ax+b)+d = CAx + Cb+d
170 // Translational portion
171 Transformation combined = new Transformation(
172 this.linearTransform(other.translate).add(this.translate)
176 for (int i=0; i<3; i++) {
181 combined.rotation[i][X] =
182 x*other.rotation[X][X] + y*other.rotation[Y][X] + z*other.rotation[Z][X];
183 combined.rotation[i][Y] =
184 x*other.rotation[X][Y] + y*other.rotation[Y][Y] + z*other.rotation[Z][Y];
185 combined.rotation[i][Z] =
186 x*other.rotation[X][Z] + y*other.rotation[Y][Z] + z*other.rotation[Z][Z];
193 * Rotate around x-axis a given angle.
194 * @param theta The angle to rotate in radians.
195 * @return The transformation.
197 public static Transformation rotate_x(double theta) {
198 return new Transformation(new double[][]{
200 {0,Math.cos(theta),-Math.sin(theta)},
201 {0,Math.sin(theta),Math.cos(theta)}});
205 * Rotate around y-axis a given angle.
206 * @param theta The angle to rotate in radians.
207 * @return The transformation.
209 public static Transformation rotate_y(double theta) {
210 return new Transformation(new double[][]{
211 {Math.cos(theta),0,Math.sin(theta)},
213 {-Math.sin(theta),0,Math.cos(theta)}});
217 * Rotate around z-axis a given angle.
218 * @param theta The angle to rotate in radians.
219 * @return The transformation.
221 public static Transformation rotate_z(double theta) {
222 return new Transformation(new double[][]{
223 {Math.cos(theta),-Math.sin(theta),0},
224 {Math.sin(theta),Math.cos(theta),0},
230 public void print(String... str) {
231 for (String s: str) {
232 System.out.println(s);
234 System.out.printf("[%3.2f %3.2f %3.2f] [%3.2f]\n",
235 rotation[X][X],rotation[X][Y],rotation[X][Z],translate.x);
236 System.out.printf("[%3.2f %3.2f %3.2f] + [%3.2f]\n",
237 rotation[Y][X],rotation[Y][Y],rotation[Y][Z],translate.y);
238 System.out.printf("[%3.2f %3.2f %3.2f] [%3.2f]\n",
239 rotation[Z][X],rotation[Z][Y],rotation[Z][Z],translate.z);
240 System.out.println();
244 public static void main(String[] arg) {
247 t = new Transformation();
249 t = new Transformation(1,2,3);
251 t = new Transformation(new Coordinate(2,3,4));
252 t.print("coord 2,3 4");
254 t = Transformation.rotate_y(0.01);
255 t.print("rotate_y 0.01");
257 t = new Transformation(-1,0,0);
258 t = t.applyTransformation(Transformation.rotate_y(0.01));
259 t = t.applyTransformation(new Transformation(1,0,0));
260 t.print("shift-rotate-shift");