%---------------------------------------------------------------------------% % vim: ts=4 sw=4 et ft=mercury %---------------------------------------------------------------------------% % % This is a regression test. Some versions of the compiler reported % an internal error when compiling with value numbering. % This code comes from Tom Conway's ray tracer. :- module vn_float. :- interface. :- import_module array. :- import_module list. :- type vec3 ---> vec(float, float, float). :- pred get_planar_coords(list(int), array(vec3), list(vec3), vec3). :- mode get_planar_coords(in, in, out, out) is det. :- implementation. :- import_module float. :- import_module int. :- import_module math. :- import_module require. :- import_module std_util. :- type mat3 ---> mat(vec3, vec3, vec3). get_planar_coords(IndList, VertArr, PlaneList, Norm) :- ( IndList = [Ind1, Ind2, Ind3 | _IndList1] -> % lookup first 3 vertices and calculate normal array__lookup(VertArr, Ind1+1, V1), array__lookup(VertArr, Ind2+1, V2), array__lookup(VertArr, Ind3+1, V3), Norm = unit(cross(V3 - V2, V1 - V2)), get_angles_from_z_axis(Norm, Theta, Phi), % need to rotate -Theta about Z axis then -Phi about Y axis CosZ = math__cos(-Theta), SinZ = math__sin(-Theta), CosY = math__cos(-Phi), SinY = math__sin(-Phi), MZ = mat(vec(CosZ, -SinZ, 0.0), vec(SinZ, CosZ, 0.0), vec(0.0, 0.0, 1.0)), MY = mat(vec(CosY, 0.0, SinY), vec(0.0, 1.0, 0.0), vec(-SinY, 0.0, CosY)), M = matmult(MZ, MY), move_vertices_to_plane(IndList, VertArr, -V1, M, PlaneList) ; error("Something strange has happend to the vertex list") ). :- pred get_angles_from_z_axis(vec3, float, float). :- mode get_angles_from_z_axis(in, out, out) is det. get_angles_from_z_axis(Vec, Theta, Phi) :- ( Vec = vec(X, Y, Z), Vector_radius = mag(Vec), XY_radius = mag(vec(X, Y, 0.0)), % magnitude of xy projection Pi = math__pi, % get a useful constant ( Vector_radius = 0.0 -> error("get_angles_from_z_axis: vector should not be zero-length") ; % check if vector is already on z axis ( XY_radius = 0.0 -> Theta = 0.0, Phi = 0.0 ; Xabs = float__abs(X), Theta1 = math__asin(Xabs / XY_radius), Phi1 = math__asin(XY_radius / Vector_radius), % angles have been calculated for the first octant % they need to be corrected for the octant they are actually in ( X =< 0.0 -> ( Y =< 0.0 -> Theta = Pi + Theta1 ; Theta = Pi - Theta1 ) ; ( Y =< 0.0 -> Theta = -Theta1 ; Theta = Theta1 ) ), ( Z =< 0.0 -> Phi = Phi1 + Pi / 2.0 ; Phi = Phi1 ) ) ) ). :- pred move_vertices_to_plane(list(int), array(vec3), vec3, mat3, list(vec3)). :- mode move_vertices_to_plane(in, in, in, in, out) is det. :- pragma no_inline(move_vertices_to_plane/5). move_vertices_to_plane(_, _, _, _, []). :- func unit(vec3) = vec3. :- pragma no_inline(unit/1). unit(V) = V. :- func cross(vec3, vec3) = vec3. :- pragma no_inline(cross/2). cross(V, _) = V. :- func '-'(vec3, vec3) = vec3. :- pragma no_inline(('-')/2). V - _ = V. :- func '-'(vec3) = vec3. :- pragma no_inline(('-')/1). -V = V. :- func mag(vec3) = float. :- pragma no_inline(mag/1). mag(_) = 42.0. :- func '*'(vec3, mat3) = vec3. :- pragma no_inline('*'/2). V * _ = V. :- func matmult(mat3, mat3) = mat3. :- pragma no_inline(matmult/2). matmult(M, _) = M.