#pragma rtGlobals=3
#pragma version = 2.1
#pragma IgorVersion = 6.1
#pragma ModuleName = PearlVectorOperations

// copyright (c) 2011-17 Paul Scherrer Institut
//
// Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//   http:///www.apache.org/licenses/LICENSE-2.0
//
// Please acknowledge the use of this code.

/// @file
/// @brief basic vector geometry operations.
/// @ingroup ArpesPackage
///
/// this procedure file contains basic vector geometry functions,
/// such as rotations.
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2011-17 Paul Scherrer Institut @n
/// Licensed under the Apache License, Version 2.0 (the "License"); @n
///   you may not use this file except in compliance with the License. @n
///   You may obtain a copy of the License at
///   http://www.apache.org/licenses/LICENSE-2.0
///

/// @namespace PearlVectorOperations
/// @brief basic vector geometry operations.
///
/// PearlVectorOperations is declared in @ref pearl-vector-operations.ipf.


/// rotate a 2D cartesian vector and returns its x component.
///
/// @param xx		x coordinate.
/// @param yy		y coordinate.
/// @param angle		rotation angle in degrees.
///
/// @return			x coordinate of the rotated vector.
///
function rotate2d_x(xx, yy, angle)
	variable xx, yy
	variable angle
	
	return xx * cos(angle * pi / 180) - yy * sin(angle * pi / 180)
end

/// rotate a 2D cartesian vector and returns its y component.
///
/// @param xx		x coordinate.
/// @param yy		y coordinate.
/// @param angle		rotation angle in degrees.
///
/// @return			y coordinate of the rotated vector.
///
function rotate2d_y(xx, yy, angle)
	variable xx, yy
	variable angle
	
	return xx * sin(angle * pi / 180) + yy * cos(angle * pi / 180)
end

/// create a free matrix wave which represents the 3-vector identity.
///
/// the matrix is initialized as identity.
///
/// @return			3x3 identity matrix in a free wave.
///
function /wave create_rotation_matrix_free()
	make /n=(3,3)/free matrix
	matrix = p == q // identity
	return matrix
end

/// calculate a matrix representing a 3-vector rotation around the x axis.
///
/// the function calculates the matrix elements of a rotation about the x axis.
///
/// @param[in,out]	matrix		3x3 wave to receive the rotation matrix elements.
///								the function calculates only the 2x2 block of the rotation.
///								the other elements must be initialized by the caller,
///								e.g. set to the identity matrix.
/// @param[in]		angle		rotation angle in degrees.
///
/// @return			rotation matrix.
///					this is the same wave instance as the matrix input.
///
function /wave set_rotation_x(matrix, angle)
	wave matrix
	variable angle
	
	variable si = sin(angle * pi / 180)
	variable co = cos(angle * pi / 180)
	
	matrix[1][1] = co
	matrix[2][2] = co
	matrix[2][1] = si
	matrix[1][2] = -si

	return matrix
end

/// calculate a matrix representing a 3-vector rotation around the y axis
///
/// the function calculates the matrix elements of a rotation about the y axis.
///
/// @param[in,out]	matrix		3x3 wave to receive the rotation matrix elements.
///								the function calculates only the 2x2 block of the rotation.
///								the other elements must be initialized by the caller,
///								e.g. set to the identity matrix.
/// @param[in]		angle		rotation angle in degrees.
///
/// @return			rotation matrix.
///					this is the same wave instance as the matrix input.
///
function /wave set_rotation_y(matrix, angle)
	wave matrix
	variable angle
	
	variable si = sin(angle * pi / 180)
	variable co = cos(angle * pi / 180)
	
	matrix[0][0] = co
	matrix[2][2] = co
	matrix[0][2] = si
	matrix[2][0] = -si

	return matrix
end

/// calculate a matrix representing a 3-vector rotation around the z axis
///
/// the function calculates the matrix elements of a rotation about the z axis.
///
/// @param[in,out]	matrix		3x3 wave to receive the rotation matrix elements.
///								the function calculates only the 2x2 block of the rotation.
///								the other elements must be initialized by the caller,
///								e.g. set to the identity matrix.
/// @param[in]		angle		rotation angle in degrees.
///
/// @return			rotation matrix.
///					this is the same wave instance as the matrix input.
///
function /wave set_rotation_z(matrix, angle)
	wave matrix
	variable angle
	
	variable si = sin(angle * pi / 180)
	variable co = cos(angle * pi / 180)
	
	matrix[0][0] = co
	matrix[1][1] = co
	matrix[1][0] = si
	matrix[0][1] = -si

	return matrix
end

/// rotate a wave of 3-vectors about the x axis.
///
/// this function rotates multiple vectors.
///
/// @param[in,out]	inout		wave with dimensions (M, N), M >= 3 (x, y, z), N >= 1.
/// 								the result will be in same wave.
///								only the first three rows of dimension 0 are used,
///								extra rows are left unchanged.
/// @param[in]		angle		rotation angle in degrees.
///
/// @return none
///
function rotate_x_wave(inout, angle)
	wave inout
	variable angle

	wave m_rotation_x = create_rotation_matrix_free()
	make /n=3/d/free w_temp_rotate_x
	variable ivec, nvec
	nvec = max(DimSize(inout, 1), 1)
	for (ivec = 0; ivec < nvec; ivec += 1)
		set_rotation_x(m_rotation_x, angle)
		w_temp_rotate_x = inout[p][ivec]
		matrixop /free w_temp_rotate_x_result = m_rotation_x x w_temp_rotate_x
		inout[0,2][ivec] = w_temp_rotate_x_result[p]
	endfor
end

/// rotates a wave of 3-vectors about the y axis
///
/// this function rotates multiple vectors.
///
/// @param[in,out]	inout		wave with dimensions (M, N), M >= 3 (x, y, z), N >= 1.
/// 								the result will be in same wave.
///								only the first three rows of dimension 0 are used,
///								extra rows are left unchanged.
/// @param[in]		angle		rotation angle in degrees.
///
/// @return none
///
function rotate_y_wave(inout, angle)
	wave inout
	variable angle

	wave m_rotation_y = create_rotation_matrix_free()
	make /n=3/d/free w_temp_rotate_y
	variable ivec, nvec
	nvec = max(DimSize(inout, 1), 1)
	for (ivec = 0; ivec < nvec; ivec += 1)
		set_rotation_y(m_rotation_y, angle)
		w_temp_rotate_y = inout[p][ivec]
		matrixop /free w_temp_rotate_y_result = m_rotation_y x w_temp_rotate_y
		inout[0,2][ivec] = w_temp_rotate_y_result[p]
	endfor	
end

/// rotates a wave of 3-vectors about the z axis
///
/// this function rotates multiple vectors.
///
/// @param[in,out]	inout		wave with dimensions (M, N), M >= 3 (x, y, z), N >= 1.
/// 								the result will be in same wave.
///								only the first three rows of dimension 0 are used,
///								extra rows are left unchanged.
/// @param[in]		angle		rotation angle in degrees.
///
/// @return none
///
function rotate_z_wave(inout, angle)
	wave inout
	variable angle

	wave m_rotation_z = create_rotation_matrix_free()
	make /n=3/d/free w_temp_rotate_z
	variable ivec, nvec
	nvec = max(DimSize(inout, 1), 1)
	for (ivec = 0; ivec < nvec; ivec += 1)
		set_rotation_z(m_rotation_z, angle)
		w_temp_rotate_z = inout[p][ivec]
		matrixop /free w_temp_rotate_z_result = m_rotation_z x w_temp_rotate_z
		inout[0,2][ivec] = w_temp_rotate_z_result[p]
	endfor	
end
