mirror of
https://github.com/tengge1/ShadowEditor.git
synced 2025-12-08 19:26:19 +00:00
537 lines
10 KiB
Go
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
|
|
}
|