2020-06-13 21:40:56 +08:00

537 lines
10 KiB
Go

// Copyright 2017-2020 The ShadowEditor Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
//
// For more information, please visit: https://github.com/tengge1/ShadowEditor
// You can also visit: https://gitee.com/tengge1/ShadowEditor
//
// This package is translated from three.js, visit `https://github.com/mrdoob/three.js`
// for more information.
package three
import (
"math"
"math/rand"
"strconv"
)
// NewVector4 :
func NewVector4(x, y, z, w float64) *Vector4 {
return &Vector4{x, y, z, w}
}
// Vector4 :
type Vector4 struct {
X float64
Y float64
Z float64
W float64
}
// Width :
func (v Vector4) Width() float64 {
return v.Z
}
// SetWidth :
func (v Vector4) SetWidth(value float64) *Vector4 {
v.Z = value
return &v
}
// Height :
func (v Vector4) Height() float64 {
return v.W
}
// SetHeight :
func (v Vector4) SetHeight(value float64) *Vector4 {
v.W = value
return &v
}
// Set :
func (v Vector4) Set(x, y, z, w float64) *Vector4 {
v.X = x
v.Y = y
v.Z = z
v.W = w
return &v
}
// SetScalar :
func (v Vector4) SetScalar(scalar float64) *Vector4 {
v.X = scalar
v.Y = scalar
v.Z = scalar
v.W = scalar
return &v
}
// SetX :
func (v Vector4) SetX(x float64) *Vector4 {
v.X = x
return &v
}
// SetY :
func (v Vector4) SetY(y float64) *Vector4 {
v.Y = y
return &v
}
// SetZ :
func (v Vector4) SetZ(z float64) *Vector4 {
v.Z = z
return &v
}
// SetW :
func (v Vector4) SetW(w float64) *Vector4 {
v.W = w
return &v
}
// SetComponent :
func (v Vector4) SetComponent(index int, value float64) *Vector4 {
switch index {
default:
panic("index is out of range: " + strconv.Itoa(index))
case 0:
v.X = value
case 1:
v.Y = value
case 2:
v.Z = value
case 3:
v.W = value
}
return &v
}
// GetComponent :
func (v Vector4) GetComponent(index int) float64 {
switch index {
default:
panic("index is out of range: " + strconv.Itoa(index))
case 0:
return v.X
case 1:
return v.Y
case 2:
return v.Z
case 3:
return v.W
}
}
// Clone :
func (v Vector4) Clone() *Vector4 {
return NewVector4(v.X, v.Y, v.Z, v.W)
}
// Copy :
func (v Vector4) Copy(v1 Vector4) *Vector4 {
v.X = v1.X
v.Y = v1.Y
v.Z = v1.Z
v.W = v1.W
return &v
}
// Add :
func (v Vector4) Add(v1 Vector4) *Vector4 {
v.X += v1.X
v.Y += v1.Y
v.Z += v1.Z
v.W += v1.W
return &v
}
// AddScalar :
func (v Vector4) AddScalar(s float64) *Vector4 {
v.X += s
v.Y += s
v.Z += s
v.W += s
return &v
}
// AddVectors :
func (v Vector4) AddVectors(a, b Vector4) *Vector4 {
v.X = a.X + b.X
v.Y = a.Y + b.Y
v.Z = a.Z + b.Z
v.W = a.W + b.W
return &v
}
// AddScaledVector :
func (v Vector4) AddScaledVector(v1 Vector4, s float64) *Vector4 {
v.X += v1.X * s
v.Y += v1.Y * s
v.Z += v1.Z * s
v.W += v1.W * s
return &v
}
// Sub :
func (v Vector4) Sub(v1 Vector4) *Vector4 {
v.X -= v1.X
v.Y -= v1.Y
v.Z -= v1.Z
v.W -= v1.W
return &v
}
// SubScalar :
func (v Vector4) SubScalar(s float64) *Vector4 {
v.X -= s
v.Y -= s
v.Z -= s
v.W -= s
return &v
}
// SubVectors :
func (v Vector4) SubVectors(a, b Vector4) *Vector4 {
v.X = a.X - b.X
v.Y = a.Y - b.Y
v.Z = a.Z - b.Z
v.W = a.W - b.W
return &v
}
// MultiplyScalar :
func (v Vector4) MultiplyScalar(scalar float64) *Vector4 {
v.X *= scalar
v.Y *= scalar
v.Z *= scalar
v.W *= scalar
return &v
}
// ApplyMatrix4 :
func (v Vector4) ApplyMatrix4(m Matrix4) *Vector4 {
x, y, z, w := v.X, v.Y, v.Z, v.W
e := m.Elements
v.X = e[0]*x + e[4]*y + e[8]*z + e[12]*w
v.Y = e[1]*x + e[5]*y + e[9]*z + e[13]*w
v.Z = e[2]*x + e[6]*y + e[10]*z + e[14]*w
v.W = e[3]*x + e[7]*y + e[11]*z + e[15]*w
return &v
}
// DivideScalar :
func (v Vector4) DivideScalar(scalar float64) *Vector4 {
return v.MultiplyScalar(1 / scalar)
}
// SetAxisAngleFromQuaternion :
func (v Vector4) SetAxisAngleFromQuaternion(q Quaternion) *Vector4 {
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
// q is assumed to be normalized
v.W = 2 * math.Acos(q.W())
s := math.Sqrt(1 - q.W()*q.W())
if s < 0.0001 {
v.X = 1
v.Y = 0
v.Z = 0
} else {
v.X = q.X() / s
v.Y = q.Y() / s
v.Z = q.Z() / s
}
return &v
}
// SetAxisAngleFromRotationMatrix :
func (v Vector4) SetAxisAngleFromRotationMatrix(m Matrix4) *Vector4 {
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
var angle, x, y, z float64 // variables for result
epsilon := 0.01 // margin to allow for rounding errors
epsilon2 := 0.1 // margin to distinguish between 0 and 180 degrees
te := m.Elements
m11, m12, m13 := te[0], te[4], te[8]
m21, m22, m23 := te[1], te[5], te[9]
m31, m32, m33 := te[2], te[6], te[10]
if (math.Abs(m12-m21) < epsilon) &&
(math.Abs(m13-m31) < epsilon) &&
(math.Abs(m23-m32) < epsilon) {
// singularity found
// first check for identity matrix which must have +1 for all terms
// in leading diagonal and zero in other terms
if (math.Abs(m12+m21) < epsilon2) &&
(math.Abs(m13+m31) < epsilon2) &&
(math.Abs(m23+m32) < epsilon2) &&
(math.Abs(m11+m22+m33-3) < epsilon2) {
// v singularity is identity matrix so angle = 0
v.Set(1, 0, 0, 0)
return &v // zero angle, arbitrary axis
}
// otherwise v singularity is angle = 180
angle = math.Pi
xx := (m11 + 1) / 2
yy := (m22 + 1) / 2
zz := (m33 + 1) / 2
xy := (m12 + m21) / 4
xz := (m13 + m31) / 4
yz := (m23 + m32) / 4
if (xx > yy) && (xx > zz) {
// m11 is the largest diagonal term
if xx < epsilon {
x = 0
y = 0.707106781
z = 0.707106781
} else {
x = math.Sqrt(xx)
y = xy / x
z = xz / x
}
} else if yy > zz {
// m22 is the largest diagonal term
if yy < epsilon {
x = 0.707106781
y = 0
z = 0.707106781
} else {
y = math.Sqrt(yy)
x = xy / y
z = yz / y
}
} else {
// m33 is the largest diagonal term so base result on v
if zz < epsilon {
x = 0.707106781
y = 0.707106781
z = 0
} else {
z = math.Sqrt(zz)
x = xz / z
y = yz / z
}
}
v.Set(x, y, z, angle)
return &v // return 180 deg rotation
}
// as we have reached here there are no singularities so we can handle normally
s := math.Sqrt((m32-m23)*(m32-m23) +
(m13-m31)*(m13-m31) +
(m21-m12)*(m21-m12)) // used to normalize
if math.Abs(s) < 0.001 {
s = 1
}
// prevent divide by zero, should not happen if matrix is orthogonal and should be
// caught by singularity test above, but I've left it in just in case
v.X = (m32 - m23) / s
v.Y = (m13 - m31) / s
v.Z = (m21 - m12) / s
v.W = math.Acos((m11 + m22 + m33 - 1) / 2)
return &v
}
// Min :
func (v Vector4) Min(v1 Vector4) *Vector4 {
v.X = math.Min(v.X, v1.X)
v.Y = math.Min(v.Y, v1.Y)
v.Z = math.Min(v.Z, v1.Z)
v.W = math.Min(v.W, v1.W)
return &v
}
// Max :
func (v Vector4) Max(v1 Vector4) *Vector4 {
v.X = math.Max(v.X, v1.X)
v.Y = math.Max(v.Y, v1.Y)
v.Z = math.Max(v.Z, v1.Z)
v.W = math.Max(v.W, v1.W)
return &v
}
// Clamp :
func (v Vector4) Clamp(min, max Vector4) *Vector4 {
// assumes min < max, componentwise
v.X = math.Max(min.X, math.Min(max.X, v.X))
v.Y = math.Max(min.Y, math.Min(max.Y, v.Y))
v.Z = math.Max(min.Z, math.Min(max.Z, v.Z))
v.W = math.Max(min.W, math.Min(max.W, v.W))
return &v
}
// ClampScalar :
func (v Vector4) ClampScalar(minVal, maxVal float64) *Vector4 {
v.X = math.Max(minVal, math.Min(maxVal, v.X))
v.Y = math.Max(minVal, math.Min(maxVal, v.Y))
v.Z = math.Max(minVal, math.Min(maxVal, v.Z))
v.W = math.Max(minVal, math.Min(maxVal, v.W))
return &v
}
// ClampLength :
func (v Vector4) ClampLength(min, max float64) *Vector4 {
length := v.Length()
if length == 0 {
length = 1
}
return v.DivideScalar(length).MultiplyScalar(math.Max(min, math.Min(max, length)))
}
// Floor :
func (v Vector4) Floor() *Vector4 {
v.X = math.Floor(v.X)
v.Y = math.Floor(v.Y)
v.Z = math.Floor(v.Z)
v.W = math.Floor(v.W)
return &v
}
// Ceil :
func (v Vector4) Ceil() *Vector4 {
v.X = math.Ceil(v.X)
v.Y = math.Ceil(v.Y)
v.Z = math.Ceil(v.Z)
v.W = math.Ceil(v.W)
return &v
}
// Round :
func (v Vector4) Round() *Vector4 {
v.X = math.Round(v.X)
v.Y = math.Round(v.Y)
v.Z = math.Round(v.Z)
v.W = math.Round(v.W)
return &v
}
// RoundToZero :
func (v Vector4) RoundToZero() *Vector4 {
if v.X < 0 {
v.X = math.Ceil(v.X)
} else {
v.X = math.Floor(v.X)
}
if v.Y < 0 {
v.Y = math.Ceil(v.Y)
} else {
v.Y = math.Floor(v.Y)
}
if v.Z < 0 {
v.Z = math.Ceil(v.Z)
} else {
v.Z = math.Floor(v.Z)
}
if v.W < 0 {
v.W = math.Ceil(v.W)
} else {
v.W = math.Floor(v.W)
}
return &v
}
// Negate :
func (v Vector4) Negate() *Vector4 {
v.X = -v.X
v.Y = -v.Y
v.Z = -v.Z
v.W = -v.W
return &v
}
// Dot :
func (v Vector4) Dot(v1 Vector4) float64 {
return v.X*v1.X + v.Y*v1.Y + v.Z*v1.Z + v.W*v1.W
}
// LengthSq :
func (v Vector4) LengthSq() float64 {
return v.X*v.X + v.Y*v.Y + v.Z*v.Z + v.W*v.W
}
// Length :
func (v Vector4) Length() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y + v.Z*v.Z + v.W*v.W)
}
// ManhattanLength :
func (v Vector4) ManhattanLength() float64 {
return math.Abs(v.X) + math.Abs(v.Y) + math.Abs(v.Z) + math.Abs(v.W)
}
// Normalize :
func (v Vector4) Normalize() *Vector4 {
length := v.Length()
if length == 0 {
length = 1
}
return v.DivideScalar(length)
}
// SetLength :
func (v Vector4) SetLength(length float64) *Vector4 {
return v.Normalize().MultiplyScalar(length)
}
// Lerp :
func (v Vector4) Lerp(v1 Vector4, alpha float64) *Vector4 {
v.X += (v1.X - v.X) * alpha
v.Y += (v1.Y - v.Y) * alpha
v.Z += (v1.Z - v.Z) * alpha
v.W += (v1.W - v.W) * alpha
return &v
}
// LerpVectors :
func (v Vector4) LerpVectors(v1, v2 Vector4, alpha float64) *Vector4 {
v.X = v1.X + (v2.X-v1.X)*alpha
v.Y = v1.Y + (v2.Y-v1.Y)*alpha
v.Z = v1.Z + (v2.Z-v1.Z)*alpha
v.W = v1.W + (v2.W-v1.W)*alpha
return &v
}
// Equals :
func (v Vector4) Equals(v1 Vector4) bool {
return ((v1.X == v.X) && (v1.Y == v.Y) && (v1.Z == v.Z) && (v1.W == v.W))
}
// FromArray :
func (v Vector4) FromArray(array []float64, offset int) *Vector4 {
if len(array) < offset+4 {
panic("array length should be greater than offset+4")
}
v.X = array[offset]
v.Y = array[offset+1]
v.Z = array[offset+2]
v.W = array[offset+3]
return &v
}
// ToArray :
func (v Vector4) ToArray(array []float64, offset int) []float64 {
if len(array) < offset+4 {
panic("array length should be greater than offset+4")
}
array[offset] = v.X
array[offset+1] = v.Y
array[offset+2] = v.Z
array[offset+3] = v.W
return array
}
// Random :
func (v Vector4) Random() *Vector4 {
v.X = rand.Float64()
v.Y = rand.Float64()
v.Z = rand.Float64()
v.W = rand.Float64()
return &v
}