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

651 lines
12 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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"
)
// NewVector3 :
func NewVector3(x, y, z float64) *Vector3 {
return &Vector3{x, y, z, true}
}
// Vector3 :
type Vector3 struct {
X float64
Y float64
Z float64
IsVector3 bool
}
var _vector3 = NewVector3(0, 0, 0)
var _quaternionV3 = NewQuaternion(0, 0, 0, 1)
// Set :
func (v Vector3) Set(x, y, z float64) *Vector3 {
v.X = x
v.Y = y
v.Z = z
return &v
}
// SetScalar :
func (v Vector3) SetScalar(scalar float64) *Vector3 {
v.X = scalar
v.Y = scalar
v.Z = scalar
return &v
}
// SetX :
func (v Vector3) SetX(x float64) *Vector3 {
v.X = x
return &v
}
// SetY :
func (v Vector3) SetY(y float64) *Vector3 {
v.Y = y
return &v
}
// SetZ :
func (v Vector3) SetZ(z float64) *Vector3 {
v.Z = z
return &v
}
// SetComponent :
func (v Vector3) SetComponent(index int, value float64) *Vector3 {
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
}
return &v
}
// GetComponent :
func (v Vector3) 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
}
}
// Clone :
func (v Vector3) Clone() *Vector3 {
return NewVector3(v.X, v.Y, v.Z)
}
// Copy :
func (v Vector3) Copy(w Vector3) *Vector3 {
v.X = w.X
v.Y = w.Y
v.Z = w.Z
return &v
}
// Add :
func (v Vector3) Add(w Vector3) *Vector3 {
v.X += w.X
v.Y += w.Y
v.Z += w.Z
return &v
}
// AddScalar :
func (v Vector3) AddScalar(s float64) *Vector3 {
v.X += s
v.Y += s
v.Z += s
return &v
}
// AddVectors :
func (v Vector3) AddVectors(a, b Vector3) *Vector3 {
v.X = a.X + b.X
v.Y = a.Y + b.Y
v.Z = a.Z + b.Z
return &v
}
// AddScaledVector :
func (v Vector3) AddScaledVector(w Vector3, s float64) *Vector3 {
v.X += w.X * s
v.Y += w.Y * s
v.Z += w.Z * s
return &v
}
// Sub :
func (v Vector3) Sub(w Vector3) *Vector3 {
v.X -= w.X
v.Y -= w.Y
v.Z -= w.Z
return &v
}
// SubScalar :
func (v Vector3) SubScalar(s float64) *Vector3 {
v.X -= s
v.Y -= s
v.Z -= s
return &v
}
// SubVectors :
func (v Vector3) SubVectors(a, b Vector3) *Vector3 {
v.X = a.X - b.X
v.Y = a.Y - b.Y
v.Z = a.Z - b.Z
return &v
}
// Multiply :
func (v Vector3) Multiply(w Vector3) *Vector3 {
v.X *= w.X
v.Y *= w.Y
v.Z *= w.Z
return &v
}
// MultiplyScalar :
func (v Vector3) MultiplyScalar(scalar float64) *Vector3 {
v.X *= scalar
v.Y *= scalar
v.Z *= scalar
return &v
}
// MultiplyVectors :
func (v Vector3) MultiplyVectors(a, b Vector3) *Vector3 {
v.X = a.X * b.X
v.Y = a.Y * b.Y
v.Z = a.Z * b.Z
return &v
}
// ApplyEuler :
func (v Vector3) ApplyEuler(euler Euler) *Vector3 {
return v.ApplyQuaternion(*_quaternionV3.SetFromEuler(euler, true))
}
// ApplyAxisAngle :
func (v Vector3) ApplyAxisAngle(axis Vector3, angle float64) *Vector3 {
return v.ApplyQuaternion(*_quaternionV3.SetFromAxisAngle(axis, angle))
}
// ApplyMatrix3 :
func (v Vector3) ApplyMatrix3(m Matrix3) *Vector3 {
x, y, z := v.X, v.Y, v.Z
me := m.Elements
v.X = me[0]*x + me[3]*y + me[6]*z
v.Y = me[1]*x + me[4]*y + me[7]*z
v.Z = me[2]*x + me[5]*y + me[8]*z
return &v
}
// ApplyNormalMatrix :
func (v Vector3) ApplyNormalMatrix(m Matrix3) *Vector3 {
return v.ApplyMatrix3(m).Normalize()
}
// ApplyMatrix4 :
func (v Vector3) ApplyMatrix4(m Matrix4) *Vector3 {
x, y, z := v.X, v.Y, v.Z
e := m.Elements
w := 1 / (e[3]*x + e[7]*y + e[11]*z + e[15])
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
return &v
}
// ApplyQuaternion :
func (v Vector3) ApplyQuaternion(q Quaternion) *Vector3 {
x, y, z := v.X, v.Y, v.Z
qx, qy, qz, qw := q.X(), q.Y(), q.Z(), q.W()
// calculate quat * vector
ix := qw*x + qy*z - qz*y
iy := qw*y + qz*x - qx*z
iz := qw*z + qx*y - qy*x
iw := -qx*x - qy*y - qz*z
// calculate result * inverse quat
v.X = ix*qw + iw*-qx + iy*-qz - iz*-qy
v.Y = iy*qw + iw*-qy + iz*-qx - ix*-qz
v.Z = iz*qw + iw*-qz + ix*-qy - iy*-qx
return &v
}
// Project :
func (v Vector3) Project(matrixWorldInverse, projectionMatrix Matrix4) *Vector3 {
return v.ApplyMatrix4(matrixWorldInverse).ApplyMatrix4(projectionMatrix)
}
// Unproject :
func (v Vector3) Unproject(projectionMatrixInverse, matrixWorld Matrix4) *Vector3 {
return v.ApplyMatrix4(projectionMatrixInverse).ApplyMatrix4(matrixWorld)
}
// TransformDirection :
func (v Vector3) TransformDirection(m Matrix4) *Vector3 {
// input: THREE.Matrix4 affine matrix
// vector interpreted as a direction
x, y, z := v.X, v.Y, v.Z
e := m.Elements
v.X = e[0]*x + e[4]*y + e[8]*z
v.Y = e[1]*x + e[5]*y + e[9]*z
v.Z = e[2]*x + e[6]*y + e[10]*z
return v.Normalize()
}
// Divide :
func (v Vector3) Divide(w Vector3) *Vector3 {
v.X /= w.X
v.Y /= w.Y
v.Z /= w.Z
return &v
}
// DivideScalar :
func (v Vector3) DivideScalar(scalar float64) *Vector3 {
return v.MultiplyScalar(1 / scalar)
}
// Min :
func (v Vector3) Min(w Vector3) *Vector3 {
v.X = math.Min(v.X, w.X)
v.Y = math.Min(v.Y, w.Y)
v.Z = math.Min(v.Z, w.Z)
return &v
}
// Max :
func (v Vector3) Max(w Vector3) *Vector3 {
v.X = math.Max(v.X, w.X)
v.Y = math.Max(v.Y, w.Y)
v.Z = math.Max(v.Z, w.Z)
return &v
}
// Clamp :
func (v Vector3) Clamp(min, max Vector3) *Vector3 {
// 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))
return &v
}
// ClampScalar :
func (v Vector3) ClampScalar(minVal, maxVal float64) *Vector3 {
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))
return &v
}
// ClampLength :
func (v Vector3) ClampLength(min, max float64) *Vector3 {
length := v.Length()
if length == 0 {
length = 1
}
return v.DivideScalar(length).MultiplyScalar(math.Max(min, math.Min(max, length)))
}
// Floor :
func (v Vector3) Floor() *Vector3 {
v.X = math.Floor(v.X)
v.Y = math.Floor(v.Y)
v.Z = math.Floor(v.Z)
return &v
}
// Ceil :
func (v Vector3) Ceil() *Vector3 {
v.X = math.Ceil(v.X)
v.Y = math.Ceil(v.Y)
v.Z = math.Ceil(v.Z)
return &v
}
// Round :
func (v Vector3) Round() *Vector3 {
v.X = math.Round(v.X)
v.Y = math.Round(v.Y)
v.Z = math.Round(v.Z)
return &v
}
// RoundToZero :
func (v Vector3) RoundToZero() *Vector3 {
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)
}
return &v
}
// Negate
func (v Vector3) Negate() *Vector3 {
v.X = -v.X
v.Y = -v.Y
v.Z = -v.Z
return &v
}
// Dot
func (v Vector3) Dot(w Vector3) float64 {
return v.X*w.X + v.Y*w.Y + v.Z*w.Z
}
// LengthSq
func (v Vector3) LengthSq() float64 {
return v.X*v.X + v.Y*v.Y + v.Z*v.Z
}
// Length
func (v Vector3) Length() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y + v.Z*v.Z)
}
// ManhattanLength
func (v Vector3) ManhattanLength() float64 {
return math.Abs(v.X) + math.Abs(v.Y) + math.Abs(v.Z)
}
// Normalize
func (v Vector3) Normalize() *Vector3 {
length := v.Length()
if length == 0 {
length = 1
}
return v.DivideScalar(length)
}
// SetLength
func (v Vector3) SetLength(length float64) *Vector3 {
return v.Normalize().MultiplyScalar(length)
}
// Lerp :
func (v Vector3) Lerp(w Vector3, alpha float64) *Vector3 {
v.X += (w.X - v.X) * alpha
v.Y += (w.Y - v.Y) * alpha
v.Z += (w.Z - v.Z) * alpha
return &v
}
// LerpVectors :
func (v Vector3) LerpVectors(v1, v2 Vector3, alpha float64) *Vector3 {
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
return &v
}
// Cross :
func (v Vector3) Cross(a Vector3) *Vector3 { // bug?
return v.CrossVectors(v, a)
}
// CrossVectors :
func (v Vector3) CrossVectors(a, b Vector3) *Vector3 {
ax, ay, az := a.X, a.Y, a.Z
bx, by, bz := b.X, b.Y, b.Z
v.X = ay*bz - az*by
v.Y = az*bx - ax*bz
v.Z = ax*by - ay*bx
return &v
}
// ProjectOnVector :
func (v Vector3) ProjectOnVector(w Vector3) *Vector3 {
denominator := w.LengthSq()
if denominator == 0 {
return v.Set(0, 0, 0)
}
scalar := w.Dot(v) / denominator
return v.Copy(w).MultiplyScalar(scalar)
}
// ProjectOnPlane :
func (v Vector3) ProjectOnPlane(planeNormal Vector3) *Vector3 {
_vector3.Copy(v).ProjectOnVector(planeNormal)
return v.Sub(*_vector3)
}
// Reflect :
func (v Vector3) Reflect(normal Vector3) *Vector3 {
// reflect incident vector off plane orthogonal to normal
// normal is assumed to have unit length
return v.Sub(*_vector3.Copy(normal).MultiplyScalar(2 * v.Dot(normal)))
}
// AngleTo :
func (v Vector3) AngleTo(w Vector3) float64 {
denominator := math.Sqrt(w.LengthSq() * w.LengthSq())
if denominator == 0 {
return math.Pi / 2
}
theta := v.Dot(v) / denominator
// clamp, to handle numerical problems
return math.Acos(Clamp(theta, -1, 1))
}
// DistanceTo :
func (v Vector3) DistanceTo(w Vector3) float64 {
return math.Sqrt(v.DistanceToSquared(w))
}
// DistanceToSquared :
func (v Vector3) DistanceToSquared(w Vector3) float64 {
dx, dy, dz := v.X-w.X, v.Y-w.Y, v.Z-w.Z
return dx*dx + dy*dy + dz*dz
}
// ManhattanDistanceTo :
func (v Vector3) ManhattanDistanceTo(w Vector3) float64 {
return math.Abs(v.X-w.X) + math.Abs(v.Y-w.Y) + math.Abs(v.Z-w.Z)
}
// SetFromSpherical :
func (v Vector3) SetFromSpherical(s Spherical) *Vector3 {
return v.SetFromSphericalCoords(s.Radius, s.Phi, s.Theta)
}
// SetFromSphericalCoords :
func (v Vector3) SetFromSphericalCoords(radius, phi, theta float64) *Vector3 {
sinPhiRadius := math.Sin(phi) * radius
v.X = sinPhiRadius * math.Sin(theta)
v.Y = math.Cos(phi) * radius
v.Z = sinPhiRadius * math.Cos(theta)
return &v
}
// SetFromCylindrical :
func (v Vector3) SetFromCylindrical(c Cylindrical) *Vector3 {
return v.SetFromCylindricalCoords(c.Radius, c.Theta, c.Y)
}
// SetFromCylindricalCoords :
func (v Vector3) SetFromCylindricalCoords(radius, theta, y float64) *Vector3 {
v.X = radius * math.Sin(theta)
v.Y = y
v.Z = radius * math.Cos(theta)
return &v
}
// SetFromMatrixPosition :
func (v Vector3) SetFromMatrixPosition(m Matrix4) *Vector3 {
e := m.Elements
v.X = e[12]
v.Y = e[13]
v.Z = e[14]
return &v
}
// SetFromMatrixScale :
func (v Vector3) SetFromMatrixScale(m Matrix4) *Vector3 {
sx := v.SetFromMatrixColumn(m, 0).Length()
sy := v.SetFromMatrixColumn(m, 1).Length()
sz := v.SetFromMatrixColumn(m, 2).Length()
v.X = sx
v.Y = sy
v.Z = sz
return &v
}
// SetFromMatrixColumn :
func (v Vector3) SetFromMatrixColumn(m Matrix4, index int) *Vector3 {
elems := []float64{}
for i := 0; i < 3; i++ {
elems = append(elems, m.Elements[index*4+i])
}
return v.FromArray(elems, 0)
}
// SetFromMatrix3Column :
func (v Vector3) SetFromMatrix3Column(m Matrix3, index int) *Vector3 {
elems := []float64{}
for i := 0; i < 3; i++ {
elems = append(elems, m.Elements[index*3+i])
}
return v.FromArray(elems, 0)
}
// Equals :
func (v Vector3) Equals(w Vector3) bool {
return w.X == v.X && w.Y == v.Y && w.Z == v.Z
}
// FromArray :
func (v Vector3) FromArray(array []float64, offset int) *Vector3 {
if len(array) < offset+3 {
panic("array length should be greater than offset+3")
}
v.X = array[offset]
v.Y = array[offset+1]
v.Z = array[offset+2]
return &v
}
// ToArray :
func (v Vector3) ToArray(array []float64, offset int) []float64 {
if len(array) < offset+3 {
panic("array length should be greater than offset+3")
}
array[offset] = v.X
array[offset+1] = v.Y
array[offset+2] = v.Z
return array
}
// Random :
func (v Vector3) Random() *Vector3 {
v.X = rand.Float64()
v.Y = rand.Float64()
v.Z = rand.Float64()
return &v
}