All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bukkit.util.Vector Maven / Gradle / Ivy

package org.bukkit.util;

import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.SerializableAs;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;

/**
 * Represents a mutable vector. Because the components of Vectors are mutable,
 * storing Vectors long term may be dangerous if passing code modifies the
 * Vector later. If you want to keep around a Vector, it may be wise to call
 * clone() in order to get a copy.
 */
@SerializableAs("Vector")
public class Vector implements Cloneable, ConfigurationSerializable {
  private static final long serialVersionUID = -2657651106777219169L;
  /**
   * Threshold for fuzzy equals().
   */
  private static final double epsilon = 0.000001;
  private static final Random random = new Random();
  protected double x;
  protected double y;
  protected double z;

  /**
   * Construct the vector with all components as 0.
   */
  public Vector() {
    this.x = 0;
    this.y = 0;
    this.z = 0;
  }

  /**
   * Construct the vector with provided integer components.
   *
   * @param x X component
   * @param y Y component
   * @param z Z component
   */
  public Vector(int x, int y, int z) {
    this.x = x;
    this.y = y;
    this.z = z;
  }

  /**
   * Construct the vector with provided double components.
   *
   * @param x X component
   * @param y Y component
   * @param z Z component
   */
  public Vector(double x, double y, double z) {
    this.x = x;
    this.y = y;
    this.z = z;
  }

  /**
   * Construct the vector with provided float components.
   *
   * @param x X component
   * @param y Y component
   * @param z Z component
   */
  public Vector(float x, float y, float z) {
    this.x = x;
    this.y = y;
    this.z = z;
  }

  /**
   * Get the threshold used for equals().
   *
   * @return The epsilon.
   */
  public static double getEpsilon() {
    return epsilon;
  }

  /**
   * Gets the minimum components of two vectors.
   *
   * @param v1 The first vector.
   * @param v2 The second vector.
   * @return minimum
   */
  public static Vector getMinimum(Vector v1, Vector v2) {
    return new Vector(Math.min(v1.x, v2.x), Math.min(v1.y, v2.y), Math.min(v1.z, v2.z));
  }

  /**
   * Gets the maximum components of two vectors.
   *
   * @param v1 The first vector.
   * @param v2 The second vector.
   * @return maximum
   */
  public static Vector getMaximum(Vector v1, Vector v2) {
    return new Vector(Math.max(v1.x, v2.x), Math.max(v1.y, v2.y), Math.max(v1.z, v2.z));
  }

  /**
   * Gets a random vector with components having a random value between 0
   * and 1.
   *
   * @return A random vector.
   */
  public static Vector getRandom() {
    return new Vector(random.nextDouble(), random.nextDouble(), random.nextDouble());
  }

  public static Vector deserialize(Map args) {
    double x = 0;
    double y = 0;
    double z = 0;

    if (args.containsKey("x")) {
      x = (Double) args.get("x");
    }
    if (args.containsKey("y")) {
      y = (Double) args.get("y");
    }
    if (args.containsKey("z")) {
      z = (Double) args.get("z");
    }

    return new Vector(x, y, z);
  }

  /**
   * Adds a vector to this one
   *
   * @param vec The other vector
   * @return the same vector
   */
  public Vector add(Vector vec) {
    x += vec.x;
    y += vec.y;
    z += vec.z;
    return this;
  }

  /**
   * Subtracts a vector from this one.
   *
   * @param vec The other vector
   * @return the same vector
   */
  public Vector subtract(Vector vec) {
    x -= vec.x;
    y -= vec.y;
    z -= vec.z;
    return this;
  }

  /**
   * Multiplies the vector by another.
   *
   * @param vec The other vector
   * @return the same vector
   */
  public Vector multiply(Vector vec) {
    x *= vec.x;
    y *= vec.y;
    z *= vec.z;
    return this;
  }

  /**
   * Divides the vector by another.
   *
   * @param vec The other vector
   * @return the same vector
   */
  public Vector divide(Vector vec) {
    x /= vec.x;
    y /= vec.y;
    z /= vec.z;
    return this;
  }

  /**
   * Copies another vector
   *
   * @param vec The other vector
   * @return the same vector
   */
  public Vector copy(Vector vec) {
    x = vec.x;
    y = vec.y;
    z = vec.z;
    return this;
  }

  /**
   * Gets the magnitude of the vector, defined as sqrt(x^2+y^2+z^2). The
   * value of this method is not cached and uses a costly square-root
   * function, so do not repeatedly call this method to get the vector's
   * magnitude. NaN will be returned if the inner result of the sqrt()
   * function overflows, which will be caused if the length is too long.
   *
   * @return the magnitude
   */
  public double length() {
    return Math.sqrt(NumberConversions.square(x) + NumberConversions.square(y) + NumberConversions.square(z));
  }

