View Javadoc
1   package org.newdawn.slick.geom;
2   
3   import java.io.Serializable;
4   
5   import org.newdawn.slick.util.FastTrig;
6   
7   import javax.annotation.Nonnull;
8   
9   /**
10   * A two dimensional vector
11   * 
12   * @author Kevin Glass
13   */
14  public strictfp class Vector2f implements Serializable {
15      /** The version ID for this class  */
16      private static final long serialVersionUID = 1339934L;
17  
18      /** The x component of this vector */
19      public float x;
20      /** The y component of this vector */
21      public float y;
22  
23      /**
24       * Create an empty vector
25       */
26      public Vector2f() {
27      }
28  
29      /**
30       * Create a vector based on the contents of a coordinate array
31       *
32       * @param coords The coordinates array, index 0 = x, index 1 = y
33       */
34      public Vector2f(float[] coords) {
35          x = coords[0];
36          y = coords[1];
37      }
38  
39      /**
40       * Create a new vector based on an angle
41       *
42       * @param theta The angle of the vector in degrees
43       */
44      public Vector2f(double theta) {
45          x = 1;
46          y = 0;
47          setTheta(theta);
48      }
49  
50      /**
51       * Calculate the components of the vectors based on a angle
52       *
53       * @param theta The angle to calculate the components from (in degrees)
54       */
55      void setTheta(double theta) {
56          // Next lines are to prevent numbers like -1.8369701E-16
57          // when working with negative numbers
58          if ((theta < -360) || (theta > 360)) {
59              theta = theta % 360;
60          }
61          if (theta < 0) {
62              theta = 360 + theta;
63          }
64          double oldTheta = getTheta();
65          if ((theta < -360) || (theta > 360)) {
66              oldTheta = oldTheta % 360;
67          }
68          if (theta < 0) {
69              oldTheta = 360 + oldTheta;
70          }
71  
72          float len = length();
73          x = len * (float) FastTrig.cos(StrictMath.toRadians(theta));
74          y = len * (float) FastTrig.sin(StrictMath.toRadians(theta));
75  
76  //        x = x / (float) FastTrig.cos(StrictMath.toRadians(oldTheta))
77  //                * (float) FastTrig.cos(StrictMath.toRadians(theta));
78  //        y = x / (float) FastTrig.sin(StrictMath.toRadians(oldTheta))
79  //                * (float) FastTrig.sin(StrictMath.toRadians(theta));
80      }
81  
82      /**
83       * Adjust this vector by a given angle
84       *
85       * @param theta
86       *            The angle to adjust the angle by (in degrees)
87       * @return This vector - useful for chaining operations
88       *
89       */
90      @Nonnull
91      public Vector2f add(double theta) {
92          setTheta(getTheta() + theta);
93  
94          return this;
95      }
96  
97      /**
98       * Adjust this vector by a given angle
99       *
100      * @param theta The angle to adjust the angle by (in degrees)
101      * @return This vector - useful for chaining operations
102      */
103     @Nonnull
104     public Vector2f sub(double theta) {
105         setTheta(getTheta() - theta);
106 
107         return this;
108     }
109 
110     /**
111      * Get the angle this vector is at
112      *
113      * @return The angle this vector is at (in degrees)
114      */
115     double getTheta() {
116         double theta = StrictMath.toDegrees(StrictMath.atan2(y, x));
117         if ((theta < -360) || (theta > 360)) {
118             theta = theta % 360;
119         }
120         if (theta < 0) {
121             theta = 360 + theta;
122         }
123 
124         return theta;
125     }
126 
127     /**
128      * Get the x component
129      *
130      * @return The x component
131      */
132     public float getX() {
133         return x;
134     }
135 
136     /**
137      * Get the y component
138      *
139      * @return The y component
140      */
141     public float getY() {
142         return y;
143     }
144 
145     /**
146      * Create a new vector based on another
147      *
148      * @param other The other vector to copy into this one
149      */
150     public Vector2f(@Nonnull Vector2f other) {
151         this(other.getX(),other.getY());
152     }
153 
154     /**
155      * Create a new vector
156      *
157      * @param x The x component to assign
158      * @param y The y component to assign
159      */
160     public Vector2f(float x, float y) {
161         this.x = x;
162         this.y = y;
163     }
164 
165     /**
166      * Set the value of this vector
167      *
168      * @param other The values to set into the vector
169      */
170     public void set(@Nonnull Vector2f other) {
171         set(other.getX(),other.getY());
172     }
173 
174     /**
175      * Dot this vector against another
176      *
177      * @param other The other vector dot agianst
178      * @return The dot product of the two vectors
179      */
180     public float dot(@Nonnull Vector2f other) {
181         return (x * other.getX()) + (y * other.getY());
182     }
183 
184     /**
185      * Set the values in this vector
186      *
187      * @param x The x component to set
188      * @param y The y component to set
189      * @return This vector - useful for chaining operations
190      */
191     @Nonnull
192     public Vector2f set(float x, float y) {
193         this.x = x;
194         this.y = y;
195 
196         return this;
197     }
198 
199     /**
200      * A vector perpendicular to this vector.
201      *
202      * @return a vector perpendicular to this vector
203      */
204     @Nonnull
205     public Vector2f getPerpendicular() {
206        return new Vector2f(-y, x);
207     }
208 
209     /**
210      * Set the values in this vector
211      *
212      * @param pt The pair of values to set into the vector
213      * @return This vector - useful for chaining operations
214      */
215     @Nonnull
216     public Vector2f set(float[] pt) {
217         return set(pt[0], pt[1]);
218     }
219 
220     /**
221      * Negate this vector
222      *
223      * @return A copy of this vector negated
224      */
225     @Nonnull
226     public Vector2f negate() {
227         return new Vector2f(-x, -y);
228     }
229 
230     /**
231      * Negate this vector without creating a new copy
232      *
233      * @return This vector - useful for chaning operations
234      */
235     @Nonnull
236     public Vector2f negateLocal() {
237         x = -x;
238         y = -y;
239 
240         return this;
241     }
242 
243     /**
244      * Add a vector to this vector
245      *
246      * @param v The vector to add
247      * @return This vector - useful for chaning operations
248      */
249     @Nonnull
250     public Vector2f add(@Nonnull Vector2f v)
251     {
252         x += v.getX();
253         y += v.getY();
254 
255         return this;
256     }
257 
258     /**
259      * Subtract a vector from this vector
260      *
261      * @param v The vector subtract
262      * @return This vector - useful for chaining operations
263      */
264     @Nonnull
265     public Vector2f sub(@Nonnull Vector2f v)
266     {
267         x -= v.getX();
268         y -= v.getY();
269 
270         return this;
271     }
272 
273     /**
274      * Scale this vector by a value
275      *
276      * @param a The value to scale this vector by
277      * @return This vector - useful for chaining operations
278      */
279     @Nonnull
280     public Vector2f scale(float a)
281     {
282         x *= a;
283         y *= a;
284 
285         return this;
286     }
287 
288     /**
289      * Normalise the vector
290      *
291      * @return This vector - useful for chaning operations
292      */
293     @Nonnull
294     Vector2f normalise() {
295         float l = length();
296 
297         if (l == 0) {
298             return this;
299         }
300 
301         x /= l;
302         y /= l;
303         return this;
304     }
305 
306     /**
307      * The normal of the vector
308      * 
309      * @return A unit vector with the same direction as the vector
310      */
311     @Nonnull
312     public Vector2f getNormal() {
313        Vector2f cp = copy();
314        cp.normalise();
315        return cp;
316     } 
317     
318     /**
319      * The length of the vector squared
320      *
321      * @return The length of the vector squared
322      */
323     public float lengthSquared() {
324         return (x * x) + (y * y);
325     }
326 
327     /**
328      * Get the length of this vector
329      *
330      * @return The length of this vector
331      */
332     public float length()
333     {
334         return (float) Math.sqrt(lengthSquared());
335     }
336 
337     /**
338      * Project this vector onto another
339      *
340      * @param b The vector to project onto
341      * @param result The projected vector
342      */
343     public void projectOntoUnit(@Nonnull Vector2f b, @Nonnull Vector2f result) {
344         float dp = b.dot(this);
345 
346         result.x = dp * b.getX();
347         result.y = dp * b.getY();
348 
349     }
350 
351     /**
352      * Return a copy of this vector
353      *
354      * @return The new instance that copies this vector
355      */
356     @Nonnull
357     Vector2f copy() {
358         return new Vector2f(x,y);
359     }
360 
361     /**
362      * @see java.lang.Object#toString()
363      */
364     @Nonnull
365     public String toString() {
366         return "[Vector2f "+x+","+y+" ("+length()+")]";
367     }
368 
369     /**
370      * Get the distance from this point to another
371      *
372      * @param other The other point we're measuring to
373      * @return The distance to the other point
374      */
375     public float distance(@Nonnull Vector2f other) {
376         return (float) Math.sqrt(distanceSquared(other));
377     }
378 
379     /**
380      * Get the distance from this point to another, squared. This
381      * can sometimes be used in place of distance and avoids the
382      * additional sqrt.
383      *
384      * @param other The other point we're measuring to
385      * @return The distance to the other point squared
386      */
387     float distanceSquared(@Nonnull Vector2f other) {
388         float dx = other.getX() - getX();
389         float dy = other.getY() - getY();
390 
391         return dx*dx +(dy*dy);
392     }
393 
394     /**
395      * @see java.lang.Object#hashCode()
396      */
397     public int hashCode() {
398         return 997 * ((int)x) ^ 991 * ((int)y); //large primes! 
399     }
400 
401     /**
402      * @see java.lang.Object#equals(java.lang.Object)
403      */
404     public boolean equals(Object other) {
405         if (other instanceof Vector2f) {
406             Vector2f o = ((Vector2f) other);
407             return (o.x == x) && (o.y == y);
408         }
409 
410         return false;
411     }
412 }