📄 quat_utils.c
字号:
#ifndef lintstatic char sccsid[] = "@(#)quat_utils.c 1.1 92/07/30 Copyr 1989, 1990 Sun Micro";#endif#include <stdio.h>#include <math.h>#include "P_include.h"/* * Sun Microsystems, inc. * Graphics Product Division * * Date: January 11th, 1989 * Author: Patrick-Gilles Maillot * * P_mk_ctx: * This primitive creates a Patk3d context in memory and sets * some default values for the user's parameters. * * The user position is set to [1,0,0], looking in the * direction of the decreasing x axis. * * The lens is set to [0,0,0] which is a direct projection, without * any perspective effect. * * The axis orientations matrix is set to * (0 0 -1 0) * (1 0 0 0) (Sun system). * (0 -1 0 0) * (0 0 0 1) * */P_ctx P_mk_ctx(){P_ctx C;int i;/* * Allocate the memory space for the P3_internxgl_ctx storage */ if (C = (P_ctx)malloc(sizeof(P3_internxgl_ctx))) {/* * Initialize the context with default values */ for (i = 0; i < 3; i++) { C->O.pos[i] = 0.; C->O.rop[i] = 0.; } C->O.rop[3] = 1.; C->O.pos[0] = -1.; C->L.g = 0.; C->L.x = 0.; C->L.y = 0.; C->S.ori[0][0] = 0.0; C->S.ori[0][1] = 0.0; C->S.ori[0][2] = -1.0; C->S.ori[0][3] = 0.0; C->S.ori[1][0] = 1.0; C->S.ori[1][1] = 0.0; C->S.ori[1][2] = 0.0; C->S.ori[1][3] = 0.0; C->S.ori[2][0] = 0.0; C->S.ori[2][1] = -1.0; C->S.ori[2][2] = 0.0; C->S.ori[2][3] = 0.0; C->S.ori[3][0] = 0.0; C->S.ori[3][1] = 0.0; C->S.ori[3][2] = 0.0; C->S.ori[3][3] = 1.0;/* * Compute internal matrices */ P3_quat_mat(C); P3_lens_mat(C); P3_matrix(C); } else { P3_set_error("P_mk_ctx: Unable to create context"); } return (C);}P3_set_error(s)char *s;{ printf("%s\n",s);}/* * Sun Microsystems, inc. * Graphics Product Division * * Date: January 11th, 1989 * Author: Patrick-Gilles Maillot * * P_set_pos: * This primitive updates a Patk3d context in memory by setting * new values for the observer eye's position in the space. * The transformation matrices are also updated. * */P_set_pos(C,x,y,z)P_ctx C;float x, y, z;{int i;/* * Set the values of the eye's position for context C */ C->O.pos[0] = -x; C->O.pos[1] = -y; C->O.pos[2] = -z;/* * Force the visualisation to be in the decreasing x axis */ C->O.rop[3] = 1.; for (i = 0; i < 3; i++) C->O.rop[i] = 0.;/* * Update the internal matrices */ P3_quat_mat(C); P3_matrix(C);}/* * Sun Microsystems, inc. * Graphics Product Division * * Date: January 11th, 1989 * Author: Patrick-Gilles Maillot * * P_set_lens: * This primitive updates a Patk3d context in memory by setting * the new values for the optical parameters. * The transformation matrices are also updated. * */P_set_lens(C,g,x,y)P_ctx C;float g, x, y;{/* * Set the values of the optical lens for context C */ C->L.g = g; C->L.x = x; C->L.y = y;/* * Update the internal matrices */ P3_lens_mat(C); P3_matrix(C);}/* * Sun Microsystems, inc. * Graphics Product Division * * Date: January 11th, 1989 * Author: Patrick-Gilles Maillot * * P_set_orient: * This primitive updates a Patk3d context in memory by setting * new values for the DC axes orientation parameters. * * A 3x3 matrix describes how each unit vector of the user * coordinate system is transformed to match the Sun default * orientation. * * By default, (1, 0, 0) is transformed to be (0, 0, -1) * (0, 1, 0) .....................(1, 0, 0) * (0, 0, 1) .....................(0, -1, 0) * * The transformation matrices are also updated. * */P_set_orient(C,user_ori)P_ctx C;float user_ori[3][3];{int i, j;/* * Set the values of the orientation of each axis for context C */ for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) C->S.ori[i][j] = user_ori[i][j];/* * Update the internal matrices */ P3_lens_mat(C); P3_matrix(C);}/* * Sun Microsystems, inc. * Graphics Product Division * * Date: January 11th, 1989 * Author: Patrick-Gilles Maillot * * P_look_to: * This primitive updates a Patk3d context in memory by setting * new values for the observer vision direction in the space. This * is done by giving a vision point in the space. The vision * direction goes from the observer eye's position to this point. * The transformation matrices are also updated. * */P_look_to(C,x,y,z)P_ctx C;float x, y, z;{float P[4], Q[4];float R, R0, C0, X, Y;int i, j;/* * Compute the visualisation direction according to C->O.pos and x, y, z. * * We need to transform the vision point. */ Q[0] = x; Q[1] = y; Q[2] = z; Q[3] = 1.; for (i = 0; i < 4; i++) { P[i] = 0.; for (j = 0; j < 4; j++) P[i] -= Q[j] * C->M_quat[j][i]; }/* * compute the new quaternion */ R = P[0] * P[0] + P[1] * P[1]; R0 = sqrt(R + P[2] * P[2]);/* * look for special or error cases * * R and R0 are positive! */ if (R > EPSILON) {/* * This is the *normal* case, we need two rotations... */ R = sqrt(R); C0 = P[0] / R; X = sqrt((1. + C0) / 2.); Y = sqrt((1. - C0) / 2.); if (P[1] < 0.) Y = -Y; P3_rot_mov(C,X,Y,2,-1); C0 = R / R0; X = sqrt((1. + C0) / 2.); Y = sqrt((1. - C0) / 2.); if (P[2] > 0.) Y = -Y; P3_rot_mov(C,X,Y,1,-1); } else {/* * If R0 is null... That means the two points are the same! */ if (R0 < EPSILON) { P3_set_error("Error: Vision and eye's positions are the same"); return; }/* * Here, the vision position is vertical to the eye's position. * We decide to move the vision direction up or down of 90 degrees, * upon the sign of the z component. */ X = Y = .7071068; /* sin(45) */ if (P[2] > 0.) Y = -Y; P3_rot_mov(C,X,Y,1,-1); }/* * Update the internal matrices */ P3_quat_mat(C); P3_matrix(C);}/* * Sun Microsystems, inc. * Graphics Product Division * * Date: January 11th, 1989 * Author: Patrick-Gilles Maillot * * P3_tra_mov: * This function computes translation movments for a given * quaternion. * * "i" is the axis of the translation, while x is the parameter * that caracterize the translation for the quaternion of the * context C. * * "w" is set to -1 if the observer moves in respect * to the scene, 1 if the scene moves in respect to * the observer. * */P3_tra_mov(C,x,i,w)P_ctx C;float x;int i, w;{int j, k;float A, B, D, E, F; if (w < 0) {/* * The observer moves in respect to the scene. */ C->O.pos[i] -= x; } else {/* * The scene moves in respect to the observer. * Compute the successor axis of i [0,1,2]; * and then the successor axis of j [0,1,2]; */ if ((j = i + 1) > 2) j = 0; if ((k = j + 1) > 2) k = 0; A = C->O.rop[j]; B = C->O.rop[k]; F = C->O.rop[3]; E = C->O.rop[i]; C->O.pos[i] += x * (E * E + F * F - A * A - B * B); D = x + x; C->O.pos[j] += D * (E * A + F * B); C->O.pos[k] += D * (E * B + F * A); }}/* * Sun Microsystems, inc. * Graphics Product Division * * Date: January 11th, 1989 * Author: Patrick-Gilles Maillot * * P3_rot_mov: * This function computes rotation based movments for a given * quaternion. * * "i" is the axis of the rotation, while x and y are the * parameters that caracterize the rotation for the quaternion * of the context C. * * "w" is set to -1 if the observer moves in respect * to the scene, 1 if the scene moves in respect to * the observer. * * "x" and "y" are typically the cosinus and sinus of the half * rotation angle. * */P3_rot_mov(C,x,y,i,w)P_ctx C;float x, y;int i, w;{int j, k;float E, F, R1;/* * Compute the successor axis of i [0,1,2]; * and then the successor axis of j [0,1,2]; */ if ((j = i + 1) > 2) j = 0; if ((k = j + 1) > 2) k = 0; E = C->O.rop[i]; C->O.rop[i] = E * x + w * y * C->O.rop[3]; C->O.rop[3] = C->O.rop[3] * x - w * y * E; E = C->O.rop[j]; C->O.rop[j] = E * x + y * C->O.rop[k]; C->O.rop[k] = C->O.rop[k] * x - y * E; if (w < 0) {/* * As the observer moves in respect to the scene, we * need to compute the new scene's position in respect to * the observer. */ R1 = x * x - y * y; F = 2. * x * y; E = C->O.pos[j]; C->O.pos[j] = E * R1 + F * C->O.pos[k]; C->O.pos[k] *= R1; C->O.pos[k] -= F * E; }}/* * Sun Microsystems, inc. * Graphics Product Division * * Date: January 11th, 1989 * Author: Patrick-Gilles Maillot * * P_3D_move: * This primitive updates a Patk3d context in memory by setting * new values for the observer eye's position in the space. * * It gives to the user the capability to move in the 6 * liberty axes. The following movement codes are recognized: * * rr a: roll right of angle a in degrees. * rl a: roll left of angle a in degrees. * pf a: pitch forward of angle a in degrees. * pb a: pitch backward of angle a in degrees. * yr a: yaw right of angle a in degrees. * yl a: yaw left of angle a in degrees. * * fw x: forward movement of x units. * bw x: backward movement of x units. * rt x: right movement of x units. * lt x: left movement of x units. * up x: up movement of x units. * dn x: down movement of x units. * * The anglular values should be [-90..+90]. * * The transformation matrices are also updated. * */P_3D_move(C,desc)P_ctx C;char *desc;{int i, j, moved, called, axe;char ch[4];float val, x, y; moved = 0; i = 0; j = 0;/* * Read the descriptor, and for each recognized code, select the * correct call to either P3_tra_mov or P3_rot_mov to update the * quaternion. */ while (sscanf(&desc[j],"%s%n",ch,&i) != EOF) { switch (ch[0]) { case 'r' :/* * rr a: roll right of angle a in degrees. * rl a: roll left of angle a in degrees. * rt x: right movement of x units. */ switch (ch[1]) { case 'r' : called = 1; axe = -1; break; case 'l' : called = 1; axe = 1; break; case 't' : called = 2; axe = 2; break; default : called = 0; break; } break;/* * pf a: pitch forward of angle a in degrees. * pb a: pitch backward of angle a in degrees. */ case 'p' : switch (ch[1]) { case 'f' : called = 1; axe = -2; break; case 'b' : called = 1; axe = 2; break; default : called = 0; break; } break;/* * yr a: yaw right of angle a in degrees. * yl a: yaw left of angle a in degrees. */ case 'y' : switch (ch[1]) { case 'r' : called = 1; axe = -3; break; case 'l' : called = 1; axe = 3; break; default : called = 0; break; } break;/* * fw x: forward movement of x units. * bw x: backward movement of x units. * lt x: left movement of x units. * up x: up movement of x units. * dn x: down movement of x units. */ case 'f' : called = 2; axe = -1; break; case 'b' : called = 2; axe = 1; break; case 'l' : called = 2; axe = -2; break; case 'u' : called = 2; axe = 3; break; case 'd' : called = 2; axe = -3; break; default: called = 0; break; } j += i; if ((called) && (sscanf(&desc[j],"%f%n",&val,&i) != EOF )) { if (axe < 0) { val = -val; axe = -axe - 1; } else { axe -= 1; } if (called == 1) {/* * Convert val as the half angle, in radians. * radiand = degree * PI / 180, and /2 for half angle. */ val /= 114.591559026; x = cos(val); y = sin(val); P3_rot_mov(C,x,y,axe,-1); } else { P3_tra_mov(C,val,axe,-1); } moved = 1; j += i; } else { P3_set_error("Error: In P_3D_move descriptor, near: rr"); } }/* * Update the internal matrices */ if (moved) { P3_quat_mat(C); P3_matrix(C); }}/* * Sun Microsystems, inc. * Graphics Product Division * * Date: January 11th, 1989 * Author: Patrick-Gilles Maillot * * P3_quat_mat: * This primitive (re)computes the matrix that corresponds * to the observer's eye position and direction. * * This is done by using the quaternion definition of the * context visualisation direction and the position of the * eye in the WC space. * */P3_quat_mat(C)P3_internxgl_ctx *C;{float e, f, r[4];int i, j, k;/* * We will need some square values! */ for (i = 0; i < 4; i++) r[i] = C->O.rop[i] * C->O.rop[i];/* * Compute each element of the matrix. * j is the successor of i (in 0, 1, 2), while k is the successor of j. */ for (i = 0; i < 3; i++) { if ((j = i + 1) > 2) j = 0; if ((k = j + 1) > 2) k = 0; e = 2. * C->O.rop[i] * C->O.rop[j]; f = 2. * C->O.rop[k] * C->O.rop[3]; C->M_quat[j][i] = e - f; C->M_quat[i][j] = e + f; C->M_quat[i][i] = r[i] + r[3] - r[j] - r[k]; C->M_quat[3][i] = C->O.pos[i]; C->M_quat[i][3] = 0.; } C->M_quat[3][3] = 1.;}/* * Sun Microsystems, inc. * Graphics Product Division * * Date: January 11th, 1989 * Author: Patrick-Gilles Maillot * * P3_lens_mat: * This primitive (re)computes the matrix that corresponds * to the observer's lens system -also called optical trans * formation- for the perspective projection. * It combines the lens itself, but also the orientation to apply * to the components of the viewing system. * * * */P3_lens_mat(C)P3_internxgl_ctx *C;{float mat[4][4];int i;/* * Compute each element of the matrix. */ for (i = 0; i < 4; i++) { mat[i][0] = 0.0; mat[i][1] = 0.0; mat[i][2] = 0.0; mat[i][3] = 0.0; mat[i][i] = 1.0; } mat[2][0] = C->L.x; mat[2][1] = C->L.y; mat[2][3] = C->L.g; P3_u_4x4(C->M_lens,C->S.ori,mat);}/* * Sun Microsystems, inc. * Graphics Product Division * * Date: January 11th, 1989 * Author: Patrick-Gilles Maillot * * P3_u_4x4: * Utility function: 4x4 matrix product. * */P3_u_4x4(m1,m2,m3)float m1[4][4], m2[4][4], m3[4][4];{int i, j, k;/* * Compute the 4x4 matrix product m1 = m2 * m3 */ for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { m1[i][j] = 0.; for (k = 0; k < 4; k++) m1[i][j] += m2[i][k] * m3[k][j]; } }}/* * Sun Microsystems, inc. * Graphics Product Division * * Date: January 11th, 1989 * Author: Patrick-Gilles Maillot * * P3_matrix: * This primitive (re)computes the matrix that corresponds * to ALL the transformations to be executed from the WC, * to the DC space, including the optical projection. * * M_all = M_quat * M_lens * */P3_matrix(C)P3_internxgl_ctx *C;{int i, j, k;float r; P3_u_4x4(C->M_all,C->M_quat,C->M_lens);/* * Compute the M_all optimization flag matrices: * M_of_0[i,j] = 0 if M_all[i,j] = 0. * = 1 else. * M_of_1[i,j] = 0 if M_all[i,j] != 1. * = 1 else. * * Note that M_of_x[i][j] is evaluated as the bit ((1 << j) << i) * of M_of_x. */ k = 1; C->M_of_1 = 0; C->M_of_0 = 0; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { r = C->M_all[i][j]; if ((r < (1. + EPSILON)) && (r > (1. - EPSILON))) { C->M_of_1 |= k; } else { if ((r > EPSILON) || (r < -EPSILON)) C->M_of_0 |= k; } k <<= 1; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -