/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2017 Sri Harsha Chilakapati
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.shc.silenceengine.math;
import com.shc.silenceengine.utils.MathUtils;
import com.shc.silenceengine.utils.ReusableStack;
/**
* @author Sri Harsha Chilakapati
*/
public class Vector2
{
public static final Vector2 ZERO = new Vector2(0, 0);
public static final Vector2 AXIS_X = new Vector2(1, 0);
public static final Vector2 AXIS_Y = new Vector2(0, 1);
public static final Vector2 LEFT = new Vector2(AXIS_X).negate();
public static final Vector2 RIGHT = new Vector2(AXIS_X);
public static final Vector2 UP = new Vector2(AXIS_Y).negate();
public static final Vector2 DOWN = new Vector2(AXIS_Y);
public static final ReusableStack<Vector2> REUSABLE_STACK = new ReusableStack<>(Vector2::new);
public float x, y;
public Vector2()
{
this(0, 0);
}
public Vector2(float x, float y)
{
this.x = x;
this.y = y;
}
public Vector2(float v)
{
this(v, v);
}
public Vector2(Vector2 v)
{
this(v.x, v.y);
}
public Vector2(Vector3 v)
{
this(v.x, v.y);
}
public Vector2(Vector4 v)
{
this(v.x, v.y);
}
public Vector2 add(Vector2 v)
{
return add(v.x, v.y);
}
public Vector2 add(float x, float y)
{
return set(this.x + x, this.y + y);
}
public Vector2 set(float x, float y)
{
this.x = x;
this.y = y;
return this;
}
public Vector2 normalize()
{
float l = length();
if (l == 0 || l == 1)
return this;
return set(x / l, y / l);
}
public Vector2 copy()
{
return new Vector2(this);
}
public float length()
{
return (float) Math.sqrt(lengthSquared());
}
public float lengthSquared()
{
return x * x + y * y;
}
public Vector2 rotate(float angle)
{
float cos = MathUtils.cos(angle);
float sin = MathUtils.sin(angle);
return set(x * cos - y * sin, x * sin + y * cos);
}
public Vector2 negate()
{
return set(-x, -y);
}
public float angle()
{
return MathUtils.atan2(y, x);
}
public float angle(Vector2 v)
{
return MathUtils.atan2(y - v.y, x - v.x);
}
public float dot(Vector2 v)
{
return dot(v.x, v.y);
}
public float dot(float x, float y)
{
return this.x * x + this.y * y;
}
public float distance(Vector2 v)
{
return (float) Math.sqrt(distanceSquared(v));
}
public float distanceSquared(Vector2 v)
{
return (v.x - x) * (v.x - x) + (v.y - y) * (v.y - y);
}
public Vector2 lerp(Vector2 target, float alpha)
{
final float oneMinusAlpha = 1f - alpha;
float x = (this.x * oneMinusAlpha) + (target.x * alpha);
float y = (this.y * oneMinusAlpha) + (target.y * alpha);
return set(x, y);
}
public Vector2 perpendicular()
{
return set(y, -x);
}
public Vector2 project(Vector2 v)
{
return scale(dot(v) / v.lengthSquared());
}
public Vector2 project(Vector2 v, Vector2 dest)
{
return dest.set(this).project(v);
}
public Vector2 scale(float s)
{
return scale(s, s);
}
public Vector2 scale(float sx, float sy)
{
return set(x * sx, y * sy);
}
public Vector2 reflect(Vector2 axis)
{
Vector2 temp = REUSABLE_STACK.pop();
set(temp.set(this).project(axis).scale(2).subtract(this));
REUSABLE_STACK.push(temp);
return this;
}
public Vector2 reflect(Vector2 axis, Vector2 dest)
{
return dest.set(this).reflect(axis);
}
public float zCross(Vector2 other)
{
return x * other.y - y * other.x;
}
public Vector2 set(Vector2 v)
{
return set(v.x, v.y);
}
public Vector2 subtract(Vector2 v)
{
return subtract(v.x, v.y);
}
public Vector2 subtract(float x, float y)
{
return add(-x, -y);
}
public Vector2 set(float v)
{
return set(v, v);
}
@Override
public int hashCode()
{
int result = (x != +0.0f ? Float.floatToIntBits(x) : 0);
result = 31 * result + (y != +0.0f ? Float.floatToIntBits(y) : 0);
return result;
}
@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Vector2 vector2 = (Vector2) o;
return Float.compare(vector2.x, x) == 0 &&
Float.compare(vector2.y, y) == 0;
}
@Override
public String toString()
{
return "[" + x + ", " + y + "]";
}
}