001/* 002 * Trident - A Multithreaded Server Alternative 003 * Copyright 2014 The TridentSDK Team 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package net.tridentsdk.base; 019 020import com.google.common.base.Objects; 021import com.google.common.base.Preconditions; 022import net.tridentsdk.util.Vector; 023import net.tridentsdk.world.Chunk; 024import net.tridentsdk.world.World; 025 026import javax.annotation.concurrent.ThreadSafe; 027 028/** 029 * Represents a point on the coordinate grid of the world, including pitch and yaw 030 * 031 * @author The TridentSDK Team 032 * @since 0.3-alpha-DP 033 */ 034@ThreadSafe 035public final class Position extends Vector implements Cloneable { 036 private volatile World world; 037 private volatile float yaw; 038 private volatile float pitch; 039 040 private Position(World world, double x, double y, double z, float yaw, float pitch) { 041 this.world = world; 042 043 this.x = x; 044 this.y = y; 045 this.z = z; 046 047 this.yaw = yaw; 048 this.pitch = pitch; 049 } 050 051 public Position(World world, double x, double y, double z) { 052 this(world, x, y, z, 0.0F, 0.0F); 053 } 054 055 private static double square(double d) { 056 return d * d; 057 } 058 059 /** 060 * References the point on the world as a position that wraps the coordinates 061 * 062 * @param world the world which the point resides in 063 * @param x the x coordinate 064 * @param y the y coordinate 065 * @param z the z coordinate 066 * @param yaw goes side to side, in degrees 067 * @param pitch goes up and down, in degrees 068 */ 069 public static Position create(World world, double x, double y, double z, float yaw, float pitch) { 070 return new Position(world, x, y, z, yaw, pitch); 071 } 072 073 /** 074 * Wraps the point without specific yaw and pitch (set to 0) 075 * 076 * @param world the world which the point resides in 077 * @param x the x coordinate 078 * @param y the y coordinate 079 * @param z the z coordinate 080 */ 081 public static Position create(World world, double x, double y, double z) { 082 return new Position(world, x, y, z); 083 } 084 085 /** 086 * The world the position is in 087 * 088 * @return the world where the position is 089 */ 090 public World world() { 091 return this.world; 092 } 093 094 /** 095 * Chunk of the current position 096 * 097 * @return Chunk of the position 098 */ 099 public Chunk chunk() { 100 return world.chunkAt((int) x >> 4, (int) z >> 4, true); 101 } 102 103 /** 104 * Sets the position's world 105 * 106 * @param world the world to set the position to 107 */ 108 public void setWorld(World world) { 109 this.world = world; 110 } 111 112 /** 113 * The yaw of the position 114 * 115 * @return the yaw of this position 116 */ 117 public float yaw() { 118 return this.yaw; 119 } 120 121 /** 122 * Sets the yaw of the position 123 * 124 * @param yaw the yaw of the position to set 125 */ 126 public void setYaw(float yaw) { 127 this.yaw = yaw; 128 } 129 130 /** 131 * The pitch of the position 132 * 133 * @return the pitch value of this position 134 */ 135 public float pitch() { 136 return this.pitch; 137 } 138 139 /** 140 * Sets the pitch of the position 141 * 142 * @param pitch the pitch of the position to set 143 */ 144 public void setPitch(float pitch) { 145 this.pitch = pitch; 146 } 147 148 /** 149 * Adds the x, y, and z from the vector to the coordinates of this position 150 * 151 * @param vector the vector containing the relative data 152 * @return the relative position 153 */ 154 public Position add(Vector vector) { 155 this.setX(x() + vector.x()); 156 this.setY(y() + vector.y()); 157 this.setZ(z() + vector.z()); 158 159 return this; 160 } 161 162 /** 163 * Acquires the relative position to this set of coordinates 164 * 165 * @param vector the vector that has the x, y, and z of the position relative to this 166 * @return the relative position 167 */ 168 public Position relative(Vector vector) { 169 return new Position(this.world(), vector.x() + this.x(), vector.y() + this.y(), 170 vector.z() + this.z(), this.yaw(), this.pitch()); 171 } 172 173 /** 174 * Acquires the tile at this position 175 * 176 * @return the tile occupying the coordinates of this position 177 */ 178 public Block block() { 179 return world().blockAt(this); 180 } 181 182 /** 183 * Creates new Vector with Location's coordinates 184 * 185 * @return New Vector containing this Location's coordinates 186 */ 187 public Vector asVector() { 188 return new Vector(this.x(), this.y(), this.z()); 189 } 190 191 /** 192 * Obtains the unit vector pointing in the direction of the pitch and yaw 193 * 194 * @return the direction vector 195 */ 196 public Vector asUnitVector() { 197 // queerest calculations ever, apparently x goes towards 3pi/2 and z to 0...? 198 double x = -Math.cos(pitch) * Math.sin(yaw); 199 double y = -Math.sin(pitch); 200 double z = Math.cos(pitch) * Math.cos(yaw); 201 202 return new Vector(x, y, z); 203 } 204 205 /** 206 * The distance this from position to another. Math.sqrt is costly, ergo calling this method a lot is not advised. 207 * 208 * @param position the position to measure distance with 209 * @return distance from this position to another 210 */ 211 public double distance(Position position) { 212 return Math.sqrt(this.distanceSquared(position)); 213 } 214 215 /** 216 * The distance squared from this position to another 217 * 218 * @param position the position to measure distance with 219 * @return distance squared from this position to another 220 */ 221 public double distanceSquared(Position position) { 222 Preconditions.checkNotNull(position, "Location cannot be null."); 223 if (!this.world().equals(position.world())) 224 return 0.0; 225 return square(this.x() - position.x()) + square(this.y() - position.y()) + 226 square(this.z() - position.z()); 227 } 228 229 /** 230 * Convert the Pitch and Yaw to a Vectorized direction 231 * 232 * @return Vector of the direction of the position 233 */ 234 public Vector toDirection(){ 235 Vector vector = new Vector(); 236 double rotX = yaw; 237 double rotY = pitch; 238 double xz = Math.cos(Math.toRadians(rotY)); 239 vector.setY(-Math.sin(Math.toRadians(rotY))); 240 vector.setX(-xz * Math.sin(Math.toRadians(rotX))); 241 vector.setZ(xz * Math.cos(Math.toRadians(rotX))); 242 return vector; 243 } 244 245 @Override 246 public Position clone() { 247 return new Position(world, x, y, z(), yaw, pitch); 248 } 249 250 @Override 251 public boolean equals(Object obj) { 252 if (!(obj instanceof Position)) 253 return false; 254 if (obj.hashCode() != this.hashCode()) 255 return false; 256 if (x != ((Position) obj).x) { 257 return false; 258 } else if (y != ((Position) obj).y) { 259 return false; 260 } else if (z != ((Position) obj).z) { 261 return false; 262 } else if (world != ((Position) obj).world) { 263 return false; 264 } else if (pitch != ((Position) obj).pitch) { 265 return false; 266 } else if (yaw != ((Position) obj).yaw) { 267 return false; 268 } 269 270 return true; 271 } 272 273 @Override 274 public int hashCode() { 275 return Objects.hashCode(world, x, y, z, pitch, yaw); 276 } 277 278 @Override 279 public String toString(){ 280 return "Position{" + 281 "world=" + world + 282 ", x=" + x + 283 ", y=" + y + 284 ", z=" + z + 285 ", yaw=" + yaw + 286 ", pitch=" + pitch + 287 '}'; 288 } 289}