mathjs/test/unit-tests/function/matrix/rotationMatrix.test.js
rnd-debug 439ec41e13
Feat/rotate matrix (#1984)
* providing rotationMatrix(theta, v)

* increase coverage

* adding latex test as is

* fixing rounding issues with math.pi

* fixing lint

* Update rotationMatrix.js

remove non-sense doc

* Update rotationMatrix.js

Remove non-sense from docs

* removing nonsense from docs

* Renaming functions

Co-authored-by: Jos de Jong <wjosdejong@gmail.com>
2020-10-07 12:41:50 +02:00

253 lines
13 KiB
JavaScript

import assert from 'assert'
import approx from '../../../../tools/approx'
import math from '../../../../src/bundleAny'
const bignumber = math.bignumber
const complex = math.complex
const unit = math.unit
const multiply = math.multiply
const matrix = math.matrix
const cos = math.cos
const sin = math.sin
const rotationMatrix = math.rotationMatrix
describe('rotationMatrix', function () {
const sqrtTwoInv = 0.7071067811865476 // = 1 / sqrt(2)
const minusSqrtTwoInv = -0.7071067811865476 // = - 1 / sqrt(2)
it('should create an empty matrix', function () {
assert.deepStrictEqual(rotationMatrix(), matrix())
assert.deepStrictEqual(rotationMatrix(1, [0.0, 0.0, 0.0]), matrix())
assert.deepStrictEqual(rotationMatrix('sparse'), matrix('sparse'))
assert.deepStrictEqual(rotationMatrix('dense'), matrix('dense'))
const mathArray = math.create({ matrix: 'Array' })
assert.deepStrictEqual(mathArray.rotationMatrix(), [])
})
it('should create a 2D rotation matrix of given angle', function () {
approx.deepEqual(rotationMatrix(0.0), matrix([[1, 0.0], [0.0, 1]]))
approx.deepEqual(rotationMatrix(math.pi / 2), matrix([[0.0, -1], [1, 0.0]]))
approx.deepEqual(rotationMatrix(1), matrix([[cos(1), -sin(1)], [sin(1), cos(1)]]))
approx.deepEqual(rotationMatrix(math.pi / 4), matrix([[sqrtTwoInv, -sqrtTwoInv], [sqrtTwoInv, sqrtTwoInv]]))
})
it('should create a 2D rotation matrix of given bignumber angle', function () {
approx.deepEqual(rotationMatrix(bignumber(0.0)), matrix([[1, 0.0], [0.0, 1]]))
const bigmath = math.create({ number: 'BigNumber' })
const minusOne = bigmath.bignumber(-1)
const cos1 = bigmath.cos(bigmath.bignumber(1))
const sin1 = bigmath.sin(bigmath.bignumber(1))
const minusSin1 = bigmath.multiply(sin1, minusOne)
assert.deepStrictEqual(bigmath.rotationMatrix(bigmath.bignumber(1)),
bigmath.matrix([[cos1, minusSin1], [sin1, cos1]]))
const cos25 = bigmath.cos(bigmath.bignumber(2.5))
const sin25 = bigmath.sin(bigmath.bignumber(2.5))
const minusSin25 = bigmath.multiply(sin25, minusOne)
assert.deepStrictEqual(bigmath.rotationMatrix(bigmath.bignumber(2.5)),
bigmath.matrix([[cos25, minusSin25], [sin25, cos25]]))
})
it('should create a 2D rotation matrix of given complex angle', function () {
const reI = 1.5430806348152437784
const imI = 1.1752011936438014568
approx.deepEqual(rotationMatrix(math.i), matrix([[complex(reI, 0.0), complex(0.0, -imI)],
[complex(0.0, imI), complex(reI, 0.0)]]))
const reCos = 4.18962569096881
const imCos = 9.10922789375534
const reSin = 9.15449914691142
const imSin = 4.16890695996656
const cosComplex = complex(-reCos, -imCos)
const sinComplex = complex(reSin, -imSin)
approx.deepEqual(rotationMatrix(complex('2+3i')), matrix([[cosComplex, multiply(-1.0, sinComplex)], [sinComplex, cosComplex]]))
})
it('should create a 2D rotation matrix of given unit angle', function () {
approx.deepEqual(rotationMatrix(unit('45deg')), matrix([[sqrtTwoInv, minusSqrtTwoInv], [sqrtTwoInv, sqrtTwoInv]]))
approx.deepEqual(rotationMatrix(unit('-135deg')), matrix([[minusSqrtTwoInv, sqrtTwoInv], [minusSqrtTwoInv, minusSqrtTwoInv]]))
const cosComplex = complex(0.833730025131149, -0.988897705762865)
const sinComplex = complex(1.298457581415977, 0.63496391478473611)
approx.deepEqual(rotationMatrix(unit(complex(1, 1), 'rad')), matrix([[cosComplex, multiply(-1.0, sinComplex)], [sinComplex, cosComplex]]))
})
it('should create a 2D rotation matrix of given angle and given storage type', function () {
assert.deepStrictEqual(rotationMatrix(0.0, 'sparse'), matrix([[1.0, 0.0], [0.0, 1.0]], 'sparse'))
assert.deepStrictEqual(rotationMatrix(math.pi / 2, 'sparse'), matrix([[0, -1], [1, 0]], 'sparse'))
approx.deepEqual(rotationMatrix(math.pi / 4, 'sparse'), matrix([[sqrtTwoInv, -sqrtTwoInv], [sqrtTwoInv, sqrtTwoInv]], 'sparse'))
})
it('should create a 3D rotation matrix by given angle around given axis', function () {
assert.deepStrictEqual(math.rotationMatrix(0.0, [1, 1, 1]), matrix([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]))
approx.deepEqual(math.rotationMatrix(math.pi / 2, [1, 0, 0]), matrix([[1.0, 0.0, 0.0], [0.0, 0.0, -1.0], [0.0, 1.0, 0.0]]))
approx.deepEqual(math.rotationMatrix(math.pi / 2, [0, 1, 0]), matrix([[0.0, 0.0, 1.0], [0.0, 1.0, 0.0], [-1.0, 0.0, 0.0]]))
approx.deepEqual(math.rotationMatrix(math.pi / 2, [0, 0, 1]), matrix([[0.0, -1.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 1.0]]))
approx.deepEqual(math.rotationMatrix(-math.pi / 4, [1, 0, 0]),
matrix([[1.0, 0.0, 0.0], [0.0, sqrtTwoInv, sqrtTwoInv], [0.0, minusSqrtTwoInv, sqrtTwoInv]]))
approx.deepEqual(math.rotationMatrix(-math.pi / 4, [0, 1, 0]),
matrix([[sqrtTwoInv, 0.0, minusSqrtTwoInv], [0.0, 1.0, 0.0], [sqrtTwoInv, 0.0, sqrtTwoInv]]))
approx.deepEqual(math.rotationMatrix(-math.pi / 4, [0, 0, 1]),
matrix([[sqrtTwoInv, sqrtTwoInv, 0.0], [minusSqrtTwoInv, sqrtTwoInv, 0.0], [0.0, 0.0, 1.0]]))
assert.deepStrictEqual(math.rotationMatrix(1, [1, 0, 0]),
matrix([[1, 0, 0],
[0, cos(1), -sin(1)],
[0, sin(1), cos(1)]]))
})
it('should create a 3D rotation matrix by given angle around given vector provided as matrix', function () {
assert.deepStrictEqual(math.rotationMatrix(0.0, matrix([1, 1, 1])),
matrix([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]))
approx.deepEqual(math.rotationMatrix(math.pi / 2, matrix([1, 0, 0])),
matrix([[1.0, 0.0, 0.0], [0.0, 0.0, -1.0], [0.0, 1.0, 0.0]]))
approx.deepEqual(math.rotationMatrix(math.pi / 2, matrix([0, 1, 0])),
matrix([[0.0, 0.0, 1.0], [0.0, 1.0, 0.0], [-1.0, 0.0, 0.0]]))
approx.deepEqual(math.rotationMatrix(math.pi / 2, matrix([0, 0, 1])),
matrix([[0.0, -1.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 1.0]]))
approx.deepEqual(math.rotationMatrix(-math.pi / 4, matrix([1, 0, 0])),
matrix([[1.0, 0.0, 0.0], [0.0, sqrtTwoInv, sqrtTwoInv], [0.0, minusSqrtTwoInv, sqrtTwoInv]]))
approx.deepEqual(math.rotationMatrix(-math.pi / 4, matrix([0, 1, 0])),
matrix([[sqrtTwoInv, 0.0, minusSqrtTwoInv], [0.0, 1.0, 0.0], [sqrtTwoInv, 0.0, sqrtTwoInv]]))
approx.deepEqual(math.rotationMatrix(-math.pi / 4, matrix([0, 0, 1])),
matrix([[sqrtTwoInv, sqrtTwoInv, 0.0], [minusSqrtTwoInv, sqrtTwoInv, 0.0], [0.0, 0.0, 1.0]]))
assert.deepStrictEqual(math.rotationMatrix(1, matrix([1, 0, 0])),
matrix([[1, 0, 0],
[0, cos(1), -sin(1)],
[0, sin(1), cos(1)]]))
})
it('should create a unitary 3D rotation matrix around non-unit vector', function () {
approx.deepEqual(math.rotationMatrix(math.pi / 2, [1000, 0, 0]),
matrix([[1.0, 0.0, 0.0], [0.0, 0.0, -1.0], [0.0, 1.0, 0.0]]))
approx.deepEqual(math.rotationMatrix(math.pi / 2, [1000, 0, 1000]),
matrix([[0.5, minusSqrtTwoInv, 0.5], [sqrtTwoInv, 0.0, minusSqrtTwoInv], [0.5, sqrtTwoInv, 0.5]]))
approx.deepEqual(math.rotationMatrix(math.pi / 2, matrix([0, 0, 1000])),
matrix([[0.0, -1.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 1.0]]))
approx.deepEqual(math.rotationMatrix(math.pi / 2, matrix([0, 200, 200])),
matrix([[0.0, minusSqrtTwoInv, sqrtTwoInv], [sqrtTwoInv, 0.5, 0.5], [minusSqrtTwoInv, 0.5, 0.5]]))
})
it('should create a 3D rotation matrix by given bignumber angle around given axis', function () {
const zero = bignumber(0)
const one = bignumber(1)
const cos2 = cos(bignumber(2))
const sin2 = sin(bignumber(2))
const minusSin2 = multiply(bignumber(-1), sin2)
assert.deepStrictEqual(math.rotationMatrix(bignumber(2), [1, 0, 0]),
matrix([[one, zero, zero],
[zero, cos2, minusSin2],
[zero, sin2, cos2]]))
assert.deepStrictEqual(math.rotationMatrix(bignumber(2), [0, 1, 0]),
matrix([[cos2, zero, sin2],
[zero, one, zero],
[minusSin2, zero, cos2]]))
assert.deepStrictEqual(math.rotationMatrix(bignumber(2), [0, 0, 1]),
matrix([[cos2, minusSin2, zero],
[sin2, cos2, zero],
[zero, zero, one]]))
assert.deepStrictEqual(math.rotationMatrix(bignumber(2), matrix([0, 0, 1])),
matrix([[cos2, minusSin2, zero],
[sin2, cos2, zero],
[zero, zero, one]]))
})
it('should create a 3D rotation matrix by given complex angle around given axis', function () {
const complexZero = math.complex(0)
const cosTheta = math.cos(complex('2+3i'))
const sinTheta = math.sin(complex('2+3i'))
const minusSinTheta = math.multiplyScalar(-1, sinTheta)
assert.deepStrictEqual(math.rotationMatrix(complex('2+3i'), [1, 0, 0]),
math.complex(matrix([[1, 0, 0],
[complexZero, cosTheta, minusSinTheta],
[complexZero, sinTheta, cosTheta]])))
assert.deepStrictEqual(math.rotationMatrix(complex('2+3i'), [0, 1, 0]),
math.complex(matrix([[cosTheta, 0.0, sinTheta],
[0.0, 1.0, 0.0],
[minusSinTheta, 0.0, cosTheta]])))
assert.deepStrictEqual(math.rotationMatrix(complex('2+3i'), [0, 0, 1]),
math.complex(matrix([[cosTheta, minusSinTheta, 0.0],
[sinTheta, cosTheta, 0.0],
[0.0, 0.0, 1.0]])))
assert.deepStrictEqual(math.rotationMatrix(complex('2+3i'), matrix([0, 1, 0])),
math.complex(matrix([[cosTheta, 0.0, sinTheta],
[0.0, 1.0, 0.0],
[minusSinTheta, 0.0, cosTheta]])))
})
it('should create a 3D rotation matrix by given unit angle around given axis', function () {
approx.deepEqual(math.rotationMatrix(unit('45deg'), [1, 0, 0]),
matrix([[1.0, 0.0, 0.0], [0.0, sqrtTwoInv, minusSqrtTwoInv], [0.0, sqrtTwoInv, sqrtTwoInv]]))
approx.deepEqual(math.rotationMatrix(unit('45deg'), [0, 1, 0]),
matrix([[sqrtTwoInv, 0.0, sqrtTwoInv], [0.0, 1.0, 0.0], [minusSqrtTwoInv, 0.0, sqrtTwoInv]]))
approx.deepEqual(math.rotationMatrix(unit('45deg'), [0, 0, 1]),
matrix([[sqrtTwoInv, minusSqrtTwoInv, 0.0], [sqrtTwoInv, sqrtTwoInv, 0.0], [0.0, 0.0, 1.0]]))
approx.deepEqual(math.rotationMatrix(unit('-135deg'), [1, 0, 0]),
matrix([[1.0, 0.0, 0.0], [0.0, minusSqrtTwoInv, sqrtTwoInv], [0.0, minusSqrtTwoInv, minusSqrtTwoInv]]))
approx.deepEqual(math.rotationMatrix(unit('-135deg'), [0, 1, 0]),
matrix([[minusSqrtTwoInv, 0.0, minusSqrtTwoInv], [0.0, 1.0, 0.0], [sqrtTwoInv, 0.0, minusSqrtTwoInv]]))
approx.deepEqual(math.rotationMatrix(unit('-135deg'), [0, 0, 1]),
matrix([[minusSqrtTwoInv, sqrtTwoInv, 0.0], [minusSqrtTwoInv, minusSqrtTwoInv, 0.0], [0.0, 0.0, 1.0]]))
approx.deepEqual(rotationMatrix(unit(complex(1, 1), 'rad'), [1, 0, 1]),
math.evaluate('matrix([[0.5 * (1 + cos(1+i)), -sin(1+i) / sqrt(2), 0.5 * (1 - cos(1+i))],' +
'[sin(1+i) / sqrt(2), cos(1+i), -sin(1+i) / sqrt(2)],' +
'[0.5 * (1 - cos(1+i)), sin(1+i) / sqrt(2), 0.5 * (1 + cos(1+i))]])'))
approx.deepEqual(math.rotationMatrix(unit('45deg'), matrix([0, 0, 1])),
matrix([[sqrtTwoInv, minusSqrtTwoInv, 0.0], [sqrtTwoInv, sqrtTwoInv, 0.0], [0.0, 0.0, 1.0]]))
approx.deepEqual(math.rotationMatrix(unit('-135deg'), matrix([1, 0, 0])),
matrix([[1.0, 0.0, 0.0], [0.0, minusSqrtTwoInv, sqrtTwoInv], [0.0, minusSqrtTwoInv, minusSqrtTwoInv]]))
})
it('should create a 3D rotation matrix of given angle around given axis and given storage type', function () {
assert.deepStrictEqual(rotationMatrix(0.0, [0, 0, 1], 'sparse'),
matrix([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]], 'sparse'))
assert.deepStrictEqual(rotationMatrix(math.pi / 2, [0, 0, 1], 'sparse'),
matrix([[0.0, -1.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 1.0]], 'sparse'))
approx.deepEqual(rotationMatrix(math.pi / 4, [0, 1, 0], 'sparse'),
matrix([[sqrtTwoInv, 0.0, sqrtTwoInv], [0, 1, 0], [minusSqrtTwoInv, 0.0, sqrtTwoInv]], 'sparse'))
approx.deepEqual(rotationMatrix(math.pi / 4, matrix([0, 1, 0]), 'sparse'),
matrix([[sqrtTwoInv, 0.0, sqrtTwoInv], [0, 1, 0], [minusSqrtTwoInv, 0.0, sqrtTwoInv]], 'sparse'))
})
it('should return an array when mathjs is configured for this', function () {
const mathArray = math.create({ matrix: 'Array' })
approx.deepEqual(mathArray.rotationMatrix(mathArray.pi / 4),
[[sqrtTwoInv, minusSqrtTwoInv], [sqrtTwoInv, sqrtTwoInv]])
approx.deepEqual(mathArray.rotationMatrix(mathArray.pi / 2, [0, 0, 1]),
[[0.0, -1.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 1.0]])
approx.deepEqual(mathArray.rotationMatrix(mathArray.pi / 2, matrix([0, 0, 1])),
[[0.0, -1.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 1.0]])
})
it('should throw an error with an invalid input', function () {
assert.throws(function () { rotationMatrix('') }, /TypeError: Unknown matrix type /)
assert.throws(function () { rotationMatrix(null) }, /TypeError: Unexpected type of argument/)
assert.throws(function () { rotationMatrix(0, []) }, /RangeError: Vector must be of dimensions 1x3/)
assert.throws(function () { rotationMatrix(0, [1]) }, /RangeError: Vector must be of dimensions 1x3/)
assert.throws(function () { rotationMatrix(0, [0, 1]) }, /RangeError: Vector must be of dimensions 1x3/)
assert.throws(function () { rotationMatrix(0, [0, 1, 0], 'something') }, /TypeError: Unknown matrix type/)
assert.throws(function () { rotationMatrix(0, [0, 1, 0], 'sparse', 4) }, /TypeError: Too many arguments/)
})
it('should LaTeX rotationMatrix', function () {
const expression = math.parse('rotationMatrix(1)')
assert.strictEqual(expression.toTex(), '\\mathrm{rotationMatrix}\\left(1\\right)')
})
})