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.Vector2DDirection; 012import fr.aumgn.bukkitutils.geom.vector.Vector2DIterator; 013 014/** 015 * Immutable Vector2D class. 016 * Inspired from WorldEdit. 017 */ 018public class Vector2D implements Iterable<Vector2D> { 019 020 private final double x, z; 021 022 public Vector2D() { 023 this.x = 0; 024 this.z = 0; 025 } 026 027 public Vector2D(int x, int z) { 028 this.x = x; 029 this.z = z; 030 } 031 032 public Vector2D(double x, double z) { 033 this.x = x; 034 this.z = z; 035 } 036 037 public Vector2D(Location loc) { 038 this(loc.getX(), loc.getZ()); 039 } 040 041 public Vector2D(Entity entity) { 042 this(entity.getLocation()); 043 } 044 045 public Vector2D(Block block) { 046 this(block.getX(), block.getZ()); 047 } 048 049 public double getX() { 050 return x; 051 } 052 053 public int getBlockX() { 054 return (int) Math.round(x); 055 } 056 057 public double getZ() { 058 return z; 059 } 060 061 public int getBlockZ() { 062 return (int) Math.round(z); 063 } 064 065 public Vector2D setX(double x) { 066 return new Vector2D(x, z); 067 } 068 069 public Vector2D setZ(double z) { 070 return new Vector2D(x, z); 071 } 072 073 public Vector2D add(double i) { 074 return new Vector2D(this.x + i, this.z + i); 075 } 076 077 public Vector2D add(double ox, double oz) { 078 return new Vector2D(x + ox, z + oz); 079 } 080 081 public Vector2D add(Vector2D other) { 082 return new Vector2D(x + other.x, z + other.z); 083 } 084 085 public Vector2D addX(double ox) { 086 return new Vector2D(x + ox, z); 087 } 088 089 public Vector2D addZ(double oz) { 090 return new Vector2D(x, z + oz); 091 } 092 093 public Vector2D subtract(double i) { 094 return new Vector2D(x - i, z - i); 095 } 096 097 public Vector2D subtract(double ox, double oz) { 098 return new Vector2D(x - ox, z - oz); 099 } 100 101 public Vector2D subtract(Vector2D other) { 102 return new Vector2D(x - other.x, z - other.z); 103 } 104 105 public Vector2D subtractX(double ox) { 106 return new Vector2D(x - ox, z); 107 } 108 109 public Vector2D subtractZ(double oz) { 110 return new Vector2D(x, z - oz); 111 } 112 113 public Vector2D multiply(double i) { 114 return new Vector2D(x * i, z * i); 115 } 116 117 public Vector2D multiply(double ox, double oz) { 118 return new Vector2D(x * ox, z * oz); 119 } 120 121 public Vector2D multiply(Vector2D other) { 122 return new Vector2D(x * other.x, z * other.z); 123 } 124 125 public Vector2D divide(double i) { 126 return new Vector2D(x / i, z / i); 127 } 128 129 public Vector2D divide(double ox, double oz) { 130 return new Vector2D(x / ox, z / oz); 131 } 132 133 public Vector2D divide(Vector2D other) { 134 return new Vector2D(x / other.x, z / other.z); 135 } 136 137 public Vector2D getMiddle(Vector2D other) { 138 return new Vector2D( 139 (x + other.x) / 2, 140 (z + other.z) / 2); 141 } 142 143 public boolean isInside(Vector2D min, Vector2D max) { 144 return x >= min.x && x <= max.x 145 && z >= min.z && z <= max.z; 146 } 147 148 public boolean isZero() { 149 return x == 0.0 && z == 0; 150 } 151 152 public Vector2D positive() { 153 return new Vector2D(Math.abs(x), Math.abs(z)); 154 } 155 156 public double lengthSq() { 157 return x * x + z * z; 158 } 159 160 public double length() { 161 return Math.sqrt(lengthSq()); 162 } 163 164 public double distanceSq(Vector2D other) { 165 return subtract(other).lengthSq(); 166 } 167 168 public double distance(Vector2D other) { 169 return subtract(other).length(); 170 } 171 172 public Vector2D rotate90() { 173 return new Vector2D(-z, x); 174 } 175 176 public Vector2D normalize() { 177 return divide(length()); 178 } 179 180 public Direction toDirection() { 181 if (isZero()) { 182 return Direction.NONE; 183 } 184 185 return new Vector2DDirection(this); 186 } 187 188 public Direction towards(Vector2D to) { 189 return to.subtract(this).toDirection(); 190 } 191 192 public Vector to3D() { 193 return new Vector(x, 0, z); 194 } 195 196 public Vector to3D(double y) { 197 return new Vector(x, y, z); 198 } 199 200 public Vector toHighest(World world) { 201 int y = world.getHighestBlockYAt( 202 getBlockX(), getBlockZ()); 203 return to3D(y); 204 } 205 206 @Override 207 public Iterator<Vector2D> iterator() { 208 return new Vector2DIterator(new Vector2D(), this); 209 } 210 211 public Iterable<Vector2D> rectangle(final Vector2D max) { 212 return new Iterable<Vector2D>() { 213 @Override 214 public Iterator<Vector2D> iterator() { 215 return new Vector2DIterator(Vector2D.this, max); 216 } 217 }; 218 } 219 220 @Override 221 public String toString() { 222 return "(" + x + ", " + + z + ")"; 223 } 224 225 @Override 226 public int hashCode() { 227 return new HashCodeBuilder(29, 13) 228 .append(x) 229 .append(z) 230 .toHashCode(); 231 } 232 233 @Override 234 public boolean equals(Object obj) { 235 if (this == obj) { 236 return true; 237 } 238 239 if (!(obj instanceof Vector2D)) { 240 return false; 241 } 242 243 Vector2D o = (Vector2D) obj; 244 if (Double.doubleToLongBits(x) != Double.doubleToLongBits(o.x) 245 || Double.doubleToLongBits(z) != Double.doubleToLongBits(o.z)) { 246 return false; 247 } 248 249 return true; 250 } 251 252 public boolean equalsBlock(Object obj) { 253 if (this == obj) { 254 return true; 255 } 256 257 if (!(obj instanceof Vector2D)) { 258 return false; 259 } 260 261 Vector2D other = (Vector2D) obj; 262 if (getBlockX() != other.getBlockX() 263 || getBlockZ() != other.getBlockZ()) { 264 return false; 265 } 266 267 return true; 268 } 269}