Fork of Poseidon providing Bukkit #1060 to older Beta versions (b1.0-b1.7.3)
1package org.bukkit;
2
3import org.bukkit.block.Block;
4import org.bukkit.util.Vector;
5
6/**
7 * Represents a 3-dimensional position in a world
8 */
9public class Location implements Cloneable {
10 private World world;
11 private double x;
12 private double y;
13 private double z;
14 private float pitch;
15 private float yaw;
16
17 /**
18 * Constructs a new Location with the given coordinates
19 *
20 * @param world The world in which this location resides
21 * @param x The x-coordinate of this new location
22 * @param y The y-coordinate of this new location
23 * @param z The z-coordinate of this new location
24 */
25 public Location(final World world, final double x, final double y, final double z) {
26 this(world, x, y, z, 0, 0);
27 }
28
29 /**
30 * Constructs a new Location with the given coordinates and direction
31 *
32 * @param world The world in which this location resides
33 * @param x The x-coordinate of this new location
34 * @param y The y-coordinate of this new location
35 * @param z The z-coordinate of this new location
36 * @param yaw The absolute rotation on the x-plane, in degrees
37 * @param pitch The absolute rotation on the y-plane, in degrees
38 */
39 public Location(final World world, final double x, final double y, final double z, final float yaw, final float pitch) {
40 this.world = world;
41 this.x = x;
42 this.y = y;
43 this.z = z;
44 this.pitch = pitch;
45 this.yaw = yaw;
46 }
47
48 /**
49 * Sets the world that this location resides in
50 *
51 * @param world New world that this location resides in
52 */
53 public void setWorld(World world) {
54 this.world = world;
55 }
56
57 /**
58 * Gets the world that this location resides in
59 *
60 * @return World that contains this location
61 */
62 public World getWorld() {
63 return world;
64 }
65
66 /**
67 * Gets the block at the represented location
68 *
69 * @return Block at the represented location
70 */
71 public Block getBlock() {
72 return world.getBlockAt(this);
73 }
74
75 /**
76 * Sets the x-coordinate of this location
77 *
78 * @param x X-coordinate
79 */
80 public void setX(double x) {
81 this.x = x;
82 }
83
84 /**
85 * Gets the x-coordinate of this location
86 *
87 * @return x-coordinate
88 */
89 public double getX() {
90 return x;
91 }
92
93 /**
94 * Gets the floored value of the X component, indicating the block that
95 * this location is contained with.
96 *
97 * @return block X
98 */
99 public int getBlockX() {
100 return locToBlock(x);
101 }
102
103 /**
104 * Sets the y-coordinate of this location
105 *
106 * @param y y-coordinate
107 */
108 public void setY(double y) {
109 this.y = y;
110 }
111
112 /**
113 * Gets the y-coordinate of this location
114 *
115 * @return y-coordinate
116 */
117 public double getY() {
118 return y;
119 }
120
121 /**
122 * Gets the floored value of the Y component, indicating the block that
123 * this location is contained with.
124 *
125 * @return block y
126 */
127 public int getBlockY() {
128 return locToBlock(y);
129 }
130
131 /**
132 * Sets the z-coordinate of this location
133 *
134 * @param z z-coordinate
135 */
136 public void setZ(double z) {
137 this.z = z;
138 }
139
140 /**
141 * Gets the z-coordinate of this location
142 *
143 * @return z-coordinate
144 */
145 public double getZ() {
146 return z;
147 }
148
149 /**
150 * Gets the floored value of the Z component, indicating the block that
151 * this location is contained with.
152 *
153 * @return block z
154 */
155 public int getBlockZ() {
156 return locToBlock(z);
157 }
158
159 /**
160 * Sets the yaw of this location
161 *
162 * @param yaw New yaw
163 */
164 public void setYaw(float yaw) {
165 this.yaw = yaw;
166 }
167
168 /**
169 * Gets the yaw of this location
170 *
171 * @return Yaw
172 */
173 public float getYaw() {
174 return yaw;
175 }
176
177 /**
178 * Sets the pitch of this location
179 *
180 * @param pitch New pitch
181 */
182 public void setPitch(float pitch) {
183 this.pitch = pitch;
184 }
185
186 /**
187 * Gets the pitch of this location
188 *
189 * @return Pitch
190 */
191 public float getPitch() {
192 return pitch;
193 }
194
195 /**
196 * Gets a Vector pointing in the direction that this Location is facing
197 *
198 * @return Vector
199 */
200 public Vector getDirection() {
201 Vector vector = new Vector();
202
203 double rotX = this.getYaw();
204 double rotY = this.getPitch();
205
206 vector.setY(-Math.sin(Math.toRadians(rotY)));
207
208 double h = Math.cos(Math.toRadians(rotY));
209
210 vector.setX(-h * Math.sin(Math.toRadians(rotX)));
211 vector.setZ(h * Math.cos(Math.toRadians(rotX)));
212
213 return vector;
214 }
215
216 /**
217 * Adds the location by another.
218 *
219 * @param vec
220 * @return the same location
221 * @throws IllegalArgumentException for differing worlds
222 * @see Vector
223 */
224 public Location add(Location vec) {
225 if (vec == null || vec.getWorld() != getWorld()) {
226 throw new IllegalArgumentException("Cannot add Locations of differing worlds");
227 }
228
229 x += vec.x;
230 y += vec.y;
231 z += vec.z;
232 return this;
233 }
234
235 /**
236 * Adds the location by another. Not world-aware.
237 *
238 * @param x
239 * @param y
240 * @param z
241 * @return the same location
242 * @see Vector
243 */
244 public Location add(double x, double y, double z) {
245 this.x += x;
246 this.y += y;
247 this.z += z;
248 return this;
249 }
250
251 /**
252 * Subtracts the location by another.
253 *
254 * @param vec
255 * @return the same location
256 * @throws IllegalArgumentException for differing worlds
257 * @see Vector
258 */
259 public Location subtract(Location vec) {
260 if (vec == null || vec.getWorld() != getWorld()) {
261 throw new IllegalArgumentException("Cannot add Locations of differing worlds");
262 }
263
264 x -= vec.x;
265 y -= vec.y;
266 z -= vec.z;
267 return this;
268 }
269
270 /**
271 * Subtracts the location by another. Not world-aware and
272 * orientation independent.
273 *
274 * @param x
275 * @param y
276 * @param z
277 * @return the same location
278 * @see Vector
279 */
280 public Location subtract(double x, double y, double z) {
281 this.x -= x;
282 this.y -= y;
283 this.z -= z;
284 return this;
285 }
286
287 /**
288 * Gets the magnitude of the location, defined as sqrt(x^2+y^2+z^2). The value
289 * of this method is not cached and uses a costly square-root function, so
290 * do not repeatedly call this method to get the location's magnitude. NaN
291 * will be returned if the inner result of the sqrt() function overflows,
292 * which will be caused if the length is too long. Not world-aware and
293 * orientation independent.
294 *
295 * @return the magnitude
296 * @see Vector
297 */
298 public double length() {
299 return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
300 }
301
302 /**
303 * Gets the magnitude of the location squared. Not world-aware and
304 * orientation independent.
305 *
306 * @return the magnitude
307 * @see Vector
308 */
309 public double lengthSquared() {
310 return Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2);
311 }
312
313 /**
314 * Get the distance between this location and another. The value
315 * of this method is not cached and uses a costly square-root function, so
316 * do not repeatedly call this method to get the location's magnitude. NaN
317 * will be returned if the inner result of the sqrt() function overflows,
318 * which will be caused if the distance is too long.
319 *
320 * @param o
321 * @return the distance
322 * @throws IllegalArgumentException for differing worlds
323 * @see Vector
324 */
325 public double distance(Location o) {
326 if (o == null || o.getWorld() != getWorld()) {
327 throw new IllegalArgumentException("Cannot measure distance between worlds or to null");
328 }
329
330 return Math.sqrt(Math.pow(x - o.x, 2) + Math.pow(y - o.y, 2) + Math.pow(z - o.z, 2));
331 }
332
333 /**
334 * Get the squared distance between this location and another.
335 *
336 * @param o
337 * @return the distance
338 * @throws IllegalArgumentException for differing worlds
339 * @see Vector
340 */
341 public double distanceSquared(Location o) {
342 if (o == null || o.getWorld() != getWorld()) {
343 throw new IllegalArgumentException("Cannot measure distance between worlds or to null");
344 }
345
346 return Math.pow(x - o.x, 2) + Math.pow(y - o.y, 2) + Math.pow(z - o.z, 2);
347 }
348
349 /**
350 * Performs scalar multiplication, multiplying all components with a scalar.
351 * Not world-aware.
352 *
353 * @param m
354 * @return the same location
355 * @see Vector
356 */
357 public Location multiply(double m) {
358 x *= m;
359 y *= m;
360 z *= m;
361 return this;
362 }
363
364 /**
365 * Zero this location's components. Not world-aware.
366 *
367 * @return the same location
368 * @see Vector
369 */
370 public Location zero() {
371 x = 0;
372 y = 0;
373 z = 0;
374 return this;
375 }
376
377 @Override
378 public boolean equals(Object obj) {
379 if (obj == null) {
380 return false;
381 }
382 if (getClass() != obj.getClass()) {
383 return false;
384 }
385 final Location other = (Location) obj;
386
387 if (this.world != other.world && (this.world == null || !this.world.equals(other.world))) {
388 return false;
389 }
390 if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x)) {
391 return false;
392 }
393 if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(other.y)) {
394 return false;
395 }
396 if (Double.doubleToLongBits(this.z) != Double.doubleToLongBits(other.z)) {
397 return false;
398 }
399 if (Float.floatToIntBits(this.pitch) != Float.floatToIntBits(other.pitch)) {
400 return false;
401 }
402 if (Float.floatToIntBits(this.yaw) != Float.floatToIntBits(other.yaw)) {
403 return false;
404 }
405 return true;
406 }
407
408 @Override
409 public int hashCode() {
410 int hash = 3;
411
412 hash = 19 * hash + (this.world != null ? this.world.hashCode() : 0);
413 hash = 19 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32));
414 hash = 19 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32));
415 hash = 19 * hash + (int) (Double.doubleToLongBits(this.z) ^ (Double.doubleToLongBits(this.z) >>> 32));
416 hash = 19 * hash + Float.floatToIntBits(this.pitch);
417 hash = 19 * hash + Float.floatToIntBits(this.yaw);
418 return hash;
419 }
420
421 @Override
422 public String toString() {
423 return "Location{" + "world=" + world + "x=" + x + "y=" + y + "z=" + z + "pitch=" + pitch + "yaw=" + yaw + '}';
424 }
425
426 /**
427 * Constructs a new {@link Vector} based on this Location
428 *
429 * @return New Vector containing the coordinates represented by this Location
430 */
431 public Vector toVector() {
432 return new Vector(x, y, z);
433 }
434
435 @Override
436 public Location clone() {
437 try {
438 Location l = (Location) super.clone();
439
440 l.world = world;
441 l.x = x;
442 l.y = y;
443 l.z = z;
444 l.yaw = yaw;
445 l.pitch = pitch;
446 return l;
447 } catch (CloneNotSupportedException e) {
448 e.printStackTrace();
449 }
450 return null;
451 }
452
453 /**
454 * Safely converts a double (location coordinate) to an int (block coordinate)
455 *
456 * @param loc Precise coordinate
457 * @return Block coordinate
458 */
459 public static int locToBlock(double loc) {
460 return (int) Math.floor(loc);
461 }
462}