001package fr.aumgn.bukkitutils.geom; 002 003import java.util.Iterator; 004 005import org.apache.commons.lang.builder.HashCodeBuilder; 006import org.bukkit.Location; 007import org.bukkit.World; 008import org.bukkit.block.Block; 009import org.bukkit.entity.Entity; 010 011import fr.aumgn.bukkitutils.geom.direction.VectorDirection; 012import fr.aumgn.bukkitutils.geom.vector.VectorIterator; 013 014/** 015 * Immutable Vector class. 016 * Inspired from WorldEdit. 017 */ 018public class Vector implements Iterable<Vector> { 019 020 private final double x, y, z; 021 022 public Vector() { 023 this.x = 0; 024 this.y = 0; 025 this.z = 0; 026 } 027 028 public Vector(int x, int y, int z) { 029 this.x = x; 030 this.y = y; 031 this.z = z; 032 } 033 034 public Vector(double x, double y, double z) { 035 this.x = x; 036 this.y = y; 037 this.z = z; 038 } 039 040 public Vector(Location loc) { 041 this(loc.getX(), loc.getY(), loc.getZ()); 042 } 043 044 public Vector(Entity entity) { 045 this(entity.getLocation()); 046 } 047 048 public Vector(Block block) { 049 this(block.getX(), block.getY(), block.getZ()); 050 } 051 052 public double getX() { 053 return x; 054 } 055 056 public int getBlockX() { 057 return (int) Math.round(x); 058 } 059 060 public double getY() { 061 return y; 062 } 063 064 public int getBlockY() { 065 return (int) Math.round(y); 066 } 067 068 public double getZ() { 069 return z; 070 } 071 072 public int getBlockZ() { 073 return (int) Math.round(z); 074 } 075 076 public Vector setX(double x) { 077 return new Vector(x, y, z); 078 } 079 080 public Vector setY(double y) { 081 return new Vector(x, y, z); 082 } 083 084 public Vector setZ(double z) { 085 return new Vector(x, y, z); 086 } 087 088 public Vector add(double i) { 089 return new Vector(this.x + i, this.y + i, this.z + i); 090 } 091 092 public Vector add(double ox, double oy, double oz) { 093 return new Vector(x + ox, y + oy, z + oz); 094 } 095 096 public Vector add(Vector other) { 097 return new Vector(x + other.x, y + other.y, z + other.z); 098 } 099 100 public Vector addX(double ox) { 101 return new Vector(x + ox, y, z); 102 } 103 104 public Vector addY(double oy) { 105 return new Vector(x, y + oy, z); 106 } 107 108 public Vector addZ(double oz) { 109 return new Vector(x, y, z + oz); 110 } 111 112 public Vector subtract(double i) { 113 return new Vector(x - i, y - i, z - i); 114 } 115 116 public Vector subtract(double ox, double oy, double oz) { 117 return new Vector(x - ox, y - oy, z - oz); 118 } 119 120 public Vector subtract(Vector other) { 121 return new Vector(x - other.x, y - other.y, z - other.z); 122 } 123 124 public Vector subtractX(double ox) { 125 return new Vector(x - ox, y, z); 126 } 127 128 public Vector subtractY(double oy) { 129 return new Vector(x, y - oy, z); 130 } 131 132 public Vector subtractZ(double oz) { 133 return new Vector(x, y, z - oz); 134 } 135 136 public Vector multiply(double i) { 137 return new Vector(x * i, y * i, z * i); 138 } 139 140 public Vector multiply(double ox, double oy, double oz) { 141 return new Vector(x * ox, y * oy, z * oz); 142 } 143 144 public Vector multiply(Vector other) { 145 return new Vector(x * other.x, y * other.y, z * other.z); 146 } 147 148 public Vector divide(double i) { 149 return new Vector(x / i, y / i, z / i); 150 } 151 152 public Vector divide(double ox, double oy, double oz) { 153 return new Vector(x / ox, y / oy, z / oz); 154 } 155 156 public Vector divide(Vector other) { 157 return new Vector(x / other.x, y / other.y, z / other.z); 158 } 159 160 public Vector getMiddle(Vector other) { 161 return new Vector( 162 (x + other.x) / 2, 163 (y + other.y) / 2, 164 (z + other.z) / 2); 165 } 166 167 public boolean isInside(Vector min, Vector max) { 168 return x >= min.x && x <= max.x 169 && y >= min.y && y <= max.y 170 && z >= min.z && z <= max.z; 171 } 172 173 public boolean isZero() { 174 return x == 0.0 && y == 0.0 && z == 0; 175 } 176 177 public Vector positive() { 178 return new Vector(Math.abs(x), Math.abs(y), Math.abs(z)); 179 } 180 181 public double lengthSq() { 182 return x * x + y * y + z * z; 183 } 184 185 public double length() { 186 return Math.sqrt(lengthSq()); 187 } 188 189 public double distanceSq(Vector other) { 190 return subtract(other).lengthSq(); 191 } 192 193 public double distance(Vector other) { 194 return subtract(other).length(); 195 } 196 197 public Vector normalize() { 198 return divide(length()); 199 } 200 201 public Vector2D to2D() { 202 return new Vector2D(x, z); 203 } 204 205 public Block toBlock(World world) { 206 return world.getBlockAt(getBlockX(), getBlockY(), getBlockZ()); 207 } 208 209 public Direction toDirection() { 210 if (isZero()) { 211 return Direction.NONE; 212 } 213 214 return new VectorDirection(this); 215 } 216 217 public Direction towards(Vector to) { 218 return to.subtract(this).toDirection(); 219 } 220 221 public org.bukkit.util.Vector toBukkit() { 222 return new org.bukkit.util.Vector(x, y, z); 223 } 224 225 public Location toLocation(World world) { 226 return toLocation(world, 0.0f, 0.0f); 227 } 228 229 public Location toLocation(World world, Vector2D direction) { 230 return toLocation(world, direction.toDirection()); 231 } 232 233 public Location toLocation(World world, Direction dir) { 234 return toLocation(world, dir.getYaw(), dir.getPitch()); 235 } 236 237 public Location toLocation(World world, float yaw, float pitch) { 238 return new Location(world, x, getBlockY() + 0.1, z, yaw, pitch); 239 } 240 241 @Override 242 public Iterator<Vector> iterator() { 243 return new VectorIterator(new Vector(), this); 244 } 245 246 public Iterable<Vector> rectangle(final Vector max) { 247 return new Iterable<Vector>() { 248 @Override 249 public Iterator<Vector> iterator() { 250 return new VectorIterator(Vector.this, max); 251 } 252 }; 253 } 254 255 @Override 256 public String toString() { 257 return "(" + x + ", " + y + ", " + z + ")"; 258 } 259 260 @Override 261 public int hashCode() { 262 return new HashCodeBuilder(23, 11) 263 .append(x) 264 .append(y) 265 .append(z) 266 .toHashCode(); 267 } 268 269 @Override 270 public boolean equals(Object obj) { 271 if (this == obj) { 272 return true; 273 } 274 275 if (!(obj instanceof Vector)) { 276 return false; 277 } 278 279 Vector o = (Vector) obj; 280 if (Double.doubleToLongBits(x) != Double.doubleToLongBits(o.x) 281 || Double.doubleToLongBits(y) != Double.doubleToLongBits(o.y) 282 || Double.doubleToLongBits(z) != Double.doubleToLongBits(o.z)) { 283 return false; 284 } 285 286 return true; 287 } 288 289 public boolean equalsBlock(Object obj) { 290 if (this == obj) { 291 return true; 292 } 293 294 if (!(obj instanceof Vector)) { 295 return false; 296 } 297 298 Vector other = (Vector) obj; 299 if (getBlockX() != other.getBlockX() 300 || getBlockY() != other.getBlockY() 301 || getBlockZ() != other.getBlockZ()) { 302 return false; 303 } 304 305 return true; 306 } 307}