1 /* 2 * Copyright (c) 2009-2010 jMonkeyEngine 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 package com.jme3.math; 34 35 import com.jme3.export.*; 36 import java.io.Externalizable; 37 import java.io.IOException; 38 import java.io.ObjectInput; 39 import java.io.ObjectOutput; 40 import java.util.logging.Logger; 41 42 /** 43 * <code>Vector2f</code> defines a Vector for a two float value vector. 44 * 45 * @author Mark Powell 46 * @author Joshua Slack 47 */ 48 public final class Vector2f implements Savable, Cloneable, java.io.Serializable { 49 50 static final long serialVersionUID = 1; 51 private static final Logger logger = Logger.getLogger(Vector2f.class.getName()); 52 53 public static final Vector2f ZERO = new Vector2f(0f, 0f); 54 public static final Vector2f UNIT_XY = new Vector2f(1f, 1f); 55 56 /** 57 * the x value of the vector. 58 */ 59 public float x; 60 /** 61 * the y value of the vector. 62 */ 63 public float y; 64 65 /** 66 * Creates a Vector2f with the given initial x and y values. 67 * 68 * @param x 69 * The x value of this Vector2f. 70 * @param y 71 * The y value of this Vector2f. 72 */ 73 public Vector2f(float x, float y) { 74 this.x = x; 75 this.y = y; 76 } 77 78 /** 79 * Creates a Vector2f with x and y set to 0. Equivalent to Vector2f(0,0). 80 */ 81 public Vector2f() { 82 x = y = 0; 83 } 84 85 /** 86 * Creates a new Vector2f that contains the passed vector's information 87 * 88 * @param vector2f 89 * The vector to copy 90 */ 91 public Vector2f(Vector2f vector2f) { 92 this.x = vector2f.x; 93 this.y = vector2f.y; 94 } 95 96 /** 97 * set the x and y values of the vector 98 * 99 * @param x 100 * the x value of the vector. 101 * @param y 102 * the y value of the vector. 103 * @return this vector 104 */ 105 public Vector2f set(float x, float y) { 106 this.x = x; 107 this.y = y; 108 return this; 109 } 110 111 /** 112 * set the x and y values of the vector from another vector 113 * 114 * @param vec 115 * the vector to copy from 116 * @return this vector 117 */ 118 public Vector2f set(Vector2f vec) { 119 this.x = vec.x; 120 this.y = vec.y; 121 return this; 122 } 123 124 /** 125 * <code>add</code> adds a provided vector to this vector creating a 126 * resultant vector which is returned. If the provided vector is null, null 127 * is returned. 128 * 129 * @param vec 130 * the vector to add to this. 131 * @return the resultant vector. 132 */ 133 public Vector2f add(Vector2f vec) { 134 if (null == vec) { 135 logger.warning("Provided vector is null, null returned."); 136 return null; 137 } 138 return new Vector2f(x + vec.x, y + vec.y); 139 } 140 141 /** 142 * <code>addLocal</code> adds a provided vector to this vector internally, 143 * and returns a handle to this vector for easy chaining of calls. If the 144 * provided vector is null, null is returned. 145 * 146 * @param vec 147 * the vector to add to this vector. 148 * @return this 149 */ 150 public Vector2f addLocal(Vector2f vec) { 151 if (null == vec) { 152 logger.warning("Provided vector is null, null returned."); 153 return null; 154 } 155 x += vec.x; 156 y += vec.y; 157 return this; 158 } 159 160 /** 161 * <code>addLocal</code> adds the provided values to this vector 162 * internally, and returns a handle to this vector for easy chaining of 163 * calls. 164 * 165 * @param addX 166 * value to add to x 167 * @param addY 168 * value to add to y 169 * @return this 170 */ 171 public Vector2f addLocal(float addX, float addY) { 172 x += addX; 173 y += addY; 174 return this; 175 } 176 177 /** 178 * <code>add</code> adds this vector by <code>vec</code> and stores the 179 * result in <code>result</code>. 180 * 181 * @param vec 182 * The vector to add. 183 * @param result 184 * The vector to store the result in. 185 * @return The result vector, after adding. 186 */ 187 public Vector2f add(Vector2f vec, Vector2f result) { 188 if (null == vec) { 189 logger.warning("Provided vector is null, null returned."); 190 return null; 191 } 192 if (result == null) 193 result = new Vector2f(); 194 result.x = x + vec.x; 195 result.y = y + vec.y; 196 return result; 197 } 198 199 /** 200 * <code>dot</code> calculates the dot product of this vector with a 201 * provided vector. If the provided vector is null, 0 is returned. 202 * 203 * @param vec 204 * the vector to dot with this vector. 205 * @return the resultant dot product of this vector and a given vector. 206 */ 207 public float dot(Vector2f vec) { 208 if (null == vec) { 209 logger.warning("Provided vector is null, 0 returned."); 210 return 0; 211 } 212 return x * vec.x + y * vec.y; 213 } 214 215 /** 216 * <code>cross</code> calculates the cross product of this vector with a 217 * parameter vector v. 218 * 219 * @param v 220 * the vector to take the cross product of with this. 221 * @return the cross product vector. 222 */ 223 public Vector3f cross(Vector2f v) { 224 return new Vector3f(0, 0, determinant(v)); 225 } 226 227 public float determinant(Vector2f v) { 228 return (x * v.y) - (y * v.x); 229 } 230 231 /** 232 * Sets this vector to the interpolation by changeAmnt from this to the 233 * finalVec this=(1-changeAmnt)*this + changeAmnt * finalVec 234 * 235 * @param finalVec 236 * The final vector to interpolate towards 237 * @param changeAmnt 238 * An amount between 0.0 - 1.0 representing a percentage change 239 * from this towards finalVec 240 */ 241 public Vector2f interpolate(Vector2f finalVec, float changeAmnt) { 242 this.x = (1 - changeAmnt) * this.x + changeAmnt * finalVec.x; 243 this.y = (1 - changeAmnt) * this.y + changeAmnt * finalVec.y; 244 return this; 245 } 246 247 /** 248 * Sets this vector to the interpolation by changeAmnt from beginVec to 249 * finalVec this=(1-changeAmnt)*beginVec + changeAmnt * finalVec 250 * 251 * @param beginVec 252 * The begining vector (delta=0) 253 * @param finalVec 254 * The final vector to interpolate towards (delta=1) 255 * @param changeAmnt 256 * An amount between 0.0 - 1.0 representing a precentage change 257 * from beginVec towards finalVec 258 */ 259 public Vector2f interpolate(Vector2f beginVec, Vector2f finalVec, 260 float changeAmnt) { 261 this.x = (1 - changeAmnt) * beginVec.x + changeAmnt * finalVec.x; 262 this.y = (1 - changeAmnt) * beginVec.y + changeAmnt * finalVec.y; 263 return this; 264 } 265 266 /** 267 * Check a vector... if it is null or its floats are NaN or infinite, return 268 * false. Else return true. 269 * 270 * @param vector 271 * the vector to check 272 * @return true or false as stated above. 273 */ 274 public static boolean isValidVector(Vector2f vector) { 275 if (vector == null) return false; 276 if (Float.isNaN(vector.x) || 277 Float.isNaN(vector.y)) return false; 278 if (Float.isInfinite(vector.x) || 279 Float.isInfinite(vector.y)) return false; 280 return true; 281 } 282 283 /** 284 * <code>length</code> calculates the magnitude of this vector. 285 * 286 * @return the length or magnitude of the vector. 287 */ 288 public float length() { 289 return FastMath.sqrt(lengthSquared()); 290 } 291 292 /** 293 * <code>lengthSquared</code> calculates the squared value of the 294 * magnitude of the vector. 295 * 296 * @return the magnitude squared of the vector. 297 */ 298 public float lengthSquared() { 299 return x * x + y * y; 300 } 301 302 /** 303 * <code>distanceSquared</code> calculates the distance squared between 304 * this vector and vector v. 305 * 306 * @param v the second vector to determine the distance squared. 307 * @return the distance squared between the two vectors. 308 */ 309 public float distanceSquared(Vector2f v) { 310 double dx = x - v.x; 311 double dy = y - v.y; 312 return (float) (dx * dx + dy * dy); 313 } 314 315 /** 316 * <code>distanceSquared</code> calculates the distance squared between 317 * this vector and vector v. 318 * 319 * @param otherX The X coordinate of the v vector 320 * @param otherY The Y coordinate of the v vector 321 * @return the distance squared between the two vectors. 322 */ 323 public float distanceSquared(float otherX, float otherY) { 324 double dx = x - otherX; 325 double dy = y - otherY; 326 return (float) (dx * dx + dy * dy); 327 } 328 329 /** 330 * <code>distance</code> calculates the distance between this vector and 331 * vector v. 332 * 333 * @param v the second vector to determine the distance. 334 * @return the distance between the two vectors. 335 */ 336 public float distance(Vector2f v) { 337 return FastMath.sqrt(distanceSquared(v)); 338 } 339 340 /** 341 * <code>mult</code> multiplies this vector by a scalar. The resultant 342 * vector is returned. 343 * 344 * @param scalar 345 * the value to multiply this vector by. 346 * @return the new vector. 347 */ 348 public Vector2f mult(float scalar) { 349 return new Vector2f(x * scalar, y * scalar); 350 } 351 352 /** 353 * <code>multLocal</code> multiplies this vector by a scalar internally, 354 * and returns a handle to this vector for easy chaining of calls. 355 * 356 * @param scalar 357 * the value to multiply this vector by. 358 * @return this 359 */ 360 public Vector2f multLocal(float scalar) { 361 x *= scalar; 362 y *= scalar; 363 return this; 364 } 365 366 /** 367 * <code>multLocal</code> multiplies a provided vector to this vector 368 * internally, and returns a handle to this vector for easy chaining of 369 * calls. If the provided vector is null, null is returned. 370 * 371 * @param vec 372 * the vector to mult to this vector. 373 * @return this 374 */ 375 public Vector2f multLocal(Vector2f vec) { 376 if (null == vec) { 377 logger.warning("Provided vector is null, null returned."); 378 return null; 379 } 380 x *= vec.x; 381 y *= vec.y; 382 return this; 383 } 384 385 /** 386 * Multiplies this Vector2f's x and y by the scalar and stores the result in 387 * product. The result is returned for chaining. Similar to 388 * product=this*scalar; 389 * 390 * @param scalar 391 * The scalar to multiply by. 392 * @param product 393 * The vector2f to store the result in. 394 * @return product, after multiplication. 395 */ 396 public Vector2f mult(float scalar, Vector2f product) { 397 if (null == product) { 398 product = new Vector2f(); 399 } 400 401 product.x = x * scalar; 402 product.y = y * scalar; 403 return product; 404 } 405 406 /** 407 * <code>divide</code> divides the values of this vector by a scalar and 408 * returns the result. The values of this vector remain untouched. 409 * 410 * @param scalar 411 * the value to divide this vectors attributes by. 412 * @return the result <code>Vector</code>. 413 */ 414 public Vector2f divide(float scalar) { 415 return new Vector2f(x / scalar, y / scalar); 416 } 417 418 /** 419 * <code>divideLocal</code> divides this vector by a scalar internally, 420 * and returns a handle to this vector for easy chaining of calls. Dividing 421 * by zero will result in an exception. 422 * 423 * @param scalar 424 * the value to divides this vector by. 425 * @return this 426 */ 427 public Vector2f divideLocal(float scalar) { 428 x /= scalar; 429 y /= scalar; 430 return this; 431 } 432 433 /** 434 * <code>negate</code> returns the negative of this vector. All values are 435 * negated and set to a new vector. 436 * 437 * @return the negated vector. 438 */ 439 public Vector2f negate() { 440 return new Vector2f(-x, -y); 441 } 442 443 /** 444 * <code>negateLocal</code> negates the internal values of this vector. 445 * 446 * @return this. 447 */ 448 public Vector2f negateLocal() { 449 x = -x; 450 y = -y; 451 return this; 452 } 453 454 /** 455 * <code>subtract</code> subtracts the values of a given vector from those 456 * of this vector creating a new vector object. If the provided vector is 457 * null, an exception is thrown. 458 * 459 * @param vec 460 * the vector to subtract from this vector. 461 * @return the result vector. 462 */ 463 public Vector2f subtract(Vector2f vec) { 464 return subtract(vec, null); 465 } 466 467 /** 468 * <code>subtract</code> subtracts the values of a given vector from those 469 * of this vector storing the result in the given vector object. If the 470 * provided vector is null, an exception is thrown. 471 * 472 * @param vec 473 * the vector to subtract from this vector. 474 * @param store 475 * the vector to store the result in. It is safe for this to be 476 * the same as vec. If null, a new vector is created. 477 * @return the result vector. 478 */ 479 public Vector2f subtract(Vector2f vec, Vector2f store) { 480 if (store == null) 481 store = new Vector2f(); 482 store.x = x - vec.x; 483 store.y = y - vec.y; 484 return store; 485 } 486 487 /** 488 * <code>subtract</code> subtracts the given x,y values from those of this 489 * vector creating a new vector object. 490 * 491 * @param valX 492 * value to subtract from x 493 * @param valY 494 * value to subtract from y 495 * @return this 496 */ 497 public Vector2f subtract(float valX, float valY) { 498 return new Vector2f(x - valX, y - valY); 499 } 500 501 /** 502 * <code>subtractLocal</code> subtracts a provided vector to this vector 503 * internally, and returns a handle to this vector for easy chaining of 504 * calls. If the provided vector is null, null is returned. 505 * 506 * @param vec 507 * the vector to subtract 508 * @return this 509 */ 510 public Vector2f subtractLocal(Vector2f vec) { 511 if (null == vec) { 512 logger.warning("Provided vector is null, null returned."); 513 return null; 514 } 515 x -= vec.x; 516 y -= vec.y; 517 return this; 518 } 519 520 /** 521 * <code>subtractLocal</code> subtracts the provided values from this 522 * vector internally, and returns a handle to this vector for easy chaining 523 * of calls. 524 * 525 * @param valX 526 * value to subtract from x 527 * @param valY 528 * value to subtract from y 529 * @return this 530 */ 531 public Vector2f subtractLocal(float valX, float valY) { 532 x -= valX; 533 y -= valY; 534 return this; 535 } 536 537 /** 538 * <code>normalize</code> returns the unit vector of this vector. 539 * 540 * @return unit vector of this vector. 541 */ 542 public Vector2f normalize() { 543 float length = length(); 544 if (length != 0) { 545 return divide(length); 546 } 547 548 return divide(1); 549 } 550 551 /** 552 * <code>normalizeLocal</code> makes this vector into a unit vector of 553 * itself. 554 * 555 * @return this. 556 */ 557 public Vector2f normalizeLocal() { 558 float length = length(); 559 if (length != 0) { 560 return divideLocal(length); 561 } 562 563 return divideLocal(1); 564 } 565 566 /** 567 * <code>smallestAngleBetween</code> returns (in radians) the minimum 568 * angle between two vectors. It is assumed that both this vector and the 569 * given vector are unit vectors (iow, normalized). 570 * 571 * @param otherVector 572 * a unit vector to find the angle against 573 * @return the angle in radians. 574 */ 575 public float smallestAngleBetween(Vector2f otherVector) { 576 float dotProduct = dot(otherVector); 577 float angle = FastMath.acos(dotProduct); 578 return angle; 579 } 580 581 /** 582 * <code>angleBetween</code> returns (in radians) the angle required to 583 * rotate a ray represented by this vector to lie colinear to a ray 584 * described by the given vector. It is assumed that both this vector and 585 * the given vector are unit vectors (iow, normalized). 586 * 587 * @param otherVector 588 * the "destination" unit vector 589 * @return the angle in radians. 590 */ 591 public float angleBetween(Vector2f otherVector) { 592 float angle = FastMath.atan2(otherVector.y, otherVector.x) 593 - FastMath.atan2(y, x); 594 return angle; 595 } 596 597 public float getX() { 598 return x; 599 } 600 601 public Vector2f setX(float x) { 602 this.x = x; 603 return this; 604 } 605 606 public float getY() { 607 return y; 608 } 609 610 public Vector2f setY(float y) { 611 this.y = y; 612 return this; 613 } 614 /** 615 * <code>getAngle</code> returns (in radians) the angle represented by 616 * this Vector2f as expressed by a conversion from rectangular coordinates (<code>x</code>, <code>y</code>) 617 * to polar coordinates (r, <i>theta</i>). 618 * 619 * @return the angle in radians. [-pi, pi) 620 */ 621 public float getAngle() { 622 return FastMath.atan2(y, x); 623 } 624 625 /** 626 * <code>zero</code> resets this vector's data to zero internally. 627 */ 628 public Vector2f zero() { 629 x = y = 0; 630 return this; 631 } 632 633 /** 634 * <code>hashCode</code> returns a unique code for this vector object 635 * based on it's values. If two vectors are logically equivalent, they will 636 * return the same hash code value. 637 * 638 * @return the hash code value of this vector. 639 */ 640 public int hashCode() { 641 int hash = 37; 642 hash += 37 * hash + Float.floatToIntBits(x); 643 hash += 37 * hash + Float.floatToIntBits(y); 644 return hash; 645 } 646 647 @Override 648 public Vector2f clone() { 649 try { 650 return (Vector2f) super.clone(); 651 } catch (CloneNotSupportedException e) { 652 throw new AssertionError(); // can not happen 653 } 654 } 655 656 /** 657 * Saves this Vector2f into the given float[] object. 658 * 659 * @param floats 660 * The float[] to take this Vector2f. If null, a new float[2] is 661 * created. 662 * @return The array, with X, Y float values in that order 663 */ 664 public float[] toArray(float[] floats) { 665 if (floats == null) { 666 floats = new float[2]; 667 } 668 floats[0] = x; 669 floats[1] = y; 670 return floats; 671 } 672 673 /** 674 * are these two vectors the same? they are is they both have the same x and 675 * y values. 676 * 677 * @param o 678 * the object to compare for equality 679 * @return true if they are equal 680 */ 681 public boolean equals(Object o) { 682 if (!(o instanceof Vector2f)) { 683 return false; 684 } 685 686 if (this == o) { 687 return true; 688 } 689 690 Vector2f comp = (Vector2f) o; 691 if (Float.compare(x, comp.x) != 0) 692 return false; 693 if (Float.compare(y, comp.y) != 0) 694 return false; 695 return true; 696 } 697 698 /** 699 * <code>toString</code> returns the string representation of this vector 700 * object. The format of the string is such: com.jme.math.Vector2f 701 * [X=XX.XXXX, Y=YY.YYYY] 702 * 703 * @return the string representation of this vector. 704 */ 705 public String toString() { 706 return "(" + x + ", " + y + ")"; 707 } 708 709 /** 710 * Used with serialization. Not to be called manually. 711 * 712 * @param in 713 * ObjectInput 714 * @throws IOException 715 * @throws ClassNotFoundException 716 * @see java.io.Externalizable 717 */ 718 public void readExternal(ObjectInput in) throws IOException, 719 ClassNotFoundException { 720 x = in.readFloat(); 721 y = in.readFloat(); 722 } 723 724 /** 725 * Used with serialization. Not to be called manually. 726 * 727 * @param out 728 * ObjectOutput 729 * @throws IOException 730 * @see java.io.Externalizable 731 */ 732 public void writeExternal(ObjectOutput out) throws IOException { 733 out.writeFloat(x); 734 out.writeFloat(y); 735 } 736 737 public void write(JmeExporter e) throws IOException { 738 OutputCapsule capsule = e.getCapsule(this); 739 capsule.write(x, "x", 0); 740 capsule.write(y, "y", 0); 741 } 742 743 public void read(JmeImporter e) throws IOException { 744 InputCapsule capsule = e.getCapsule(this); 745 x = capsule.readFloat("x", 0); 746 y = capsule.readFloat("y", 0); 747 } 748 749 public void rotateAroundOrigin(float angle, boolean cw) { 750 if (cw) 751 angle = -angle; 752 float newX = FastMath.cos(angle) * x - FastMath.sin(angle) * y; 753 float newY = FastMath.sin(angle) * x + FastMath.cos(angle) * y; 754 x = newX; 755 y = newY; 756 } 757 } 758