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.util;
019
020import com.google.common.base.Objects;
021import net.tridentsdk.base.Position;
022import net.tridentsdk.world.World;
023
024import javax.annotation.concurrent.ThreadSafe;
025import java.io.Serializable;
026
027/**
028 * Just like in math, a vector represents magnitude and direction, where magnitude is usually the speed of an entity.
029 *
030 * <p>This class is essentially just 3 arbitrary values</p>
031 *
032 * @author The TridentSDK Team
033 * @since 0.3-alpha-DP
034 */
035@ThreadSafe
036public class Vector implements Serializable, Cloneable {
037    private static final long serialVersionUID = -7634050835106851288L;
038
039    protected volatile double x;
040    protected volatile double y;
041    protected volatile double z;
042
043    /**
044     * Creates a default vector with x, y, and z set to (0, 0, 0)
045     */
046    public Vector() {
047        this(0, 0, 0);
048    }
049
050    /**
051     * Creates a vector with the directional values set to the provided values
052     *
053     * @param x the x value of the vector
054     * @param y the y value of the vector
055     * @param z the z value of the vector
056     */
057    public Vector(double x, double y, double z) {
058        this.setX(x);
059        this.setY(y);
060        this.setZ(z);
061    }
062
063    /**
064     * Creates a vector with the directional values set to the provided values
065     *
066     * @param x the x value of the vector
067     * @param y the y value of the vector
068     * @param z the z value of the vector
069     */
070    public Vector(int x, int y, int z) {
071        this.setX((double) x);
072        this.setY((double) y);
073        this.setZ((double) z);
074    }
075
076    /**
077     * Adds the vector x, y, and z to the current vector coordinates
078     *
079     * @param vector the vector to retrieve the values to be added
080     * @return the current vector with updated coordinates
081     */
082    public Vector add(Vector vector) {
083        return this.add(vector.x(), vector.y(), vector.z());
084    }
085
086    /**
087     * Adds the coordinate values to the current vector's coordinates with double accuracy
088     *
089     * @param x the x value of the vector to add
090     * @param y the y value of the vector to add
091     * @param z the z value of the vector to add
092     * @return the current vector with updated coordinates
093     */
094    public Vector add(double x, double y, double z) {
095        this.setX(this.x() + x);
096        this.setY(this.y() + y);
097        this.setZ(this.z() + z);
098
099        return this;
100    }
101
102    /**
103     * Adds the coordinate values to the current vector's coordinates
104     *
105     * @param x the x value of the vector to add
106     * @param y the y value of the vector to add
107     * @param z the z value of the vector to add
108     * @return the current vector with updated coordinates
109     */
110    public Vector add(int x, int y, int z) {
111        return this.add((double) x, (double) y, (double) z);
112        /* Implementation detail:
113        DO NOT CREATE A NEW VECTOR HERE JUST BECAUSE (!)
114        Doing so wastes memory and adds unnecessary object
115        creation overhead, therefore, delegate to the
116        setters instead of the previous implementation.
117        Same with the other methods */
118    }
119
120    /**
121     * Takes the current vector coordinates and subtract them with the vector x, y, and z
122     *
123     * @param vector the vector to retrieve the values to be subtracted
124     * @return the current vector with updated coordinates
125     */
126    public Vector subtract(Vector vector) {
127        return this.subtract(vector.x(), vector.y(), vector.z());
128    }
129
130    /**
131     * Takes the the current vector's coordinates and subtracts them from the coordinate values with double accuracy
132     *
133     * @param x the x value of the vector to subtract
134     * @param y the y value of the vector to subtract
135     * @param z the z value of the vector to subtract
136     * @return the current vector with updated coordinates
137     */
138    public Vector subtract(double x, double y, double z) {
139        this.setX(this.x() - x);
140        this.setY(this.y() - y);
141        this.setZ(this.z() - z);
142
143        return this;
144    }
145
146    /**
147     * Takes the the current vector's coordinates and subtracts them from the coordinate values
148     *
149     * @param x the x value of the vector to subtract
150     * @param y the y value of the vector to subtract
151     * @param z the z value of the vector to subtract
152     * @return the current vector with updated coordinates
153     */
154    public Vector subtract(int x, int y, int z) {
155        return this.subtract((double) x, (double) y, (double) z);
156    }
157
158    /**
159     * Multiplies the vector x, y, and z to the current vector coordinates
160     *
161     * @param vec the vector to retrieve the values to be multiplied
162     * @return the current vector with updated coordinates
163     */
164    public Vector multiply(Vector vec) {
165        return this.multiply(vec.x(), vec.y(), vec.z());
166    }
167
168    /**
169     * Multiplies the magnitude of this vector by a double
170     *
171     * @param amount The amount to multiply by
172     * @return This vector, with updated coordinates
173     */
174    public Vector multiply(double amount) {
175        return this.multiply(amount, amount, amount);
176    }
177
178    /**
179     * Multiplies the coordinate values to the current vector's coordinates with double accuracy
180     *
181     * @param x the x value of the vector to multiply
182     * @param y the y value of the vector to multiply
183     * @param z the z value of the vector to multiply
184     * @return the current vector with updated coordinates
185     */
186    public Vector multiply(double x, double y, double z) {
187        this.setX(this.x() * x);
188        this.setY(this.y() * y);
189        this.setZ(this.z() * z);
190
191        return this;
192    }
193
194    /**
195     * Multiplies the coordinate values to the current vector's coordinates
196     *
197     * @param x the x value of the vector to multiply
198     * @param y the y value of the vector to multiply
199     * @param z the z value of the vector to multiply
200     * @return the current vector with updated coordinates
201     */
202    public Vector multiply(int x, int y, int z) {
203        return this.multiply((double) x, (double) y, (double) z);
204    }
205
206    /**
207     * Takes the current vector coordinates and divide them with the vector x, y, and z
208     *
209     * @param vec the vector to retrieve the values to be divided
210     * @return the current vector with updated coordinates
211     */
212    public Vector divide(Vector vec) {
213        return this.divide(vec.x(), vec.y(), vec.z());
214    }
215
216    /**
217     * Divides the magnitude of this vector by a given amount.
218     *
219     * @param amount The amount to divide by
220     * @return this vector
221     */
222    public Vector divide(double amount) {
223        return this.divide(amount, amount, amount);
224    }
225
226    /**
227     * Takes the the current vector's coordinates and divides them from the coordinate values with double accuracy
228     *
229     * @param x the x value of the vector to divide
230     * @param y the y value of the vector to divide
231     * @param z the z value of the vector to divide
232     * @return the current vector with updated coordinates
233     */
234    public Vector divide(double x, double y, double z) {
235        this.setX(this.x() / x);
236        this.setY(this.y() / y);
237        this.setZ(this.z() / z);
238
239        return this;
240    }
241
242    /**
243     * Takes the the current vector's coordinates and divides them from the coordinate values
244     *
245     * @param x the x value of the vector to divide
246     * @param y the y value of the vector to divide
247     * @param z the z value of the vector to divide
248     * @return the current vector with updated coordinates
249     */
250    public Vector divide(int x, int y, int z) {
251        return this.divide((double) x, (double) y, (double) z);
252    }
253
254    /**
255     * Sets the current vector to the crossproduct between this vector and another one
256     *
257     * @param vector the vector to crossproduct with
258     * @return this vector, updated with the crossproduct with the other vector
259     */
260    public Vector crossProduct(Vector vector) {
261        double x = this.x;
262        double y = this.y;
263        double z = this.z;
264
265        this.setX(y * vector.z() - vector.y() * z);
266        this.setY(z * vector.x() - vector.z() - x);
267        this.setZ(x * vector.y() - vector.x() * y);
268
269        return this;
270    }
271
272    /**
273     * Gets the square of the magnitude of this vector
274     *
275     * @return The magnitude of this vector, squared
276     */
277    public double magnitudeSquared() {
278        return this.x * this.x + this.y * this.y + this.z * this.z;
279    }
280
281    /**
282     * Gets the magnitude for this vector  Note that this is an expensive operation, and if possible, you should use
283     * magnitudeSquared() instead
284     *
285     * @return The magnitude of this vector
286     */
287    public double magnitude() {
288        return Math.sqrt(this.magnitudeSquared());
289    }
290
291    /**
292     * Normalizes this vector (changes the magnitude to 1 without changing the direction)
293     *
294     * @return This vector
295     */
296    public Vector normalize() {
297        return this.divide(this.magnitude());
298    }
299
300    /**
301     * Calculates the dot product of this vector and another
302     *
303     * @param vec the other vector
304     * @return dot product of the two vectors
305     */
306    public double dotProduct(Vector vec) {
307        return this.x * vec.x + this.y * vec.y + this.z * vec.z;
308    }
309
310    /**
311     * Returns a new position in this world, with the coordinates the x, y, and z values
312     */
313    public Position asLocation(World world) {
314        return Position.create(world, this.x, this.y, this.z);
315    }
316
317    /**
318     * Gets the x directional-magnitude value
319     *
320     * @return the vector x value
321     */
322    public double x() {
323        return this.x;
324    }
325
326    /**
327     * Sets this vector's x value
328     *
329     * @param x the x value to set this vector
330     */
331    public void setX(double x) {
332        this.x = x;
333    }
334
335    /**
336     * Gets the y directional-magnitude value
337     *
338     * @return the vector y value
339     */
340    public double y() {
341        return this.y;
342    }
343
344    /**
345     * Sets this vector's y value
346     *
347     * @param y the y value to set this vector
348     */
349    public void setY(double y) {
350        this.y = y;
351    }
352
353    /**
354     * Gets the z directional-magnitude value
355     *
356     * @return the vector z value
357     */
358    public double z() {
359        return this.z;
360    }
361
362    /**
363     * Sets this vector's z value
364     *
365     * @param z the z value to set this vector
366     */
367    public void setZ(double z) {
368        this.z = z;
369    }
370
371    /**
372     * Clones this Vector.
373     *
374     * @return the cloned vector
375     */
376    @Override
377    public Vector clone() {
378        try {
379            return (Vector) super.clone();
380        } catch (CloneNotSupportedException e) {
381            return null;
382        }
383    }
384
385    @Override
386    public boolean equals(Object obj) {
387        if (!(obj instanceof Vector))
388            return false;
389        if (obj.hashCode() != this.hashCode())
390            return false;
391        if (x != ((Vector) obj).x) {
392            return false;
393        } else if (y != ((Vector) obj).y) {
394            return false;
395        } else if (z != ((Vector) obj).z) {
396            return false;
397        }
398
399        return true;
400    }
401
402    @Override
403    public int hashCode() {
404        return Objects.hashCode(x, y, z);
405    }
406
407    @Override
408    public String toString(){
409        return "Vector{" +
410                "x=" + x +
411                ", y=" + y +
412                ", z=" + z +
413                '}';
414    }
415}