const mat4 = require('../maths/mat4')
const plane = require('../maths/plane')
const vec2 = require('../maths/vec2')
const vec3 = require('../maths/vec3')
const OrthoNormalBasis = require('../maths/OrthoNormalBasis')
const transform = require('./transform')
/**
* Get the transformation matrix that connects the given connectors.
* @param {Object} options
* @param {Boolean} [options.mirror=false] - the 'axis' vectors should point in the same direction
* true: the 'axis' vectors should point in opposite direction
* @param {Number} [options.normalRotation=0] - the angle (RADIANS) of rotation between the 'normal' vectors
* @param {connector} from - connector from which to connect
* @param {connector} to - connector to which to connected
* @returns {mat4} - the matrix that transforms (connects) one connector to another
* @alias module:modeling/connectors.transformationBetween
*/
const transformationBetween = (options, from, to) => {
const defaults = {
mirror: false,
normalRotation: 0
}
// mirror = !!mirror
const { mirror, normalRotation } = Object.assign({}, defaults, options)
// shift to the 0,0 origin
const matrix = mat4.fromTranslation(mat4.create(), vec3.negate(vec3.create(), from.point))
// align the axis
const axesplane = plane.fromPointsRandom(plane.create(), vec3.create(), from.axis, to.axis)
const axesbasis = new OrthoNormalBasis(axesplane)
let angle1 = vec2.angleRadians(axesbasis.to2D(from.axis))
let angle2 = vec2.angleRadians(axesbasis.to2D(to.axis))
let rotation = angle2 - angle1
if (mirror) rotation += Math.PI // 180 degrees
// TODO: understand and explain this
mat4.multiply(matrix, matrix, axesbasis.getProjectionMatrix())
mat4.multiply(matrix, matrix, mat4.fromZRotation(mat4.create(), rotation))
mat4.multiply(matrix, matrix, axesbasis.getInverseProjectionMatrix())
const usAxesAligned = transform(matrix, from)
// Now we have done the transformation for aligning the axes.
// align the normals
const normalsplane = plane.fromNormalAndPoint(plane.create(), to.axis, vec3.create())
const normalsbasis = new OrthoNormalBasis(normalsplane)
angle1 = vec2.angleRadians(normalsbasis.to2D(usAxesAligned.normal))
angle2 = vec2.angleRadians(normalsbasis.to2D(to.normal))
rotation = angle2 - angle1 + normalRotation
mat4.multiply(matrix, matrix, normalsbasis.getProjectionMatrix())
mat4.multiply(matrix, matrix, mat4.fromZRotation(mat4.create(), rotation))
mat4.multiply(matrix, matrix, normalsbasis.getInverseProjectionMatrix())
// translate to the destination point
mat4.multiply(matrix, matrix, mat4.fromTranslation(mat4.create(), to.point))
return matrix
}
module.exports = transformationBetween