%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%

% Basic geometric transformations.
:- module transform.

:- interface.

:- import_module eval.
:- import_module vector.

	% translate(Point, Tx, Ty, Tz) = TranslatedPoint.
:- func translate(point, float, float, float) = point.

	% scale(Point, Sx, Sy, Sz) = ScaledPoint
:- func scale(point, float, float, float) = point.

	% isotropic_scale(Point, S) = scale(Point, S, S, S).
:- func isotropic_scale(point, float) = point.

	% rotate_x(Point, AngleInDegrees) = RotatedPoint.
:- func rotate_x(point, float) = point.

	% rotate_y(Point, AngleInDegrees) = RotatedPoint.
:- func rotate_y(point, float) = point.

	% rotate_z(Point, AngleInDegrees) = RotatedPoint.
:- func rotate_z(point, float) = point.

:- implementation.

:- import_module float.
:- import_module math.

translate(point(X, Y, Z), Tx, Ty, Tz) = point(X + Tx, Y + Ty, Z + Tz).

scale(point(X, Y, Z), Sx, Sy, Sz) = point(X * Sx, Y * Sy, Z * Sz).

isotropic_scale(Point, S) = scale(Point, S, S, S).

rotate_x(point(X, Y, Z), Degrees) =
		point(X, Y * Cos - Z * Sin, Y * Sin + Z * Cos) :-
	cos_and_sin(Degrees, Cos, Sin).

rotate_y(point(X, Y, Z), Degrees) =
		point(X * Cos + Z * Sin, Y, - X * Sin + Z * Cos) :-
	cos_and_sin(Degrees, Cos, Sin).

rotate_z(point(X, Y, Z), Degrees) =
		point(X * Cos - Y * Sin, X * Sin + Cos * Y, Z) :-
	cos_and_sin(Degrees, Cos, Sin).

:- pred cos_and_sin(float, float, float).
:- mode cos_and_sin(in, out, out) is det.

cos_and_sin(Degrees, Cos, Sin) :-
	% XXX It might be worth doing this conversion when the angle is
	% read in to avoid doing multiple conversions.
	Radians = Degrees / (2.0 * math.pi),
	Cos = math.cos(Radians),
	Sin = math.sin(Radians).
