1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2026-05-09 14:49:10 -04:00
Files
OpenDiablo2/d2common/d2math/vector2.go
Ian 0dee6518b4 WIP: Add checkboxes, de-lint ecs branch (#1017)
* Add checkboxes, checkbox test scene

* De-lint ecs branch
2021-01-04 00:43:56 -08:00

226 lines
6.0 KiB
Go

package d2math
import "math"
// Vector2Like is something that has an XY method that returns x and y coordinate values
type Vector2Like interface {
XY() (float64, float64)
}
// static check that Vector2 is Vector2Like
var _ Vector2Like = &Vector2{}
// NewVector2 creates a new Vector2
func NewVector2(x, y float64) *Vector2 {
return &Vector2{
X: x,
Y: y,
}
}
// Vector2 is a representation of a vector in 2D space.
type Vector2 struct {
X, Y float64
}
// XY returns the x and y values
func (v *Vector2) XY() (x, y float64) {
return v.X, v.Y
}
// Clone makes a clone of this Vector2.
func (v *Vector2) Clone() *Vector2 {
return NewVector2(v.X, v.Y)
}
// Copy copies the values from the given vector into this vector
func (v *Vector2) Copy(source *Vector2) *Vector2 {
return v.Set(source.X, source.Y)
}
// SetFromVectorLike sets the x, y values of this Vector from a given Vector2Like object.
func (v *Vector2) SetFromVectorLike(l Vector2Like) *Vector2 {
return v.Set(l.XY())
}
// Set the `x` and `y` components of the this Vector to the given `x` and `y` values.
func (v *Vector2) Set(x, y float64) *Vector2 {
v.X, v.Y = x, y
return v
}
// SetTo is an alias for `Vector2.Set`.
func (v *Vector2) SetTo(x, y float64) *Vector2 {
return v.Set(x, y)
}
// SetToPolar sets the `x` and `y` values of this object from a given polar coordinate.
func (v *Vector2) SetToPolar(azimuth, radius float64) *Vector2 {
return v.Set(math.Cos(azimuth)*radius, math.Sin(azimuth)*radius)
}
// Equals checks whether this Vector is equal to a given Vector.
func (v *Vector2) Equals(other *Vector2) bool {
return math.Abs(v.X-other.X) < Epsilon && math.Abs(v.Y-other.Y) < Epsilon
}
// Angle calculates the angle between this Vector and the positive x-v.Xis, in radians.
func (v *Vector2) Angle() float64 {
angle := math.Atan2(v.XY())
if angle < 0 {
angle = PI2
}
return angle
}
// SetAngle sets the angle of this Vector.
func (v *Vector2) SetAngle(angle float64) *Vector2 {
return v.SetToPolar(angle, v.Length())
}
// Add the given Vector to this Vector.
// Addition is component-wise and mutates the vector.
func (v *Vector2) Add(source *Vector2) *Vector2 {
return v.Set(v.X+source.X, v.Y+source.Y)
}
// Subtract the given Vector from this Vector.
// Subtraction is component-wise and mutates the vector.
func (v *Vector2) Subtract(source *Vector2) *Vector2 {
return v.Set(v.X-source.X, v.Y-source.Y)
}
// Multiply this vector with the given Vector.
// Multiplication is component-wise and mutates the vector.
func (v *Vector2) Multiply(source *Vector2) *Vector2 {
return v.Set(v.X*source.X, v.Y*source.Y)
}
// Scale this Vector with a scalar.
// Multiplication is component-wise and mutates the vector.
func (v *Vector2) Scale(scalar float64) *Vector2 {
return v.Set(v.X*scalar, v.Y*scalar)
}
// Divide this vector by the given Vector.
// Division is component-wise and mutates the vector.
func (v *Vector2) Divide(source *Vector2) *Vector2 {
return v.Set(v.X/source.X, v.Y/source.Y)
}
// Negate the x/y values of this vector.
func (v *Vector2) Negate() *Vector2 {
return v.Set(-v.X, -v.Y)
}
// Distance calculate the distance between this Vector and the given Vector.
func (v *Vector2) Distance(source *Vector2) float64 {
return math.Sqrt(v.DistanceSquared(source))
}
// DistanceSquared calculate the distance squared between this Vector and the given Vector.
func (v *Vector2) DistanceSquared(source *Vector2) float64 {
dx, dy := source.X-v.X, source.Y-v.Y
return dx*dx + dy*dy
}
// Length calculates the length (or magnitude) of this Vector.
func (v *Vector2) Length() float64 {
return math.Sqrt(v.LengthSquared())
}
// LengthSquared calculates the length squared of this Vector.
func (v *Vector2) LengthSquared() float64 {
return v.X*v.X + v.Y*v.Y
}
// SetLength sets the length of the vector and returns the length (or magnitude) of this Vector.
func (v *Vector2) SetLength(l float64) *Vector2 {
return v.Normalize().Scale(l)
}
// Normalize this Vector to length of 1
func (v *Vector2) Normalize() *Vector2 {
l := v.Length()
if l > 0 {
l = 1 / math.Sqrt(l)
v.Scale(l)
}
return v
}
// NormalizeRightHand rotates this Vector to its perpendicular, in the positive direction.
func (v *Vector2) NormalizeRightHand() *Vector2 {
return v.Set(v.Y*-1, v.X)
}
// NormalizeLeftHand rotates this Vector to its perpendicular, in the negative direction.
func (v *Vector2) NormalizeLeftHand() *Vector2 {
return v.Set(v.Y, v.X*-1)
}
// Dot calculate the dot product of this Vector and the given Vector.
func (v *Vector2) Dot(other *Vector2) float64 {
return v.X*other.X + v.Y + other.Y
}
// Cross calculate the dot product of this Vector and the given Vector.
func (v *Vector2) Cross(other *Vector2) float64 {
return v.X*other.X - v.Y + other.Y
}
// Lerp linearly interpolates between this Vector and the given Vector.
func (v *Vector2) Lerp(other *Vector2, t float64) *Vector2 {
return v.Set(v.X+t*(other.X-v.X), v.Y+t*(other.Y-v.Y))
}
// TransformMat3 transforms this Vector with the given Matrix3.
func (v *Vector2) TransformMat3(m3 *Matrix3) *Vector2 {
m := m3.Values
return v.Set(m[0]*v.X+m[3]*v.Y+m[6], m[1]*v.X+m[4]*v.Y+m[7])
}
// TransformMat4 transforms this Vector with the given Matrix4.
func (v *Vector2) TransformMat4(m4 *Matrix4) *Vector2 {
m := m4.Values
return v.Set(m[0]*v.X+m[4]*v.Y+m[12], m[1]*v.X+m[5]*v.Y+m[13])
}
// Reset makes this Vector the zero vector (0, 0).
func (v *Vector2) Reset() *Vector2 {
return v.Set(0, 0)
}
// Limit the length (or magnitude) of this Vector.
func (v *Vector2) Limit(l float64) *Vector2 {
if v.Length() > l {
v.SetLength(l)
}
return v
}
// Reflect this Vector off a line defined by a normal.
//nolint:gomnd // math
func (v *Vector2) Reflect(other *Vector2) *Vector2 {
normal := other.Clone().Normalize()
return v.Subtract(normal.Scale(2 * v.Dot(normal)))
}
// Mirror reflects this Vector across another.
func (v *Vector2) Mirror(axis *Vector2) *Vector2 {
return v.Reflect(axis).Negate()
}
// Rotate this Vector by an angle amount.
func (v *Vector2) Rotate(radians float64) *Vector2 {
c, s := math.Cos(radians), math.Sin(radians)
return v.Set(c*v.X-s*v.Y, s*v.X+c*v.Y)
}