  /**
   * Gets the magnitude of the vector squared.
   *
   * @return the magnitude
   */
  public double lengthSquared() {
    return NumberConversions.square(x) + NumberConversions.square(y) + NumberConversions.square(z);
  }

  /**
   * Get the distance between this vector and another. The value of this
   * method is not cached and uses a costly square-root function, so do not
   * repeatedly call this method to get the vector's magnitude. NaN will be
   * returned if the inner result of the sqrt() function overflows, which
   * will be caused if the distance is too long.
   *
   * @param o The other vector
   * @return the distance
   */
  public double distance(Vector o) {
    return Math.sqrt(NumberConversions.square(x - o.x) + NumberConversions.square(y - o.y) + NumberConversions.square(z - o.z));
  }

  /**
   * Get the squared distance between this vector and another.
   *
   * @param o The other vector
   * @return the distance
   */
  public double distanceSquared(Vector o) {
    return NumberConversions.square(x - o.x) + NumberConversions.square(y - o.y) + NumberConversions.square(z - o.z);
  }

  /**
   * Gets the angle between this vector and another in radians.
   *
   * @param other The other vector
   * @return angle in radians
   */
  public float angle(Vector other) {
    double dot = dot(other) / (length() * other.length());

    return (float) Math.acos(dot);
  }

  /**
   * Sets this vector to the midpoint between this vector and another.
   *
   * @param other The other vector
   * @return this same vector (now a midpoint)
   */
  public Vector midpoint(Vector other) {
    x = (x + other.x) / 2;
    y = (y + other.y) / 2;
    z = (z + other.z) / 2;
    return this;
  }

  /**
   * Gets a new midpoint vector between this vector and another.
   *
   * @param other The other vector
   * @return a new midpoint vector
   */
  public Vector getMidpoint(Vector other) {
    double x = (this.x + other.x) / 2;
    double y = (this.y + other.y) / 2;
    double z = (this.z + other.z) / 2;
    return new Vector(x, y, z);
  }

  /**
   * Performs scalar multiplication, multiplying all components with a
   * scalar.
   *
   * @param m The factor
   * @return the same vector
   */
  public Vector multiply(int m) {
    x *= m;
    y *= m;
    z *= m;
    return this;
  }

  /**
   * Performs scalar multiplication, multiplying all components with a
   * scalar.
   *
   * @param m The factor
   * @return the same vector
   */
  public Vector multiply(double m) {
    x *= m;
    y *= m;
    z *= m;
    return this;
  }

  /**
   * Performs scalar multiplication, multiplying all components with a
   * scalar.
   *
   * @param m The factor
   * @return the same vector
   */
  public Vector multiply(float m) {
    x *= m;
    y *= m;
    z *= m;
    return this;
  }

  /**
   * Calculates the dot product of this vector with another. The dot product
   * is defined as x1*x2+y1*y2+z1*z2. The returned value is a scalar.
   *
   * @param other The other vector
   * @return dot product
   */
  public double dot(Vector other) {
    return x * other.x + y * other.y + z * other.z;
  }

