Home Reference Source Repository

js/SceneKit/SCNVector3.js

'use strict'

import SCNVector4 from './SCNVector4'

/**
 * A representation of a three-component vector.
 * @access public
 * @see https://developer.apple.com/documentation/scenekit/scnvector3
 */
export default class SCNVector3 {

  // Initializers

  /**
   * 
   * @access public
   * @constructor
   * @param {number} x - 
   * @param {number} y - 
   * @param {number} z - 
   * @returns {void}
   * @see https://developer.apple.com/documentation/scenekit/scnvector3/1522904-init
   */
  constructor(x = 0, y = 0, z = 0) {
    // Instance Properties
    /** @type {number} */
    this.x = x
    /** @type {number} */
    this.y = y
    /** @type {number} */
    this.z = z

    //if(x instanceof Ammo.btVector3){
    //  this.x = x.x()
    //  this.y = x.y()
    //  this.z = x.z()
    //}
  }

  /**
   * @access private
   * @param {Buffer} data -
   * @param {number} [offset = 0] -
   * @param {boolean} [bigEndian = false] -
   * @returns {SCNVector3} -
   */
  static _initWithData(data, offset = 0, bigEndian = false) {
    const instance = new SCNVector3()
    if(bigEndian){
      instance.x = data.readFloatBE(offset + 0)
      instance.y = data.readFloatBE(offset + 4)
      instance.z = data.readFloatBE(offset + 8)
    }else{
      instance.x = data.readFloatLE(offset + 0)
      instance.y = data.readFloatLE(offset + 4)
      instance.z = data.readFloatLE(offset + 8)
    }
    return instance
  }

  _copy() {
    return new SCNVector3(this.x, this.y, this.z)
  }

  _copyFrom(v) {
    this.x = v.x
    this.y = v.y
    this.z = v.z
  }

  // extensions

  zero() {
    return new SCNVector3()
  }

  /**
   * @access public
   * @param {SCNVector3} v -
   * @returns {SCNVector3} -
   */
  add(v) {
    const r = new SCNVector3()
    r.x = this.x + v.x
    r.y = this.y + v.y
    r.z = this.z + v.z
    return r
  }

  /**
   * @access public
   * @param {SCNVector3} v -
   * @returns {SCNVector3} -
   */
  sub(v) {
    const r = new SCNVector3()
    r.x = this.x - v.x
    r.y = this.y - v.y
    r.z = this.z - v.z
    return r
  }

  /**
   * @access public
   * @param {number} n -
   * @returns {SCNVector3} -
   */
  mul(n) {
    const r = new SCNVector3()
    r.x = this.x * n
    r.y = this.y * n
    r.z = this.z * n
    return r
  }

  /**
   * @access public
   * @param {SCNVector3} v -
   * @returns {SCNVector3}
   */
  mulv(v) {
    const r = new SCNVector3()
    r.x = this.x * v.x
    r.y = this.y * v.y
    r.z = this.z * v.z
    return r
  }

  /**
   * @access public
   * @param {SCNVector3} v -
   * @returns {number} -
   */
  dot(v) {
    return this.x * v.x + this.y * v.y + this.z * v.z
  }

  /**
   * @access public
   * @param {SCNVecor3} v -
   * @returns {SCNVector3} -
   */
  cross(v) {
    const r = new SCNVector3()
    r.x = this.y * v.z - this.z * v.y
    r.y = this.z * v.x - this.x * v.z
    r.z = this.x * v.y - this.y * v.x
    return r
  }

  /**
   * @access public
   * @param {SCNVector3} v -
   * @param {number} rate -
   * @returns {SCNVector3} -
   */
  lerp(v, rate) {
    const r = new SCNVector3()
    r.x = this.x + rate * (v.x - this.x)
    r.y = this.y + rate * (v.y - this.y)
    r.z = this.z + rate * (v.z - this.z)
    return r
  }

  /**
   * @access public
   * @returns {SCNVector3} -
   */
  normalize() {
    const len = this.length()
    const r = new SCNVector3()
    if(len === 0){
      return r
    }
    const sqr = 1.0 / len
    r.x = this.x * sqr
    r.y = this.y * sqr
    r.z = this.z * sqr

    return r
  }

  /**
   * @access public
   * @returns {number} -
   */
  length2() {
    return (this.x * this.x + this.y * this.y + this.z * this.z)
  }

  /**
   * @access public
   * @returns {number} -
   */
  length() {
    return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z)
  }

  /**
   * @access public
   * @param {SCNMatrix4} m -
   * @returns {SCNVector3} -
   */
  transform(m) {
    const r = new SCNVector3()
    const w = this.x * m.m14 + this.y * m.m24 + this.z * m.m34 + m.m44
    if(w === 0){
      return r
    }
    const iw = 1.0 / w
    r.x = (this.x * m.m11 + this.y * m.m21 + this.z * m.m31 + m.m41) * iw
    r.y = (this.x * m.m12 + this.y * m.m22 + this.z * m.m32 + m.m42) * iw
    r.z = (this.x * m.m13 + this.y * m.m23 + this.z * m.m33 + m.m43) * iw
    return r
  }

  /**
   * @access public
   * @param {SCNMatrix4} m -
   * @returns {SCNVector3} -
   */
  rotate(m) {
    const r = new SCNVector3()
    r.x = this.x * m.m11 + this.y * m.m21 + this.z * m.m31
    r.y = this.x * m.m12 + this.y * m.m22 + this.z * m.m32
    r.z = this.x * m.m13 + this.y * m.m23 + this.z * m.m33
    return r
  }

  /**
   * @access public
   * @param {SCNVector4} q -
   * @returns {SCNVector3} -
   */
  rotateWithQuaternion(q) {
    return this.rotate(q.rotMatrix())
  }

  /**
   * @access public
   * @returns {SCNVector4} -
   */
  eulerAnglesToRotation() {
    const rot = new SCNVector4()
    const halfX = this.x * 0.5
    const halfY = this.y * 0.5
    const halfZ = this.z * 0.5
    const cosX = Math.cos(halfX)
    const sinX = Math.sin(halfX)
    const cosY = Math.cos(halfY)
    const sinY = Math.sin(halfY)
    const cosZ = Math.cos(halfZ)
    const sinZ = Math.sin(halfZ)

    const q = new SCNVector4()
    const x = sinX * cosY * cosZ - cosX * sinY * sinZ
    const y = cosX * sinY * cosZ + sinX * cosY * sinZ
    const z = cosX * cosY * sinZ - sinX * sinY * cosZ
    const d = x * x + y * y + z * z
    if(d === 0){
      rot.x = 0
      rot.y = 0
      rot.z = 0
      rot.w = 0
    }else{
      const r = 1.0 / Math.sqrt(d)
      rot.x = x * r
      rot.y = y * r
      rot.z = z * r
      rot.w = 2 * Math.acos(cosX * cosY * cosZ + sinX * sinY * sinZ)
    }

    return rot
  }

  /**
   * @access public
   * @returns {SCNVector4} -
   */
  eulerAnglesToQuat() {
    return this.eulerAnglesToRotation().rotationToQuat()
  }

  /**
   * @access public
   * @returns {number[]} -
   */
  floatArray() {
    return [this.x, this.y, this.z]
  }

  /**
   * @access public
   * @returns {Float32Array} -
   */
  float32Array() {
    return new Float32Array([this.x, this.y, this.z])
  }

  /**
   * @access private
   * @returns {Ammo.btVector3} -
   * @desc call Ammo.destroy(vec) after using it.
   */
  _createBtVector3() {
    //return new Ammo.btVector3(this.x, this.y, this.z)
  }
}