package net.aufdemrand.denizen.utilities;
import org.bukkit.Location;
import org.bukkit.util.Vector;
public class Velocity {
/**
* Calculates the vector between two locations' vectors
*
* Original code by SethBling, edited to be a bit
* more accurate.
*
* @param from The origin's vector
* @param to The destination's vector
* @param gravity The gravity value of the entity
* @param heightGain The gain in height
*
* @return A vector
*/
public static Vector calculate(Vector from, Vector to, double gravity, double heightGain) {
// Block locations
int endGain = to.getBlockY() - from.getBlockY();
double horizDist = Math.sqrt(distanceSquared(from, to));
double maxGain = heightGain > (endGain + heightGain) ? heightGain : (endGain + heightGain);
// Solve quadratic equation for velocity
double a = -horizDist * horizDist / (4 * maxGain);
double b = horizDist;
double c = -endGain;
double slope = -b / (2 * a) - Math.sqrt(b * b - 4 * a * c) / (2 * a);
// Vertical velocity
double vy = Math.sqrt(maxGain * (gravity + 0.0013675090252708 * heightGain));
// Horizontal velocity
double vh = vy / slope;
// Calculate horizontal direction
int dx = to.getBlockX() - from.getBlockX();
int dz = to.getBlockZ() - from.getBlockZ();
double mag = Math.sqrt(dx * dx + dz * dz);
double dirx = dx / mag;
double dirz = dz / mag;
// Horizontal velocity components
double vx = vh * dirx;
double vz = vh * dirz;
return new Vector(vx, vy, vz);
}
private static double distanceSquared(Vector from, Vector to) {
double dx = to.getBlockX() - from.getBlockX();
double dz = to.getBlockZ() - from.getBlockZ();
return dx * dx + dz * dz;
}
public static Vector spread(Vector from, double yaw, double pitch) {
Vector vec = from.clone();
float cosyaw = (float)Math.cos(yaw);
float cospitch = (float)Math.cos(pitch);
float sinyaw = (float)Math.sin(yaw);
float sinpitch = (float)Math.sin(pitch);
float bX = (float) (vec.getY() * sinpitch + vec.getX() * cospitch);
float bY = (float) (vec.getY() * cospitch - vec.getX() * sinpitch);
return new Vector(bX * cosyaw - vec.getZ() * sinyaw, bY, bX * sinyaw + vec.getZ() * cosyaw);
}
public static double launchAngle(Location from, Vector to, double v, double elev, double g) {
Vector victor = from.toVector().subtract(to);
Double dist = Math.sqrt(Math.pow(victor.getX(), 2) + Math.pow(victor.getZ(), 2));
double v2 = Math.pow(v,2);
double v4 = Math.pow(v,4);
double derp = g * (g * Math.pow(dist, 2) + 2 * elev * v2);
if( v4 < derp) {
// Max optimal (won't hit!)
return Math.atan((2 * g * elev + v2) / (2 * g * elev + 2 * v2));
}
else {
return Math.atan((v2 - Math.sqrt(v4 - derp)) / (g * dist));
}
}
public static double hangtime(double launchAngle, double v, double elev, double g) {
double a = v * Math.sin(launchAngle);
double b = -2*g*elev;
if(Math.pow(a, 2) + b < 0){
return 0;
}
return (a + Math.sqrt(Math.pow(a, 2) + b)) / g;
}
}