View Javadoc
1   package org.newdawn.slick.geom;
2   
3   import org.newdawn.slick.util.FastTrig;
4   
5   import javax.annotation.Nonnull;
6   
7   /**   
8    * A 2 dimensional transformation that can be applied to <code>Shape</code> implemenations.   
9    *    
10   * @author Mark   
11   */   
12  public class Transform {   
13      /**   
14       * Value for each position in the matrix   
15       *    
16       * |0 1 2|   
17       * |3 4 5|   
18       * |6 7 8|   
19       */   
20      private float matrixPosition[];   
21     
22      /**   
23       * Create and identity transform   
24       *   
25       */   
26      public Transform() {   
27          matrixPosition = new float[]{1, 0, 0, 0, 1, 0, 0, 0, 1};   
28      }   
29      
30      /**   
31       * Copy a transform
32       * 
33       * @param other The other transform to copy
34       */
35      private Transform(@Nonnull Transform other) {
36          matrixPosition = new float[9];
37          System.arraycopy(other.matrixPosition, 0, matrixPosition, 0, 9);
38      }   
39         
40      /**
41       * Concatanate to transform into one
42       * 
43       * @param t1 The first transform to join
44       * @param t2 The second transform to join
45       */
46      public Transform(@Nonnull Transform t1, @Nonnull Transform t2) {
47          this(t1);
48          concatenate(t2);
49      }
50      
51      /**   
52       * Create a transform for the given positions   
53       *    
54       * @param matrixPosition An array of float[6] to set up a transform   
55       * @throws RuntimeException if the array is not of length 6   
56       */   
57      public Transform(@Nonnull float matrixPosition[]) {
58          if(matrixPosition.length != 6) {   
59              throw new RuntimeException("The parameter must be a float array of length 6.");   
60          }   
61          this.matrixPosition = new float[]{matrixPosition[0], matrixPosition[1], matrixPosition[2],    
62                  matrixPosition[3], matrixPosition[4], matrixPosition[5],    
63                  0, 0, 1};   
64      }   
65         
66      /**   
67       * Create a transform for the given positions   
68       *    
69       * @param point00 float for the first position   
70       * @param point01 float for the second position   
71       * @param point02 float for the third position   
72       * @param point10 float for the fourth position   
73       * @param point11 float for the fifth position   
74       * @param point12 float for the sixth position   
75       */
76      private Transform(float point00, float point01, float point02, float point10, float point11, float point12) {
77          matrixPosition = new float[]{point00, point01, point02, point10, point11, point12, 0, 0, 1};   
78      }   
79         
80      /**   
81       * Transform the point pairs in the source array and store them in the destination array.   
82       * All operations will be done before storing the results in the destination.  This way the source   
83       * and destination array can be the same without worry of overwriting information before it is transformed.   
84       *    
85       * @param source Array of floats containing the points to be transformed   
86       * @param sourceOffset Where in the array to start processing   
87       * @param destination Array of floats to store the results.   
88       * @param destOffset Where in the array to start storing   
89       * @param numberOfPoints Number of points to be transformed   
90       * @throws ArrayIndexOutOfBoundsException if sourceOffset + numberOfPoints * 2 > source.length or the same operation on the destination array   
91       */   
92      public void transform(float source[], int sourceOffset, float destination[], int destOffset, int numberOfPoints) {   
93          //TODO performance can be improved by removing the safety to the destination array   
94          float result[] = source == destination ? new float[numberOfPoints * 2] : destination;
95             
96          for(int i=0;i<numberOfPoints * 2;i+=2) {   
97              for(int j=0;j<6;j+=3) {   
98                  result[i + (j / 3)] = source[i + sourceOffset] * matrixPosition[j] + source[i + sourceOffset + 1] * matrixPosition[j + 1] + 1 * matrixPosition[j + 2];   
99              }   
100         }   
101         
102         if (source == destination) {
103             //for safety of the destination, the results are copied after the entire operation.
104             for(int i=0;i<numberOfPoints * 2;i+=2) {
105                 destination[i + destOffset] = result[i];
106                 destination[i + destOffset + 1] = result[i + 1];
107             }
108         }
109     }   
110        
111     /**   
112      * Update this Transform by concatenating the given Transform to this one.   
113      *    
114      * @param tx The Transfrom to concatenate to this one.   
115      * @return The resulting Transform   
116      */   
117     @Nonnull
118     Transform concatenate(@Nonnull Transform tx) {
119         float[] mp = new float[9];
120         float n00 = matrixPosition[0] * tx.matrixPosition[0] + matrixPosition[1] * tx.matrixPosition[3];
121         float n01 = matrixPosition[0] * tx.matrixPosition[1] + matrixPosition[1] * tx.matrixPosition[4];
122         float n02 = matrixPosition[0] * tx.matrixPosition[2] + matrixPosition[1] * tx.matrixPosition[5] + matrixPosition[2];
123         float n10 = matrixPosition[3] * tx.matrixPosition[0] + matrixPosition[4] * tx.matrixPosition[3];
124         float n11 = matrixPosition[3] * tx.matrixPosition[1] + matrixPosition[4] * tx.matrixPosition[4];
125         float n12 = matrixPosition[3] * tx.matrixPosition[2] + matrixPosition[4] * tx.matrixPosition[5] + matrixPosition[5];
126         mp[0] = n00;
127         mp[1] = n01;
128         mp[2] = n02;
129         mp[3] = n10;
130         mp[4] = n11;
131         mp[5] = n12;
132 //
133 //        mp[0] = matrixPosition[0] * transform.matrixPosition[0] + matrixPosition[0] * transform.matrixPosition[3] + matrixPosition[0] * transform.matrixPosition[6]; 
134 //        mp[1] = matrixPosition[1] * transform.matrixPosition[1] + matrixPosition[1] * transform.matrixPosition[4] + matrixPosition[1] * transform.matrixPosition[7];
135 //        mp[2] = matrixPosition[2] * transform.matrixPosition[2] + matrixPosition[2] * transform.matrixPosition[5] + matrixPosition[2] * transform.matrixPosition[8]; 
136 //        mp[3] = matrixPosition[3] * transform.matrixPosition[0] + matrixPosition[3] * transform.matrixPosition[3] + matrixPosition[3] * transform.matrixPosition[6]; 
137 //        mp[4] = matrixPosition[4] * transform.matrixPosition[1] + matrixPosition[4] * transform.matrixPosition[4] + matrixPosition[4] * transform.matrixPosition[7];
138 //        mp[5] = matrixPosition[5] * transform.matrixPosition[2] + matrixPosition[5] * transform.matrixPosition[5] + matrixPosition[5] * transform.matrixPosition[8]; 
139 //        
140         matrixPosition = mp;
141         return this;
142     }   
143    
144        
145     /**   
146      * Convert this Transform to a String.   
147      *    
148      * @return This Transform in human readable format.   
149      */   
150     @Nonnull
151     public String toString() {
152         String result = "Transform[[" + matrixPosition[0] + "," + matrixPosition[1] + "," + matrixPosition[2] +    
153         "][" + matrixPosition[3] + "," + matrixPosition[4] + "," + matrixPosition[5] + 
154         "][" + matrixPosition[6] + "," + matrixPosition[7] + "," + matrixPosition[8] + "]]";   
155            
156         return result;
157     }   
158    
159     /**   
160      * Get an array representing this Transform.   
161      *    
162      * @return an array representing this Transform.    
163      */   
164     public float[] getMatrixPosition() {   
165         return matrixPosition;   
166     }   
167        
168     /**   
169      * Create a new rotation Transform   
170      *    
171      * @param angle The angle in radians to set the transform.   
172      * @return The resulting Transform   
173      */   
174     @Nonnull
175     private static Transform createRotateTransform(float angle) {
176         return new Transform((float)FastTrig.cos(angle), -(float)FastTrig.sin(angle), 0, (float)FastTrig.sin(angle), (float)FastTrig.cos(angle), 0);   
177     }   
178        
179     /**   
180      * Create a new rotation Transform around the specified point   
181      *    
182      * @param angle The angle in radians to set the transform.   
183      * @param x The x coordinate around which to rotate.   
184      * @param y The y coordinate around which to rotate.   
185      * @return The resulting Transform   
186      */   
187     @Nonnull
188     public static Transform createRotateTransform(float angle, float x, float y) {
189         Transform temp = Transform.createRotateTransform(angle);
190         float sinAngle = temp.matrixPosition[3];
191         float oneMinusCosAngle = 1.0f - temp.matrixPosition[4];
192         temp.matrixPosition[2] = x * oneMinusCosAngle + y * sinAngle;
193         temp.matrixPosition[5] = y * oneMinusCosAngle - x * sinAngle;
194 
195         return temp;   
196     }   
197        
198     /**   
199      * Create a new translation Transform   
200      *    
201      * @param xOffset The amount to move in the x direction   
202      * @param yOffset The amount to move in the y direction   
203      * @return The resulting Transform   
204      */   
205     @Nonnull
206     public static Transform createTranslateTransform(float xOffset, float yOffset) {
207         return new Transform(1, 0, xOffset, 0, 1, yOffset);   
208     }   
209        
210     /**   
211      * Create an new scaling Transform   
212      *    
213      * @param xScale The amount to scale in the x coordinate   
214      * @param yScale The amount to scale in the x coordinate   
215      * @return The resulting Transform   
216      */   
217     @Nonnull
218     public static Transform createScaleTransform(float xScale, float yScale) {
219         return new Transform(xScale, 0, 0, 0, yScale, 0);   
220     }
221     
222     /**
223      * Transform the vector2f based on the matrix defined in this transform
224      * 
225      * @param pt The point to be transformed
226      * @return The resulting point transformed by this matrix
227      */
228     @Nonnull
229     public Vector2f transform(@Nonnull Vector2f pt) {
230         float[] in = new float[] {pt.x, pt.y};
231         float[] out = new float[2];
232 
233         transform(in, 0, out, 0, 1);
234 
235         return new Vector2f(out[0], out[1]);
236     }
237 }