mirror of
https://github.com/genxium/DelayNoMore
synced 2024-12-27 12:08:21 +00:00
282 lines
5.3 KiB
Go
282 lines
5.3 KiB
Go
|
package resolv
|
||
|
|
||
|
import (
|
||
|
"math"
|
||
|
)
|
||
|
|
||
|
// Vector is the definition of a row vector that contains scalars as
|
||
|
// 64 bit floats
|
||
|
type Vector []float64
|
||
|
|
||
|
// Axis is an integer enum type that describes vector axis
|
||
|
type Axis int
|
||
|
|
||
|
const (
|
||
|
// the consts below are used to represent vector axis, they are useful
|
||
|
// to lookup values within the vector.
|
||
|
X Axis = iota
|
||
|
Y
|
||
|
Z
|
||
|
)
|
||
|
|
||
|
// Clone a vector
|
||
|
func Clone(v Vector) Vector {
|
||
|
return v.Clone()
|
||
|
}
|
||
|
|
||
|
// Clone a vector
|
||
|
func (v Vector) Clone() Vector {
|
||
|
clone := make(Vector, len(v))
|
||
|
copy(clone, v)
|
||
|
return clone
|
||
|
}
|
||
|
|
||
|
// Add a vector with a vector or a set of vectors
|
||
|
func Add(v1 Vector, vs ...Vector) Vector {
|
||
|
return v1.Clone().Add(vs...)
|
||
|
}
|
||
|
|
||
|
// Add a vector with a vector or a set of vectors
|
||
|
func (v Vector) Add(vs ...Vector) Vector {
|
||
|
dim := len(v)
|
||
|
|
||
|
for i := range vs {
|
||
|
if len(vs[i]) > dim {
|
||
|
axpyUnitaryTo(v, 1, v, vs[i][:dim])
|
||
|
} else {
|
||
|
axpyUnitaryTo(v, 1, v, vs[i])
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return v
|
||
|
}
|
||
|
|
||
|
// Sub subtracts a vector with another vector or a set of vectors
|
||
|
func Sub(v1 Vector, vs ...Vector) Vector {
|
||
|
return v1.Clone().Sub(vs...)
|
||
|
}
|
||
|
|
||
|
// Sub subtracts a vector with another vector or a set of vectors
|
||
|
func (v Vector) Sub(vs ...Vector) Vector {
|
||
|
dim := len(v)
|
||
|
|
||
|
for i := range vs {
|
||
|
if len(vs[i]) > dim {
|
||
|
axpyUnitaryTo(v, -1, vs[i][:dim], v)
|
||
|
} else {
|
||
|
axpyUnitaryTo(v, -1, vs[i], v)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return v
|
||
|
}
|
||
|
|
||
|
// Scale vector with a given size
|
||
|
func Scale(v Vector, size float64) Vector {
|
||
|
return v.Clone().Scale(size)
|
||
|
}
|
||
|
|
||
|
// Scale vector with a given size
|
||
|
func (v Vector) Scale(size float64) Vector {
|
||
|
scalUnitaryTo(v, size, v)
|
||
|
return v
|
||
|
}
|
||
|
|
||
|
// Equal compares that two vectors are equal to each other
|
||
|
func Equal(v1, v2 Vector) bool {
|
||
|
return v1.Equal(v2)
|
||
|
}
|
||
|
|
||
|
// Equal compares that two vectors are equal to each other
|
||
|
func (v Vector) Equal(v2 Vector) bool {
|
||
|
if len(v) != len(v2) {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
for i := range v {
|
||
|
if math.Abs(v[i]-v2[i]) > 1e-8 {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
// Magnitude of a vector
|
||
|
func Magnitude(v Vector) float64 {
|
||
|
return v.Magnitude()
|
||
|
}
|
||
|
|
||
|
// Magnitude of a vector
|
||
|
func (v Vector) Magnitude() float64 {
|
||
|
return math.Sqrt(v.Magnitude2())
|
||
|
}
|
||
|
|
||
|
func (v Vector) Magnitude2() float64 {
|
||
|
var result float64
|
||
|
|
||
|
for _, scalar := range v {
|
||
|
result += scalar * scalar
|
||
|
}
|
||
|
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
// Unit returns a direction vector with the length of one.
|
||
|
func Unit(v Vector) Vector {
|
||
|
return v.Clone().Unit()
|
||
|
}
|
||
|
|
||
|
// Unit returns a direction vector with the length of one.
|
||
|
func (v Vector) Unit() Vector {
|
||
|
l := v.Magnitude()
|
||
|
|
||
|
if l < 1e-8 {
|
||
|
return v
|
||
|
}
|
||
|
|
||
|
for i := range v {
|
||
|
v[i] = v[i] / l
|
||
|
}
|
||
|
|
||
|
return v
|
||
|
}
|
||
|
|
||
|
// Dot product of two vectors
|
||
|
func Dot(v1, v2 Vector) float64 {
|
||
|
result, dim1, dim2 := 0., len(v1), len(v2)
|
||
|
|
||
|
if dim1 > dim2 {
|
||
|
v2 = append(v2, make(Vector, dim1-dim2)...)
|
||
|
}
|
||
|
|
||
|
if dim1 < dim2 {
|
||
|
v1 = append(v1, make(Vector, dim2-dim1)...)
|
||
|
}
|
||
|
|
||
|
for i := range v1 {
|
||
|
result += v1[i] * v2[i]
|
||
|
}
|
||
|
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
// Dot product of two vectors
|
||
|
func (v Vector) Dot(v2 Vector) float64 {
|
||
|
return Dot(v, v2)
|
||
|
}
|
||
|
|
||
|
// Cross product of two vectors
|
||
|
func Cross(v1, v2 Vector) Vector {
|
||
|
return v1.Cross(v2)
|
||
|
}
|
||
|
|
||
|
// Cross product of two vectors
|
||
|
func (v Vector) Cross(v2 Vector) Vector {
|
||
|
if len(v) != 3 || len(v2) != 3 {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
return Vector{
|
||
|
v[Y]*v2[Z] - v[Z]*v2[Y],
|
||
|
v[Z]*v2[X] - v[X]*v2[Z],
|
||
|
v[X]*v2[Z] - v[Z]*v2[X],
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Rotate is rotating a vector around a specified axis.
|
||
|
// If no axis are specified, it will default to the Z axis.
|
||
|
//
|
||
|
// If a vector with more than 3-dimensions is rotated, it will cut the extra
|
||
|
// dimensions and return a 3-dimensional vector.
|
||
|
//
|
||
|
// NOTE: the ...Axis is just syntactic sugar that allows the axis to not be
|
||
|
// specified and default to Z, if multiple axis is passed the first will be
|
||
|
// set as the rotation axis
|
||
|
func Rotate(v Vector, angle float64, as ...Axis) Vector {
|
||
|
return v.Clone().Rotate(angle, as...)
|
||
|
}
|
||
|
|
||
|
// Rotate is rotating a vector around a specified axis.
|
||
|
// If no axis are specified, it will default to the Z axis.
|
||
|
//
|
||
|
// If a vector with more than 3-dimensions is rotated, it will cut the extra
|
||
|
// dimensions and return a 3-dimensional vector.
|
||
|
//
|
||
|
// NOTE: the ...Axis is just syntactic sugar that allows the axis to not be
|
||
|
// specified and default to Z, if multiple axis is passed the first will be
|
||
|
// set as the rotation axis
|
||
|
func (v Vector) Rotate(angle float64, as ...Axis) Vector {
|
||
|
axis, dim := Z, len(v)
|
||
|
|
||
|
if dim == 0 {
|
||
|
return v
|
||
|
}
|
||
|
|
||
|
if len(as) > 0 {
|
||
|
axis = as[0]
|
||
|
}
|
||
|
|
||
|
if dim == 1 && axis != Z {
|
||
|
v = append(v, 0, 0)
|
||
|
}
|
||
|
|
||
|
if (dim < 2 && axis == Z) || (dim == 2 && axis != Z) {
|
||
|
v = append(v, 0)
|
||
|
}
|
||
|
|
||
|
x, y := v[X], v[Y]
|
||
|
|
||
|
cos, sin := math.Cos(angle), math.Sin(angle)
|
||
|
|
||
|
switch axis {
|
||
|
case X:
|
||
|
z := v[Z]
|
||
|
v[Y] = y*cos - z*sin
|
||
|
v[Z] = y*sin + z*cos
|
||
|
case Y:
|
||
|
z := v[Z]
|
||
|
v[X] = x*cos + z*sin
|
||
|
v[Z] = -x*sin + z*cos
|
||
|
case Z:
|
||
|
v[X] = x*cos - y*sin
|
||
|
v[Y] = x*sin + y*cos
|
||
|
}
|
||
|
|
||
|
if dim > 3 {
|
||
|
return v[:3]
|
||
|
}
|
||
|
|
||
|
return v
|
||
|
}
|
||
|
|
||
|
// X is corresponding to doing a v[0] lookup, if index 0 does not exist yet, a
|
||
|
// 0 will be returned instead
|
||
|
func (v Vector) X() float64 {
|
||
|
if len(v) < 1 {
|
||
|
return 0.
|
||
|
}
|
||
|
|
||
|
return v[X]
|
||
|
}
|
||
|
|
||
|
// Y is corresponding to doing a v[1] lookup, if index 1 does not exist yet, a
|
||
|
// 0 will be returned instead
|
||
|
func (v Vector) Y() float64 {
|
||
|
if len(v) < 2 {
|
||
|
return 0.
|
||
|
}
|
||
|
|
||
|
return v[Y]
|
||
|
}
|
||
|
|
||
|
// Z is corresponding to doing a v[2] lookup, if index 2 does not exist yet, a
|
||
|
// 0 will be returned instead
|
||
|
func (v Vector) Z() float64 {
|
||
|
if len(v) < 3 {
|
||
|
return 0.
|
||
|
}
|
||
|
|
||
|
return v[Z]
|
||
|
}
|