1 package net.sf.openrocket.util;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Iterator;
8 * Defines an affine transformation of the form A*x+c, where x and c are Coordinates and
11 * The Transformations are immutable. All modification methods return a new transformation.
13 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
16 public class Transformation implements java.io.Serializable {
19 public static final Transformation IDENTITY =
22 public static final Transformation PROJECT_XY =
23 new Transformation(new double[][]{{1,0,0},{0,1,0},{0,0,0}});
24 public static final Transformation PROJECT_YZ =
25 new Transformation(new double[][]{{0,0,0},{0,1,0},{0,0,1}});
26 public static final Transformation PROJECT_XZ =
27 new Transformation(new double[][]{{1,0,0},{0,0,0},{0,0,1}});
29 private static final int X = 0;
30 private static final int Y = 1;
31 private static final int Z = 2;
33 private final Coordinate translate;
34 private final double[][] rotation = new double[3][3];
37 * Create identity transformation.
39 public Transformation() {
40 translate = new Coordinate(0,0,0);
47 * Create transformation with only translation.
48 * @param x Translation in x-axis.
49 * @param y Translation in y-axis.
50 * @param z Translation in z-axis.
52 public Transformation(double x,double y,double z) {
53 translate = new Coordinate(x,y,z);
60 * Create transformation with only translation.
61 * @param translation The translation term.
63 public Transformation(Coordinate translation) {
64 this.translate = translation;
71 * Create transformation with given rotation matrix and translation.
75 public Transformation(double[][] rotation, Coordinate translation) {
76 for (int i=0; i<3; i++)
77 for (int j=0; j<3; j++)
78 this.rotation[i][j] = rotation[i][j];
79 this.translate = translation;
84 * Create transformation with given rotation matrix and translation.
88 public Transformation(double[][] rotation) {
89 for (int i=0; i<3; i++)
90 for (int j=0; j<3; j++)
91 this.rotation[i][j] = rotation[i][j];
92 this.translate = Coordinate.NUL;
100 * Transform a coordinate according to this transformation.
102 * @param orig the coordinate to transform.
103 * @return the result.
105 public Coordinate transform(Coordinate orig) {
108 x = rotation[X][X]*orig.x + rotation[X][Y]*orig.y + rotation[X][Z]*orig.z + translate.x;
109 y = rotation[Y][X]*orig.x + rotation[Y][Y]*orig.y + rotation[Y][Z]*orig.z + translate.y;
110 z = rotation[Z][X]*orig.x + rotation[Z][Y]*orig.y + rotation[Z][Z]*orig.z + translate.z;
112 return new Coordinate(x,y,z,orig.weight);
117 * Transform an array of coordinates. The transformed coordinates are stored
118 * in the same array, and the array is returned.
120 * @param orig the coordinates to transform.
121 * @return <code>orig</code>, with the coordinates transformed.
123 public Coordinate[] transform(Coordinate[] orig) {
124 for (int i=0; i < orig.length; i++) {
125 orig[i] = transform(orig[i]);
131 * Transforms all coordinates in a Collection. The original coordinate elements are
132 * removed from the set and replaced with the transformed ones. The Collection given
133 * must implement the .clear() and .addAll() methods.
135 * @param set Collection of coordinates to transform.
137 public void transform(Collection<Coordinate> set) {
138 ArrayList<Coordinate> temp = new ArrayList<Coordinate>(set.size());
139 Iterator<Coordinate> iter = set.iterator();
140 while (iter.hasNext())
141 temp.add(this.transform(iter.next()));
147 * Applies only the linear transformation A*x
148 * @param orig Coordinate to transform.
150 public Coordinate linearTransform(Coordinate orig) {
153 x = rotation[X][X]*orig.x + rotation[X][Y]*orig.y + rotation[X][Z]*orig.z;
154 y = rotation[Y][X]*orig.x + rotation[Y][Y]*orig.y + rotation[Y][Z]*orig.z;
155 z = rotation[Z][X]*orig.x + rotation[Z][Y]*orig.y + rotation[Z][Z]*orig.z;
157 return new Coordinate(x,y,z,orig.weight);
161 * Applies the given transformation before this tranformation. The resulting
162 * transformation result.transform(c) will equal this.transform(other.transform(c)).
164 * @param other Transformation to apply
165 * @return The new transformation
167 public Transformation applyTransformation(Transformation other) {
170 // C(Ax+b)+d = CAx + Cb+d
172 // Translational portion
173 Transformation combined = new Transformation(
174 this.linearTransform(other.translate).add(this.translate)
178 for (int i=0; i<3; i++) {
183 combined.rotation[i][X] =
184 x*other.rotation[X][X] + y*other.rotation[Y][X] + z*other.rotation[Z][X];
185 combined.rotation[i][Y] =
186 x*other.rotation[X][Y] + y*other.rotation[Y][Y] + z*other.rotation[Z][Y];
187 combined.rotation[i][Z] =
188 x*other.rotation[X][Z] + y*other.rotation[Y][Z] + z*other.rotation[Z][Z];
195 * Rotate around x-axis a given angle.
196 * @param theta The angle to rotate in radians.
197 * @return The transformation.
199 public static Transformation rotate_x(double theta) {
200 return new Transformation(new double[][]{
202 {0,Math.cos(theta),-Math.sin(theta)},
203 {0,Math.sin(theta),Math.cos(theta)}});
207 * Rotate around y-axis a given angle.
208 * @param theta The angle to rotate in radians.
209 * @return The transformation.
211 public static Transformation rotate_y(double theta) {
212 return new Transformation(new double[][]{
213 {Math.cos(theta),0,Math.sin(theta)},
215 {-Math.sin(theta),0,Math.cos(theta)}});
219 * Rotate around z-axis a given angle.
220 * @param theta The angle to rotate in radians.
221 * @return The transformation.
223 public static Transformation rotate_z(double theta) {
224 return new Transformation(new double[][]{
225 {Math.cos(theta),-Math.sin(theta),0},
226 {Math.sin(theta),Math.cos(theta),0},
232 public void print(String... str) {
233 for (String s: str) {
234 System.out.println(s);
236 System.out.printf("[%3.2f %3.2f %3.2f] [%3.2f]\n",
237 rotation[X][X],rotation[X][Y],rotation[X][Z],translate.x);
238 System.out.printf("[%3.2f %3.2f %3.2f] + [%3.2f]\n",
239 rotation[Y][X],rotation[Y][Y],rotation[Y][Z],translate.y);
240 System.out.printf("[%3.2f %3.2f %3.2f] [%3.2f]\n",
241 rotation[Z][X],rotation[Z][Y],rotation[Z][Z],translate.z);
242 System.out.println();
247 public boolean equals(Object other) {
248 if (!(other instanceof Transformation))
250 Transformation o = (Transformation)other;
251 for (int i=0; i<3; i++) {
252 for (int j=0; j<3; j++) {
253 if (!MathUtil.equals(this.rotation[i][j], o.rotation[i][j]))
257 return this.translate.equals(o.translate);
260 public static void main(String[] arg) {
263 t = new Transformation();
265 t = new Transformation(1,2,3);
267 t = new Transformation(new Coordinate(2,3,4));
268 t.print("coord 2,3 4");
270 t = Transformation.rotate_y(0.01);
271 t.print("rotate_y 0.01");
273 t = new Transformation(-1,0,0);
274 t = t.applyTransformation(Transformation.rotate_y(0.01));
275 t = t.applyTransformation(new Transformation(1,0,0));
276 t.print("shift-rotate-shift");