  /**
   * Calculates the cross product of this vector with another. The cross
   * product is defined as:
   * 
    *
  • x = y1 * z2 - y2 * z1 *
  • y = z1 * x2 - z2 * x1 *
  • z = x1 * y2 - x2 * y1 *
* * @param o The other vector * @return the same vector */ public Vector crossProduct(Vector o) { double newX = y * o.z - o.y * z; double newY = z * o.x - o.z * x; double newZ = x * o.y - o.x * y; x = newX; y = newY; z = newZ; return this; } /** * Calculates the cross product of this vector with another without mutating * the original. The cross product is defined as: *
    *
  • x = y1 * z2 - y2 * z1 *
  • y = z1 * x2 - z2 * x1 *
  • z = x1 * y2 - x2 * y1 *
* * @param o The other vector * @return a new vector */ public Vector getCrossProduct(Vector o) { double x = this.y * o.z - o.y * this.z; double y = this.z * o.x - o.z * this.x; double z = this.x * o.y - o.x * this.y; return new Vector(x, y, z); } /** * Converts this vector to a unit vector (a vector with length of 1). * * @return the same vector */ public Vector normalize() { double length = length(); x /= length; y /= length; z /= length; return this; } /** * Zero this vector's components. * * @return the same vector */ public Vector zero() { x = 0; y = 0; z = 0; return this; } /** * Returns whether this vector is in an axis-aligned bounding box. *

* The minimum and maximum vectors given must be truly the minimum and * maximum X, Y and Z components. * * @param min Minimum vector * @param max Maximum vector * @return whether this vector is in the AABB */ public boolean isInAABB(Vector min, Vector max) { return x >= min.x && x <= max.x && y >= min.y && y <= max.y && z >= min.z && z <= max.z; } /** * Returns whether this vector is within a sphere. * * @param origin Sphere origin. * @param radius Sphere radius * @return whether this vector is in the sphere */ public boolean isInSphere(Vector origin, double radius) { return (NumberConversions.square(origin.x - x) + NumberConversions.square(origin.y - y) + NumberConversions.square(origin.z - z)) <= NumberConversions.square(radius); } /** * Gets the X component. * * @return The X component. */ public double getX() { return x; } /** * Set the X component. * * @param x The new X component. * @return This vector. */ public Vector setX(int x) { this.x = x; return this; } /** * Set the X component. * * @param x The new X component. * @return This vector. */ public Vector setX(double x) { this.x = x; return this; } /** * Set the X component. * * @param x The new X component. * @return This vector. */ public Vector setX(float x) { this.x = x; return this; } /** * Gets the floored value of the X component, indicating the block that * this vector is contained with. * * @return block X */ public int getBlockX() { return NumberConversions.floor(x); } /** * Gets the Y component. * * @return The Y component. */ public double getY() { return y; } /** * Set the Y component. * * @param y The new Y component. * @return This vector. */ public Vector setY(int y) { this.y = y; return this; } /** * Set the Y component. * * @param y The new Y component. * @return This vector. */ public Vector setY(double y) { this.y = y; return this; } /** * Set the Y component. * * @param y The new Y component. * @return This vector. */ public Vector setY(float y) { this.y = y; return this; } /** * Gets the floored value of the Y component, indicating the block that * this vector is contained with. * * @return block y */ public int getBlockY() { return NumberConversions.floor(y); } /** * Gets the Z component. * * @return The Z component. */ public double getZ() { return z; } /** * Set the Z component. * * @param z The new Z component. * @return This vector. */ public Vector setZ(int z) { this.z = z; return this; } /** * Set the Z component. * * @param z The new Z component. * @return This vector. */ public Vector setZ(double z) { this.z = z; return this; } /** * Set the Z component. * * @param z The new Z component. * @return This vector. */ public Vector setZ(float z) { this.z = z; return this; } /** * Gets the floored value of the Z component, indicating the block that * this vector is contained with. * * @return block z */ public int getBlockZ() { return NumberConversions.floor(z); } /** * Checks to see if two objects are equal. *

* Only two Vectors can ever return true. This method uses a fuzzy match * to account for floating point errors. The epsilon can be retrieved * with epsilon. */ @Override public boolean equals(Object obj) { if (!(obj instanceof Vector)) { return false; } Vector other = (Vector) obj; return Math.abs(x - other.x) < epsilon && Math.abs(y - other.y) < epsilon && Math.abs(z - other.z) < epsilon && (this.getClass().equals(obj.getClass())); } /** * Returns a hash code for this vector * * @return hash code */ @Override public int hashCode() { int hash = 7; hash = 79 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32)); hash = 79 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32)); hash = 79 * hash + (int) (Double.doubleToLongBits(this.z) ^ (Double.doubleToLongBits(this.z) >>> 32)); return hash; } /** * Get a new vector. * * @return vector */ @Override public Vector clone() { try { return (Vector) super.clone(); } catch (CloneNotSupportedException e) { throw new Error(e); } } /** * Returns this vector's components as x,y,z. */ @Override public String toString() { return x + "," + y + "," + z; } /** * Gets a Location version of this vector with yaw and pitch being 0. * * @param world The world to link the location to. * @return the location */ public Location toLocation(World world) { return new Location(world, x, y, z); } /** * Gets a Location version of this vector. * * @param world The world to link the location to. * @param yaw The desired yaw. * @param pitch The desired pitch. * @return the location */ public Location toLocation(World world, float yaw, float pitch) { return new Location(world, x, y, z, yaw, pitch); } /** * Get the block vector of this vector. * * @return A block vector. */ public BlockVector toBlockVector() { return new BlockVector(x, y, z); } public Map serialize() { Map result = new LinkedHashMap(); result.put("x", getX()); result.put("y", getY()); result.put("z", getZ()); return result; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy