view.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:9k
源码类别:

GIS编程

开发平台:

Visual C++

  1. /*
  2.  * MODULE Name: view.c
  3.  *
  4.  * FUNCTION:
  5.  * This module provides two different routines that compute and return
  6.  * viewing matrices.  Both routines take a direction and an up vector, 
  7.  * and return a matrix that transforms the direction to the z-axis, and
  8.  * the up-vector to the y-axis.
  9.  * 
  10.  * HISTORY:
  11.  * written by Linas Vepstas August 1991
  12.  * Added double precision interface, March 1993, Linas
  13.  */
  14. #include <math.h>
  15. #include "rot.h"
  16. #include "gutil.h"
  17. #include "vvector.h"
  18. /* ============================================================ */
  19. /*
  20.  * The uviewdirection subroutine computes and returns a 4x4 rotation
  21.  * matrix that puts the negative z axis along the direction v21 and 
  22.  * puts the y axis along the up vector.
  23.  *
  24.  * Note that this code is fairly tolerant of "weird" paramters.
  25.  * It normalizes when necessary, it does nothing when vectors are of
  26.  * zero length, or are co-linear.  This code shouldn't croak, no matter
  27.  * what the user sends in as arguments.
  28.  */
  29. #ifdef __GUTIL_DOUBLE
  30. void uview_direction_d (double m[4][4], /* returned */
  31.                         double v21[3], /* input */
  32.                         double up[3]) /* input */
  33. #else
  34. void uview_direction_f (float m[4][4], /* returned */
  35.                         float v21[3], /* input */
  36.                         float up[3]) /* input */
  37. #endif
  38. {
  39.    double amat[4][4];
  40.    double bmat[4][4];
  41.    double cmat[4][4];
  42.    double v_hat_21[3];
  43.    double v_xy[3];
  44.    double sine, cosine;
  45.    double len;
  46.    double up_proj[3];
  47.    double tmp[3];
  48.    /* find the unit vector that points in the v21 direction */
  49.    VEC_COPY (v_hat_21, v21);    
  50.    VEC_LENGTH (len, v_hat_21);
  51.    if (len != 0.0) {
  52.       len = 1.0 / len;
  53.       VEC_SCALE (v_hat_21, len, v_hat_21);
  54.       /* rotate z in the xz-plane until same latitude */
  55.       sine = sqrt ( 1.0 - v_hat_21[2] * v_hat_21[2]);
  56.       ROTY_CS (amat, (-v_hat_21[2]), (-sine));
  57.    } else {
  58.       /* error condition: zero length vecotr passed in -- do nothing */
  59.       IDENTIFY_MATRIX_4X4 (amat);
  60.    }
  61.    /* project v21 onto the xy plane */
  62.    v_xy[0] = v21[0];
  63.    v_xy[1] = v21[1];
  64.    v_xy[2] = 0.0;
  65.    VEC_LENGTH (len, v_xy);
  66.    /* rotate in the x-y plane until v21 lies on z axis ---
  67.     * but of course, if its already there, do nothing */
  68.    if (len != 0.0) { 
  69.       /* want xy projection to be unit vector, so that sines/cosines pop out */
  70.       len = 1.0 / len;
  71.       VEC_SCALE (v_xy, len, v_xy);
  72.       /* rotate the projection of v21 in the xy-plane over to the x axis */
  73.       ROTZ_CS (bmat, v_xy[0], v_xy[1]);
  74.       /* concatenate these together */
  75.       MATRIX_PRODUCT_4X4 (cmat, amat, bmat);
  76.    } else {
  77.       /* no-op -- vector is already in correct position */
  78.       COPY_MATRIX_4X4 (cmat, amat);
  79.    }
  80.    /* up vector really should be perpendicular to the x-form direction --
  81.     * Use up a couple of cycles, and make sure it is, 
  82.     * just in case the user blew it.
  83.     */
  84.    VEC_PERP (up_proj, up, v_hat_21); 
  85.    VEC_LENGTH (len, up_proj);
  86.    if (len != 0.0) {
  87.       /* normalize the vector */
  88.       len = 1.0/len;
  89.       VEC_SCALE (up_proj, len, up_proj);
  90.    
  91.       /* compare the up-vector to the  y-axis to get the cosine of the angle */
  92.       tmp [0] = cmat [1][0];
  93.       tmp [1] = cmat [1][1];
  94.       tmp [2] = cmat [1][2];
  95.       VEC_DOT_PRODUCT (cosine, tmp, up_proj);
  96.    
  97.       /* compare the up-vector to the x-axis to get the sine of the angle */
  98.       tmp [0] = cmat [0][0];
  99.       tmp [1] = cmat [0][1];
  100.       tmp [2] = cmat [0][2];
  101.       VEC_DOT_PRODUCT (sine, tmp, up_proj);
  102.    
  103.       /* rotate to align the up vector with the y-axis */
  104.       ROTZ_CS (amat, cosine, -sine);
  105.    
  106.       /* This xform, although computed last, acts first */
  107.       MATRIX_PRODUCT_4X4 (m, amat, cmat);
  108.    } else {
  109.       /* error condition: up vector is indeterminate (zero length) 
  110.        * -- do nothing */
  111.       COPY_MATRIX_4X4 (m, cmat);
  112.    }
  113. }
  114. /* ============================================================ */
  115. #ifdef __STALE_CODE
  116. /*
  117.  * The uview_dire subroutine computes and returns a 4x4 rotation
  118.  * matrix that puts the negative z axis along the direction v21 and 
  119.  * puts the y axis along the up vector.
  120.  * 
  121.  * It computes exactly the same matrix as the code above
  122.  * (uview_direction), but with an entirely different (and slower)
  123.  * algorithm.
  124.  *
  125.  * Note that the code below is slightly less robust than that above --
  126.  * it may croak if the supplied vectors are of zero length, or are
  127.  * parallel to each other ... 
  128.  */
  129. void uview_dire (float m[4][4], /* returned */
  130.                  float v21[3], /* input */
  131.                  float up[3]) /* input */
  132. {
  133.    double theta;
  134.    float v_hat_21 [3];
  135.    float z_hat [3];
  136.    float v_cross_z [3];
  137.    float u[3];
  138.    float y_hat [3];
  139.    float u_cross_y [3];
  140.    double cosine;
  141.    float zmat [4][4];
  142.    float upmat[4][4];
  143.    float dot;
  144.    /* perform rotation to z-axis only if not already 
  145.     * pointing down z */
  146.    if ((v21[0] != 0.0 ) || (v21[1] != 0.0)) {
  147.       /* find the unit vector that points in the v21 direction */
  148.       VEC_COPY (v_hat_21, v21);    
  149.       VEC_NORMALIZE (v_hat_21);
  150.    
  151.       /* cosine theta equals v_hat dot z_hat */
  152.       cosine = - v_hat_21 [2];
  153.       theta = - acos (cosine);
  154.    
  155.       /* Take cros product with z -- we need this, because we will rotate
  156.        * about this axis */
  157.       z_hat[0] = 0.0;
  158.       z_hat[1] = 0.0;
  159.       z_hat[2] = -1.0;
  160.    
  161.       VEC_CROSS_PRODUCT (v_cross_z, v_hat_21, z_hat);
  162.       VEC_NORMALIZE (v_cross_z);
  163.    
  164.       /* compute rotation matrix that takes -z axis to the v21 axis */
  165.       urot_axis (zmat, (float) theta, v_cross_z);
  166.    } else {
  167.       IDENTIFY_MATRIX_4X4 (zmat);
  168.       if (v21[2] > 0.0) {
  169.          /* if its pointing down the positive z-axis, flip it, so that
  170.           * we point down negative z-axis.  We flip x so that the partiy
  171.           * isn't destroyed (looks like a rotation)
  172.           */
  173.          zmat[0][0] = -1.0;
  174.          zmat[2][2] = -1.0;
  175.       }
  176.    }
  177.    
  178.    /* --------------------- */
  179.    /* OK, now compute the part that takes the y-axis to the up vector */
  180.    VEC_COPY (u, up);
  181.    /* the rotation blows up, if the up vector is not perpendicular to
  182.     * the v21 vector.  Let us make sure that this is so. */
  183.    VEC_PERP (u, u, v_hat_21);
  184.    /* need to run the y axis through above x-form, to see where it went */
  185.    y_hat[0] = zmat [1][0];
  186.    y_hat[1] = zmat [1][1];
  187.    y_hat[2] = zmat [1][2];
  188.    
  189.    /* perform rotation to up-axis only if not already 
  190.     * pointing along y axis */
  191.    VEC_DOT_PRODUCT (dot, y_hat, u);
  192.    if ((-1.0 < dot) && (dot < 1.0))  {
  193.       /* make sure that up really is a unit vector */
  194.       VEC_NORMALIZE (u);
  195.       /* cosine phi equals y_hat dot up_vec */
  196.       VEC_DOT_PRODUCT (cosine, u, y_hat);
  197.       theta = - acos (cosine);
  198.    
  199.       /* Take cross product with y */
  200.       VEC_CROSS_PRODUCT (u_cross_y, u, y_hat);
  201.       VEC_NORMALIZE (u_cross_y);
  202.    
  203.       /* As a matter of fact, u_cross_y points either in the v21 direction,
  204.        * or in the minus v21 direction.  In either case, we needed to compute 
  205.        * it, because the the arccosine function returns values only for 
  206.        * 0 to 180 degree, not 0 to 360, which is what we need.  The 
  207.        * cross-product helps us make up for this.
  208.        */
  209.       /* rotate about the NEW z axis (i.e. v21) by the cosine */
  210.       urot_axis (upmat, (float) theta, u_cross_y);
  211.    } else {
  212.       IDENTIFY_MATRIX_4X4 (upmat);
  213.       if (dot == -1.0) {
  214.          /* if its pointing along the negative y-axis, flip it, so that
  215.           * we point along the positive y-axis.  We flip x so that the partiy
  216.           * isn't destroyed (looks like a rotation)
  217.           */
  218.          upmat[0][0] = -1.0;
  219.          upmat[1][1] = -1.0;
  220.       }
  221.    }
  222.    
  223.    MATRIX_PRODUCT_4X4 (m, zmat, upmat);
  224. }
  225. #endif /* __STALE_CODE */
  226. /* ============================================================ */
  227. /*
  228.  * The uviewpoint subroutine computes and returns a 4x4 matrix that 
  229.  * translates the origen to the point v1, puts the negative z axis
  230.  * along the direction v21==v2-v1, and puts the y axis along the up
  231.  * vector.
  232.  */
  233. #ifdef __GUTIL_DOUBLE
  234. void uviewpoint_d (double m[4][4], /* returned */
  235.                    double v1[3], /* input */
  236.                    double v2[3], /* input */
  237.                    double up[3]) /* input */
  238. #else 
  239. void uviewpoint_f (float m[4][4], /* returned */
  240.                    float v1[3], /* input */
  241.                    float v2[3], /* input */
  242.                    float up[3]) /* input */
  243. #endif
  244. {
  245. #ifdef __GUTIL_DOUBLE
  246.    double v_hat_21 [3];
  247.    double trans_mat[4][4];
  248.    double rot_mat[4][4];
  249. #else
  250.    float v_hat_21 [3];
  251.    float trans_mat[4][4];
  252.    float rot_mat[4][4];
  253. #endif
  254.    /* find the vector that points in the v21 direction */
  255.    VEC_DIFF (v_hat_21, v2, v1);
  256.    /* compute rotation matrix that takes -z axis to the v21 axis,
  257.     * and y to the up dierction */
  258. #ifdef __GUTIL_DOUBLE
  259.    uview_direction_d (rot_mat, v_hat_21, up);
  260. #else
  261.    uview_direction_f (rot_mat, v_hat_21, up);
  262. #endif
  263.    /* build matrix that translates the origin to v1 */
  264.    IDENTIFY_MATRIX_4X4 (trans_mat);
  265.    trans_mat[3][0] = v1[0];
  266.    trans_mat[3][1] = v1[1];
  267.    trans_mat[3][2] = v1[2];
  268.    /* concatenate the matrices together */
  269.    MATRIX_PRODUCT_4X4 (m, rot_mat, trans_mat);
  270. }
  271. /* ================== END OF FILE ============================ */