:- module vector. % a 3D vector module. :- interface. :- import_module float. :- import_module pair. :- type real == float. :- type vector ---> point(real, real, real). :- type position == point. :- type point == vector. :- func '+'(vector, vector) = vector. :- func '-'(vector, vector) = vector. :- func '-'(vector) = vector. :- func dot(vector, vector) = real. % Dot product, but zeroed if not positive. :- func positive_dot(vector, vector) = real. :- func cross(vector, vector) = vector. :- func mag(vector) = real. % The square of the magnitude. :- func mag2(vector) = real. % The square of the distance between two points. :- func distance_squared(point, point) = real. :- func unit(vector) = vector. :- func scale(real, vector) = vector. :- func angle(vector, vector) = real. % ProjectedV1 = project(V1, V2) % Find the projection of V1 onto V2 :- func project(vector, vector) = vector. % Project vector onto XY plane. :- func projectXY(vector) = vector. :- func projectXZ(vector) = vector. :- func projectZY(vector) = vector. % Return a pair containing the X and Y coords of the vector. :- func xy(vector) = pair(real). :- func xz(vector) = pair(real). :- func zy(vector) = pair(real). % Some useful constants. :- func zero = vector. :- func i = vector. :- func j = vector. :- func k = vector. :- func real_epsilon = real. :- func real_max = real. :- implementation. :- import_module math. point(Ax, Ay, Az) + point(Bx, By, Bz) = point(Ax+Bx, Ay+By, Az+Bz). point(Ax, Ay, Az) - point(Bx, By, Bz) = point(Ax-Bx, Ay-By, Az-Bz). -point(X, Y, Z) = point(-X, -Y, -Z). dot(point(Ax, Ay, Az), point(Bx, By, Bz)) = Ax*Bx + Ay*By + Az*Bz. positive_dot(A, B) = PosDot :- dot(A, B) = Dot, ( Dot < 0.0 -> PosDot = 0.0 ; PosDot = Dot ). cross(point(Ax, Ay, Az), point(Bx, By, Bz)) = point(Cx, Cy, Cz) :- Cx = Ay*Bz - Az*By, Cy = Az*Bx - Ax*Bz, Cz = Ax*By - Ay*Bx. mag(V) = math__sqrt(mag2(V)). :- pragma inline(func(mag2/1)). mag2(point(Ax, Ay, Az)) = Ax*Ax + Ay*Ay + Az*Az. distance_squared(point(X1, Y1, Z1), point(X2, Y2, Z2)) = DistanceSquared :- DX = X1 - X2, DY = Y1 - Y2, DZ = Z1 - Z2, DistanceSquared = DX * DX + DY * DY + DZ * DZ. :- pragma inline(func(unit/1)). unit(point(Ax, Ay, Az)) = point(Ax/Mag, Ay/Mag, Az/Mag) :- Mag = mag(point(Ax, Ay, Az)). scale(S, point(Ax, Ay, Az)) = point(S*Ax, S*Ay, S*Az). % calculate angle between 2 vectors angle(V1, V2) = math__acos(dot(V1, V2) / mag(V1) / mag(V2)). project(V1, V2) = Projection :- UnitV2 = unit(V2), Projection = scale(dot(V1, UnitV2), UnitV2). projectXY(point(X, Y, _)) = point(X, Y, 0.0). projectXZ(point(X, _, Z)) = point(X, 0.0, Z). projectZY(point(_, Y, Z)) = point(0.0, Y, Z). xy(point(X, Y, _)) = X - Y. xz(point(X, _, Z)) = X - Z. zy(point(_, Y, Z)) = Z - Y. zero = point(0.0, 0.0, 0.0). i = point(1.0, 0.0, 0.0). j = point(0.0, 1.0, 0.0). k = point(0.0, 0.0, 1.0). real_epsilon = float__epsilon. real_max = float__max.