home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / extensions / lib / PEXlib / pl_util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-09  |  78.5 KB  |  3,281 lines

  1. /* $XConsortium: pl_util.c,v 1.7 92/09/09 15:58:50 mor Exp $ */
  2.  
  3. /******************************************************************************
  4. Copyright 1987,1991 by Digital Equipment Corporation, Maynard, Massachusetts
  5. Copyright 1992 by the Massachusetts Institute of Technology
  6.  
  7.                         All Rights Reserved
  8.  
  9. Permission to use, copy, modify, distribute, and sell this software and its
  10. documentation for any purpose is hereby granted without fee, provided that
  11. the above copyright notice appear in all copies and that both that copyright
  12. notice and this permission notice appear in supporting documentation, and that
  13. the name of Digital or M.I.T. not be used in advertising or publicity
  14. pertaining to distribution of the software without specific, written prior
  15. permission.  Digital and M.I.T. make no representations about the suitability
  16. of this software for any purpose.  It is provided "as is" without express or
  17. implied warranty.
  18.  
  19. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  20. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  21. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  22. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  23. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  24. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  25. SOFTWARE.
  26. ******************************************************************************/
  27.  
  28. #include <math.h>
  29. #include "PEXlib.h"
  30. #include "PEXlibint.h"
  31. #include "pl_util.h"
  32.  
  33.  
  34. int
  35. PEXRotate (axis, angle, matrix_return)
  36.  
  37. INPUT int        axis;
  38. INPUT double        angle;
  39. OUTPUT PEXMatrix    matrix_return;
  40.  
  41. {
  42.     double    sine;
  43.     double    cosine;
  44.  
  45.     sine = sin (angle);
  46.     cosine = cos (angle);
  47.  
  48.     switch (axis)
  49.     {
  50.     case PEXXAxis:
  51.         matrix_return[0][0] = 1.0;
  52.         matrix_return[0][1] = 0.0;
  53.         matrix_return[0][2] = 0.0;
  54.         matrix_return[0][3] = 0.0;
  55.  
  56.         matrix_return[1][0] = 0.0;
  57.         matrix_return[1][1] = cosine;
  58.         matrix_return[1][2] = -sine;
  59.         matrix_return[1][3] = 0.0;
  60.  
  61.         matrix_return[2][0] = 0.0;
  62.         matrix_return[2][1] = sine;
  63.         matrix_return[2][2] = cosine;
  64.         matrix_return[2][3] = 0.0;
  65.  
  66.         matrix_return[3][0] = 0.0;
  67.         matrix_return[3][1] = 0.0;
  68.         matrix_return[3][2] = 0.0;
  69.         matrix_return[3][3] = 1.0;
  70.         break;
  71.  
  72.     case PEXYAxis:
  73.         matrix_return[0][0] = cosine;
  74.         matrix_return[0][1] = 0.0;
  75.         matrix_return[0][2] = sine;
  76.         matrix_return[0][3] = 0.0;
  77.  
  78.         matrix_return[1][0] = 0.0;
  79.         matrix_return[1][1] = 1.0;
  80.         matrix_return[1][2] = 0.0;
  81.         matrix_return[1][3] = 0.0;
  82.  
  83.         matrix_return[2][0] = -sine;
  84.         matrix_return[2][1] = 0.0;
  85.         matrix_return[2][2] = cosine;
  86.         matrix_return[2][3] = 0.0;
  87.  
  88.         matrix_return[3][0] = 0.0;
  89.         matrix_return[3][1] = 0.0;
  90.         matrix_return[3][2] = 0.0;
  91.         matrix_return[3][3] = 1.0;
  92.         break;
  93.  
  94.     case PEXZAxis:
  95.         matrix_return[0][0] = cosine;
  96.         matrix_return[0][1] = -sine;
  97.         matrix_return[0][2] = 0.0;
  98.         matrix_return[0][3] = 0.0;
  99.  
  100.         matrix_return[1][0] = sine;
  101.         matrix_return[1][1] = cosine;
  102.         matrix_return[1][2] = 0.0;
  103.         matrix_return[1][3] = 0.0;
  104.  
  105.         matrix_return[2][0] = 0.0;
  106.         matrix_return[2][1] = 0.0;
  107.         matrix_return[2][2] = 1.0;
  108.         matrix_return[2][3] = 0.0;
  109.  
  110.         matrix_return[3][0] = 0.0;
  111.         matrix_return[3][1] = 0.0;
  112.         matrix_return[3][2] = 0.0;
  113.         matrix_return[3][3] = 1.0;
  114.         break;
  115.  
  116.     default:
  117.         return (PEXBadAxis);     /* error - invalid axis specifier */
  118.     }
  119.  
  120.     return (0);
  121. }
  122.  
  123.  
  124. void
  125. PEXRotate2D (angle, matrix_return)
  126.  
  127. INPUT double        angle;
  128. OUTPUT PEXMatrix3x3    matrix_return;
  129.  
  130. {
  131.     double    sine;
  132.     double    cosine;
  133.  
  134.     sine = sin (angle);
  135.     cosine = cos (angle);
  136.  
  137.     matrix_return[0][0] = cosine;
  138.     matrix_return[0][1] = -sine;
  139.     matrix_return[0][2] = 0.0;
  140.  
  141.     matrix_return[1][0] = sine;
  142.     matrix_return[1][1] = cosine;
  143.     matrix_return[1][2] = 0.0;
  144.  
  145.     matrix_return[2][0] = 0.0;
  146.     matrix_return[2][1] = 0.0;
  147.     matrix_return[2][2] = 1.0;
  148. }
  149.  
  150.  
  151. int
  152. PEXRotateGeneral (point1, point2, angle, matrix_return)
  153.  
  154. INPUT PEXCoord        *point1;
  155. INPUT PEXCoord        *point2;
  156. INPUT double        angle;
  157. OUTPUT PEXMatrix    matrix_return;
  158.  
  159. {
  160.     PEXMatrix    preMatrix, calcMatrix, postMatrix, tempMatrix;
  161.     PEXCoord    diff, rot;
  162.     float    dist, temp, s;
  163.     double    sine, cosine;
  164.     int        i, j;
  165.  
  166.     /*
  167.      * The matrix is calculated as preMatrix * calcMatrix * postMatrix
  168.      * where postMatrix translates by point1 and preMatrix translates back
  169.      * by point1 and calcMatrix does the real work.
  170.      */
  171.  
  172.     preMatrix[0][0] = 1.0;
  173.     preMatrix[0][1] = 0.0;
  174.     preMatrix[0][2] = 0.0;
  175.     preMatrix[0][3] = point1->x;
  176.  
  177.     preMatrix[1][0] = 0.0;
  178.     preMatrix[1][1] = 1.0;
  179.     preMatrix[1][2] = 0.0;
  180.     preMatrix[1][3] = point1->y;
  181.  
  182.     preMatrix[2][0] = 0.0;
  183.     preMatrix[2][1] = 0.0;
  184.     preMatrix[2][2] = 1.0;
  185.     preMatrix[2][3] = point1->z;
  186.  
  187.     preMatrix[3][0] = 0.0;
  188.     preMatrix[3][1] = 0.0;
  189.     preMatrix[3][2] = 0.0;
  190.     preMatrix[3][3] = 1.0;
  191.  
  192.  
  193.     postMatrix[0][0] = 1.0;
  194.     postMatrix[0][1] = 0.0;
  195.     postMatrix[0][2] = 0.0;
  196.     postMatrix[0][3] = -(point1->x);
  197.  
  198.     postMatrix[1][0] = 0.0;
  199.     postMatrix[1][1] = 1.0;
  200.     postMatrix[1][2] = 0.0;
  201.     postMatrix[1][3] = -(point1->y);
  202.  
  203.     postMatrix[2][0] = 0.0;
  204.     postMatrix[2][1] = 0.0;
  205.     postMatrix[2][2] = 1.0;
  206.     postMatrix[2][3] = -(point1->z);
  207.  
  208.     postMatrix[3][0] = 0.0;
  209.     postMatrix[3][1] = 0.0;
  210.     postMatrix[3][2] = 0.0;
  211.     postMatrix[3][3] = 1.0;
  212.  
  213.  
  214.     /*
  215.      * Compute calcMatrix
  216.      */
  217.  
  218.     diff.x = point2->x - point1->x;
  219.     diff.y = point2->y - point1->y;
  220.     diff.z = point2->z - point1->z;
  221.  
  222.     dist = sqrt (diff.x * diff.x + diff.y * diff.y + diff.z * diff.z);
  223.  
  224.     if (NEAR_ZERO (dist))
  225.     return (PEXBadAxis);
  226.  
  227.     rot.x = diff.x = diff.x / dist;    /* normalize rotation vector */
  228.     rot.y = diff.y = diff.y / dist;
  229.     rot.z = diff.z = diff.z / dist;
  230.  
  231.     rot.x = rot.x * rot.x;        /* square it */
  232.     rot.y = rot.y * rot.y;
  233.     rot.z = rot.z * rot.z;
  234.  
  235.     cosine = cos (angle);
  236.     sine = sin (angle);
  237.  
  238.     calcMatrix[0][0] = rot.x + cosine * (1.0 - rot.x);
  239.     calcMatrix[1][1] = rot.y + cosine * (1.0 - rot.y);
  240.     calcMatrix[2][2] = rot.z + cosine * (1.0 - rot.z);
  241.  
  242.     temp = diff.x * diff.y * (1.0 - cosine);
  243.     s = sine * diff.z;
  244.  
  245.     calcMatrix[1][0] = temp - s;
  246.     calcMatrix[0][1] = temp + s;
  247.  
  248.     temp = diff.x * diff.z * (1.0 - cosine);
  249.     s = sine * diff.y;
  250.  
  251.     calcMatrix[2][0] = temp + s;
  252.     calcMatrix[0][2] = temp - s;
  253.  
  254.     temp = diff.y * diff.z * (1.0 - cosine);
  255.     s = sine * diff.x;
  256.  
  257.     calcMatrix[2][1] = temp - s;
  258.     calcMatrix[1][2] = temp + s;
  259.  
  260.     calcMatrix[0][3] = 0.0;
  261.     calcMatrix[1][3] = 0.0;
  262.     calcMatrix[2][3] = 0.0;
  263.     calcMatrix[3][0] = 0.0;
  264.     calcMatrix[3][1] = 0.0;
  265.     calcMatrix[3][2] = 0.0;
  266.     calcMatrix[3][3] = 1.0;
  267.  
  268.  
  269.     /* Multiply preMatrix by calcMatrix */
  270.  
  271.     for (i = 0; i < 4; i++)
  272.     {
  273.         for (j = 0; j < 4; j++)
  274.         {
  275.             tempMatrix[i][j] = preMatrix[i][0] * calcMatrix[0][j] +
  276.                                preMatrix[i][1] * calcMatrix[1][j] +
  277.                                preMatrix[i][2] * calcMatrix[2][j] +
  278.                                preMatrix[i][3] * calcMatrix[3][j];
  279.         }
  280.     }
  281.  
  282.  
  283.     /* Multiply by postMatrix and return the new matrix */
  284.  
  285.     for (i = 0; i < 4; i++)
  286.     {
  287.         for (j = 0; j < 4; j++)
  288.         {
  289.             matrix_return[i][j] = tempMatrix[i][0] * postMatrix[0][j] +
  290.                                   tempMatrix[i][1] * postMatrix[1][j] +
  291.                                   tempMatrix[i][2] * postMatrix[2][j] +
  292.                                   tempMatrix[i][3] * postMatrix[3][j];
  293.         }
  294.     }
  295.  
  296.     return (0);
  297. }
  298.  
  299.  
  300. void
  301. PEXScale (scale_vector, matrix_return)
  302.  
  303. INPUT PEXVector        *scale_vector;
  304. OUTPUT PEXMatrix    matrix_return;
  305.  
  306. {
  307.     matrix_return[0][0] = scale_vector->x;
  308.     matrix_return[0][1] = 0.0;
  309.     matrix_return[0][2] = 0.0;
  310.     matrix_return[0][3] = 0.0;
  311.  
  312.     matrix_return[1][0] = 0.0;
  313.     matrix_return[1][1] = scale_vector->y;
  314.     matrix_return[1][2] = 0.0;
  315.     matrix_return[1][3] = 0.0;
  316.  
  317.     matrix_return[2][0] = 0.0;
  318.     matrix_return[2][1] = 0.0;
  319.     matrix_return[2][2] = scale_vector->z;
  320.     matrix_return[2][3] = 0.0;
  321.  
  322.     matrix_return[3][0] = 0.0;
  323.     matrix_return[3][1] = 0.0;
  324.     matrix_return[3][2] = 0.0;
  325.     matrix_return[3][3] = 1.0;
  326. }
  327.  
  328.  
  329. void
  330. PEXScale2D (scale_vector, matrix_return)
  331.  
  332. INPUT PEXVector2D    *scale_vector;
  333. OUTPUT PEXMatrix3x3    matrix_return;
  334.  
  335. {
  336.     matrix_return[0][0] = scale_vector->x;
  337.     matrix_return[0][1] = 0.0;
  338.     matrix_return[0][2] = 0.0;
  339.  
  340.     matrix_return[1][0] = 0.0;
  341.     matrix_return[1][1] = scale_vector->y;
  342.     matrix_return[1][2] = 0.0;
  343.  
  344.     matrix_return[2][0] = 0.0;
  345.     matrix_return[2][1] = 0.0;
  346.     matrix_return[2][2] = 1.0;
  347. }
  348.  
  349.  
  350. void
  351. PEXTranslate (trans_vector, matrix_return)
  352.  
  353. INPUT PEXVector        *trans_vector;
  354. OUTPUT PEXMatrix    matrix_return;
  355.  
  356. {
  357.     matrix_return[0][0] = 1.0;
  358.     matrix_return[0][1] = 0.0;
  359.     matrix_return[0][2] = 0.0;
  360.     matrix_return[0][3] = trans_vector->x;
  361.  
  362.     matrix_return[1][0] = 0.0;
  363.     matrix_return[1][1] = 1.0;
  364.     matrix_return[1][2] = 0.0;
  365.     matrix_return[1][3] = trans_vector->y;
  366.  
  367.     matrix_return[2][0] = 0.0;
  368.     matrix_return[2][1] = 0.0;
  369.     matrix_return[2][2] = 1.0;
  370.     matrix_return[2][3] = trans_vector->z;
  371.  
  372.     matrix_return[3][0] = 0.0;
  373.     matrix_return[3][1] = 0.0;
  374.     matrix_return[3][2] = 0.0;
  375.     matrix_return[3][3] = 1.0;
  376. }
  377.  
  378.  
  379. void
  380. PEXTranslate2D (trans_vector, matrix_return)
  381.  
  382. INPUT PEXVector2D    *trans_vector;
  383. OUTPUT PEXMatrix3x3    matrix_return;
  384.  
  385. {
  386.     matrix_return[0][0] = 1.0;
  387.     matrix_return[0][1] = 0.0;
  388.     matrix_return[0][2] = trans_vector->x;
  389.  
  390.     matrix_return[1][0] = 0.0;
  391.     matrix_return[1][1] = 1.0;
  392.     matrix_return[1][2] = trans_vector->y;
  393.  
  394.     matrix_return[2][0] = 0.0;
  395.     matrix_return[2][1] = 0.0;
  396.     matrix_return[2][2] = 1.0;
  397. }
  398.  
  399.  
  400. void
  401. PEXMatrixMult (matrix1, matrix2, matrix_return)
  402.  
  403. INPUT PEXMatrix        matrix1;
  404. INPUT PEXMatrix        matrix2;
  405. OUTPUT PEXMatrix    matrix_return;
  406.  
  407. {
  408.     register float    *r;
  409.     register int    i;
  410.  
  411.     if ((matrix_return != matrix1) && (matrix_return != matrix2))
  412.     {
  413.     for (i = 0; i < 4; i++)
  414.     {
  415.         r = matrix1[i];
  416.         matrix_return[i][0] = r[0] * matrix2[0][0] + r[1] * matrix2[1][0] +
  417.                   r[2] * matrix2[2][0] + r[3] * matrix2[3][0];
  418.         matrix_return[i][1] = r[0] * matrix2[0][1] + r[1] * matrix2[1][1] +
  419.                   r[2] * matrix2[2][1] + r[3] * matrix2[3][1];
  420.         matrix_return[i][2] = r[0] * matrix2[0][2] + r[1] * matrix2[1][2] +
  421.                   r[2] * matrix2[2][2] + r[3] * matrix2[3][2];
  422.         matrix_return[i][3] = r[0] * matrix2[0][3] + r[1] * matrix2[1][3] +
  423.                   r[2] * matrix2[2][3] + r[3] * matrix2[3][3];
  424.     }
  425.     }
  426.     else
  427.     {
  428.     register float    *src, *dst;
  429.     PEXMatrix    temp;
  430.     
  431.     for (i = 0; i < 4; i++)
  432.     {
  433.         r = matrix1[i];
  434.         temp[i][0] = r[0] * matrix2[0][0] + r[1] * matrix2[1][0] +
  435.                    r[2] * matrix2[2][0] + r[3] * matrix2[3][0];
  436.         temp[i][1] = r[0] * matrix2[0][1] + r[1] * matrix2[1][1] +
  437.              r[2] * matrix2[2][1] + r[3] * matrix2[3][1];
  438.         temp[i][2] = r[0] * matrix2[0][2] + r[1] * matrix2[1][2] +
  439.              r[2] * matrix2[2][2] + r[3] * matrix2[3][2];
  440.         temp[i][3] = r[0] * matrix2[0][3] + r[1] * matrix2[1][3] +
  441.              r[2] * matrix2[2][3] + r[3] * matrix2[3][3];
  442.     }
  443.  
  444.     src = (float *) temp;
  445.     dst = (float *) matrix_return;
  446.     for (i = 0; i < 16; i++)
  447.         *dst++ = *src++;
  448.     }
  449. }
  450.  
  451.  
  452. void
  453. PEXMatrixMult2D (matrix1, matrix2, matrix_return)
  454.  
  455. INPUT PEXMatrix3x3    matrix1;
  456. INPUT PEXMatrix3x3    matrix2;
  457. OUTPUT PEXMatrix3x3    matrix_return;
  458.  
  459. {
  460.     register float    *r;
  461.     register int    i;
  462.  
  463.     if ((matrix_return != matrix1) && (matrix_return != matrix2))
  464.     {
  465.     for (i = 0; i < 3; i++)
  466.     {
  467.         r = matrix1[i];
  468.         matrix_return[i][0] = r[0] * matrix2[0][0] + r[1] * matrix2[1][0] +
  469.                   r[2] * matrix2[2][0];
  470.         matrix_return[i][1] = r[0] * matrix2[0][1] + r[1] * matrix2[1][1] +
  471.                   r[2] * matrix2[2][1];
  472.         matrix_return[i][2] = r[0] * matrix2[0][2] + r[1] * matrix2[1][2] +
  473.                   r[2] * matrix2[2][2];
  474.     }
  475.     }
  476.     else
  477.     {
  478.     register float    *src, *dst;
  479.     PEXMatrix3x3     temp;
  480.     
  481.     for (i = 0; i < 3; i++)
  482.     {
  483.         r = matrix1[i];
  484.         temp[i][0] = r[0] * matrix2[0][0] + r[1] * matrix2[1][0] +
  485.                    r[2] * matrix2[2][0];
  486.         temp[i][1] = r[0] * matrix2[0][1] + r[1] * matrix2[1][1] +
  487.              r[2] * matrix2[2][1];
  488.         temp[i][2] = r[0] * matrix2[0][2] + r[1] * matrix2[1][2] +
  489.              r[2] * matrix2[2][2];
  490.     }
  491.  
  492.     src = (float *) temp;
  493.     dst = (float *) matrix_return;
  494.     for (i = 0; i < 9; i++)
  495.         *dst++ = *src++;
  496.     }
  497. }
  498.  
  499.  
  500. void
  501. PEXBuildTransform (fixed_point, trans_vector, angle_x, angle_y, angle_z,
  502.     scale_vector, matrix_return)
  503.  
  504. INPUT PEXCoord        *fixed_point;
  505. INPUT PEXVector        *trans_vector;
  506. INPUT double        angle_x;
  507. INPUT double        angle_y;
  508. INPUT double        angle_z;
  509. INPUT PEXVector        *scale_vector;
  510. OUTPUT PEXMatrix    matrix_return;
  511.  
  512. {
  513.     /*
  514.      * Translate fixed_point to the origin, scale, rotate, translate back
  515.      * to fixed_point, then apply trans_vector:
  516.      *
  517.      *            T * Tf~ * Rz * Ry * Rx * S * Tf.
  518.      *
  519.      *    where:    T is the "trans_vector" transform,
  520.      *            Tf ia the translation of fixed_point to the origin and
  521.      *            Tf~ is it's inverse,
  522.      *            Ri is the rotation transform about the i'th axis,
  523.      *            S is the scaling transform.
  524.      */
  525.  
  526.     register float    cz, sz, cx, sx, cy, sy;
  527.     register float    *r;
  528.  
  529.     cx = cos (angle_x); sx = sin (angle_x);
  530.     cy = cos (angle_y); sy = sin (angle_y);
  531.     cz = cos (angle_z); sz = sin (angle_z);
  532.  
  533.     r = matrix_return[0];
  534.     r[0] = cz * cy * scale_vector->x;
  535.     r[1] = (cz * sx * sy - sz * cx) * scale_vector->y;
  536.     r[2] = (cz * sy * cx + sz * sx) * scale_vector->z;
  537.     r[3] = trans_vector->x + fixed_point->x -
  538.     (r[0] * fixed_point->x + r[1] * fixed_point->y +
  539.         r[2] * fixed_point->z);
  540.  
  541.     r = matrix_return[1];
  542.     r[0] = sz * cy * scale_vector->x;
  543.     r[1] = (sz * sx * sy + cz * cx) * scale_vector->y;
  544.     r[2] = (sz * sy * cx - cz * sx) * scale_vector->z;
  545.     r[3] = trans_vector->y + fixed_point->y -
  546.     (r[0] * fixed_point->x + r[1] * fixed_point->y +
  547.         r[2] * fixed_point->z);
  548.  
  549.     r = matrix_return[2];
  550.     r[0] = -sy * scale_vector->x;
  551.     r[1] = cy * sx * scale_vector->y;
  552.     r[2] = cy * cx * scale_vector->z;
  553.     r[3] = trans_vector->z + fixed_point->z -
  554.     (r[0] * fixed_point->x + r[1] * fixed_point->y +
  555.         r[2] * fixed_point->z);
  556.  
  557.     r = matrix_return[3];
  558.     r[0] = r[1] = r[2] = 0.0;
  559.     r[3] = 1.0;
  560. }
  561.  
  562.  
  563. void
  564. PEXBuildTransform2D (fixed_point, trans_vector, angle_z,
  565.     scale_vector, matrix_return)
  566.  
  567. INPUT PEXCoord2D    *fixed_point;
  568. INPUT PEXVector2D    *trans_vector;
  569. INPUT double        angle_z;
  570. INPUT PEXVector2D    *scale_vector;
  571. OUTPUT PEXMatrix3x3    matrix_return;
  572.  
  573. {
  574.     /*
  575.      * Translate fixed_point to the origin, scale, rotate, translate back
  576.      * to fixed_point, then apply trans_vector:
  577.      *
  578.      *            T * Tf~ * R * S * Tf.
  579.      *
  580.      *    where:    T is the "trans_vector" transform,
  581.      *            Tf ia the translation of fixed_point to the origin and
  582.      *            Tf~ is it's inverse,
  583.      *            R is the rotation transform,
  584.      *            S is the scaling transform.
  585.      */
  586.  
  587.     register float    *r;
  588.     register float    c, s;
  589.  
  590.     c = cos (angle_z);
  591.     s = sin (angle_z);
  592.  
  593.     r = matrix_return[0];
  594.     r[0] = c * scale_vector->x;
  595.     r[1] = -s * scale_vector->y;
  596.     r[2] = trans_vector->x + fixed_point->x -
  597.     c * scale_vector->x * fixed_point->x +
  598.         s * scale_vector->y * fixed_point->y;
  599.  
  600.     r = matrix_return[1];
  601.     r[0] = s * scale_vector->x;
  602.     r[1] = c * scale_vector->y;
  603.     r[2] = trans_vector->y + fixed_point->y -
  604.     (s * scale_vector->x * fixed_point->x +
  605.         c * scale_vector->y * fixed_point->y);
  606.  
  607.     r = matrix_return[2];
  608.     r[0] = r[1] = 0.0;
  609.     r[2] = 1.0;
  610. }
  611.  
  612.  
  613. int
  614. PEXViewOrientationMatrix (vrp, vpn, vup, matrix_return)
  615.  
  616. INPUT PEXCoord          *vrp;
  617. INPUT PEXVector         *vpn;
  618. INPUT PEXVector         *vup;
  619. OUTPUT PEXMatrix        matrix_return;
  620.  
  621. {
  622.     /*
  623.      * Translate to VRP then change the basis.
  624.      * The old basis is: e1 = < 1, 0, 0>,  e2 = < 0, 1, 0>, e3 = < 0, 0, 1>.
  625.      * The new basis is: ("x" means cross product)
  626.      *        e3' = VPN / |VPN|
  627.      *        e1' = VUP x VPN / |VUP x VPN|
  628.      *        e2' = e3' x e1'
  629.      * Therefore the transform from old to new is x' = ATx, where:
  630.      *
  631.      *         | e1' 0 |         | 1 0 0 -vrp.x |
  632.      *   A = |       |,    T = | 0 1 0 -vrp.y |
  633.      *       | e2' 0 |         | 0 0 1 -vrp.z |
  634.      *         |       |         | 0 0 0    1   |
  635.      *         | e3' 0 |
  636.      *         |       |
  637.      *         | -0-  1|
  638.      */
  639.  
  640.     /* These ei's are really ei primes. */
  641.     float    *e1 = matrix_return[0],
  642.                 *e2 = matrix_return[1],
  643.                 *e3 = matrix_return[2];
  644.     double    s, mag_vpn;
  645.  
  646.     if (ZERO_MAG (mag_vpn = MAG_V3 (vpn)))
  647.     {
  648.     return (PEXBadVector);
  649.     }
  650.     else if (ZERO_MAG (MAG_V3 (vup)))
  651.     {
  652.     return (PEXBadVector);
  653.     }
  654.     else
  655.     {
  656.     /*
  657.          * e1' = VUP x VPN / |VUP x VPN|, but do the division later.
  658.      */
  659.  
  660.     e1[0] = vup->y * vpn->z - vup->z * vpn->y;
  661.     e1[1] = vup->z * vpn->x - vup->x * vpn->z;
  662.     e1[2] = vup->x * vpn->y - vup->y * vpn->x;
  663.  
  664.     s = sqrt (e1[0] * e1[0] + e1[1] * e1[1] + e1[2] * e1[2]);
  665.  
  666.  
  667.     /*
  668.      * Check for vup and vpn colinear (zero dot product).
  669.      */
  670.  
  671.     if (ZERO_MAG (s))
  672.         return (PEXBadVectors);
  673.     }
  674.     
  675.  
  676.     /*
  677.      * Normalize e1
  678.      */
  679.  
  680.     s = 1.0 / s;
  681.     e1[0] *= s; e1[1] *= s; e1[2] *= s;
  682.  
  683.  
  684.     /*
  685.      * e3 = VPN / |VPN|
  686.      */
  687.  
  688.     s = 1.0 / mag_vpn;
  689.     e3[0] = s * vpn->x; e3[1] = s * vpn->y; e3[2] = s * vpn->z;
  690.  
  691.  
  692.     /*
  693.      * e2 = e3 x e1
  694.      */
  695.  
  696.     e2[0] = e3[1] * e1[2] - e3[2] * e1[1];
  697.     e2[1] = e3[2] * e1[0] - e3[0] * e1[2];
  698.     e2[2] = e3[0] * e1[1] - e3[1] * e1[0];
  699.  
  700.  
  701.     /*
  702.      * Add the translation
  703.      */
  704.  
  705.     e1[3] = -(e1[0] * vrp->x + e1[1] * vrp->y + e1[2] * vrp->z);
  706.     e2[3] = -(e2[0] * vrp->x + e2[1] * vrp->y + e2[2] * vrp->z);
  707.     e3[3] = -(e3[0] * vrp->x + e3[1] * vrp->y + e3[2] * vrp->z);
  708.  
  709.  
  710.     /*
  711.      * Homogeneous entries
  712.      */
  713.  
  714.     matrix_return[3][0] = matrix_return[3][1] = matrix_return[3][2] = 0.0;
  715.     matrix_return[3][3] = 1.0;
  716.  
  717.     return (0);
  718. }
  719.  
  720.  
  721. int
  722. PEXViewOrientationMatrix2D (vrp, vup, matrix_return)
  723.  
  724. INPUT PEXCoord2D        *vrp;
  725. INPUT PEXVector2D       *vup;
  726. OUTPUT PEXMatrix3x3     matrix_return;
  727.  
  728. {
  729.     /*
  730.      * The old basis is: e1 = < 1, 0>,  e2 = < 0, 1>
  731.      * The new basis is: e1' = < vup.y, -vup.x> / |vup|,  e2' = vup / |vup|.
  732.      * Therefore the transform for old to new is x' = ATx, where:
  733.      *
  734.      *         | e1' 0 |         | 1 0 -vrp.x |
  735.      *     A = |       |,    T = | 0 1 -vrp.y |
  736.      *         | e2' 0 |         | 0 0    1   |
  737.      *         |       |
  738.      *         | -0-  1|
  739.      */
  740.  
  741.     register double    s;
  742.  
  743.     if (ZERO_MAG (s = MAG_V2 (vup)))
  744.     {
  745.     return (PEXBadVector);
  746.     }
  747.     else
  748.     {
  749.     /*
  750.      * Compute the new basis, note that matrix_return[0] is e1'
  751.      * and matrix_return[1] is e2'.
  752.      */
  753.  
  754.     s = 1.0 / s;
  755.     matrix_return[0][0] = s * vup->y;
  756.     matrix_return[0][1] = s * -vup->x;
  757.     matrix_return[1][0] = s * vup->x;
  758.     matrix_return[1][1] = s * vup->y;
  759.  
  760.  
  761.     /*
  762.      * Add the translation
  763.      */
  764.  
  765.     matrix_return[0][2] = -(matrix_return[0][0] * vrp->x +
  766.                 matrix_return[0][1] * vrp->y);
  767.     matrix_return[1][2] = -(matrix_return[1][0] * vrp->x +
  768.                 matrix_return[1][1] * vrp->y);
  769.  
  770.  
  771.     /*
  772.      * Homogeneous entries
  773.      */
  774.  
  775.     matrix_return[2][0] = matrix_return[2][1] = 0.0;
  776.     matrix_return[2][2] = 1.0;
  777.  
  778.     return (0);
  779.     }
  780. }
  781.  
  782.  
  783. int
  784. PEXViewMappingMatrix (frame, viewport, perspective, prp, view_plane,
  785.     back_plane, front_plane, matrix_return)
  786.  
  787. INPUT PEXCoord2D    *frame;
  788. INPUT PEXNPCSubVolume    *viewport;
  789. INPUT int        perspective;
  790. INPUT PEXCoord        *prp;
  791. INPUT double        view_plane;
  792. INPUT double        back_plane;
  793. INPUT double        front_plane;
  794. OUTPUT PEXMatrix    matrix_return;
  795.  
  796. {
  797.     /*
  798.      * Procedure:
  799.      *
  800.      * (Perspective):
  801.      *   - Translate to PRP,            Tc
  802.      *     - Convert to left handed coords,    Tlr
  803.      *     - Shear,                H
  804.      *     - Scale to canonical view volume,    S
  805.      *     - Normalize perspective view volume,    Ntp
  806.      *     - Scale to viewport,            Svp
  807.      *     - Convert to right handed coords,    Tlr
  808.      *     - Translate to viewport,        Tvp
  809.      *
  810.      * (Parallel):
  811.      *     - Translate to view plane,        Tc
  812.      *     - Shear about the view plane,        H
  813.      *     - Translate back,            Tc inverse
  814.      *     - Translate frame to origin,        Tl
  815.      *     - Scale to canonical view volume,    S
  816.      *     - Scale to viewport,            Svp
  817.      *     - Translate to viewport,        Tvp
  818.      */
  819.  
  820.     double    dx = viewport->max.x - viewport->min.x;
  821.     double    dy = viewport->max.y - viewport->min.y;
  822.     double    dz = viewport->max.z - viewport->min.z;
  823.     double    vvz = front_plane - back_plane;
  824.     double    sz, sx, sy;
  825.     double    hx, hy;
  826.     double    d;
  827.     double    zf;
  828.     float    *r;
  829.  
  830.     if (!(frame[0].x < frame[1].x) || !(frame[0].y < frame[1].y))
  831.     {
  832.     return (PEXBadLimits);
  833.     }
  834.     else if (!(viewport->min.x < viewport->max.x) ||
  835.              !(viewport->min.y < viewport->max.y) ||
  836.              !(viewport->min.z <= viewport->max.z))
  837.     {
  838.     return (PEXBadViewport);
  839.     }
  840.     else if (NEAR_ZERO (vvz) && viewport->min.z != viewport->max.z)
  841.     {
  842.     return (PEXBadPlanes);
  843.     }
  844.     else if (perspective && prp->z < front_plane && prp->z > back_plane)
  845.     {
  846.     return (PEXBadPlanes);
  847.     }
  848.     else if (prp->z == view_plane)
  849.     {
  850.     return (PEXBadPRP);
  851.     }
  852.     else if (front_plane < back_plane)
  853.     {
  854.     return (PEXBadPlanes);
  855.     }
  856.     else if (!IN_RANGE (0.0, 1.0, viewport->min.x) ||
  857.          !IN_RANGE (0.0, 1.0, viewport->max.x) ||
  858.          !IN_RANGE (0.0, 1.0, viewport->min.y) ||
  859.          !IN_RANGE (0.0, 1.0, viewport->max.y) ||
  860.          !IN_RANGE (0.0, 1.0, viewport->min.z) ||
  861.          !IN_RANGE (0.0, 1.0, viewport->max.z))
  862.     {
  863.     return (PEXBadViewport);
  864.     }
  865.     
  866.     if (perspective)
  867.     {
  868.     d = prp->z - view_plane;
  869.     sz = 1.0 / (prp->z - back_plane);
  870.     sx = sz * d * 2.0 / (frame[1].x - frame[0].x);
  871.     sy = sz * d * 2.0 / (frame[1].y - frame[0].y);
  872.     hx = (prp->x - 0.5 * (frame[0].x + frame[1].x)) / d;
  873.     hy = (prp->y - 0.5 * (frame[0].y + frame[1].y)) / d;
  874.  
  875.     r = matrix_return[0];
  876.     r[0] = 0.5 * dx * sx;
  877.     r[1] = 0.0;
  878.     r[2] = -(0.5 * dx * (sx * hx + sz) + sz * viewport->min.x);
  879.     r[3] = -(0.5 * dx * sx * (prp->x - hx * prp->z) -
  880.         sz * prp->z * (0.5 * dx + viewport->min.x));
  881.  
  882.     r = matrix_return[1];
  883.     r[0] = 0.0;
  884.     r[1] = 0.5 * dy * sy;
  885.     r[2] = -(0.5 * dy * (sy * hy + sz) + sz * viewport->min.y);
  886.     r[3] = -(0.5 * dy * sy * (prp->y - hy * prp->z) -
  887.         sz * prp->z * (0.5 * dy + viewport->min.y));
  888.  
  889.     r = matrix_return[2];
  890.     r[0] = r[1] = 0.0;
  891.     zf = (prp->z - front_plane) / (prp->z - back_plane);
  892.     if (NEAR_ZERO (1.0 - zf))
  893.     {
  894.         r[2] = 0.0;
  895.         r[3] = sz * prp->z * viewport->max.z;
  896.     }
  897.     else
  898.     {
  899.         r[2] = sz * ((dz / (1.0 - zf)) - viewport->max.z);
  900.         r[3] = sz * prp->z * viewport->max.z -
  901.         (dz / (1.0 - zf)) * (sz * prp->z - zf);
  902.     }
  903.  
  904.     r = matrix_return[3];
  905.     r[0] = r[1] = 0.0;
  906.     r[2] = -sz;
  907.     r[3] = sz * prp->z;
  908.     }
  909.     else
  910.     {    /* parallel */
  911.     sx = dx / (frame[1].x - frame[0].x);
  912.     sy = dy / (frame[1].y - frame[0].y);
  913.     hx = (prp->x - 0.5 * (frame[0].x + frame[1].x)) /
  914.         (view_plane - prp->z);
  915.     hy = (prp->y - 0.5 * (frame[0].y + frame[1].y)) /
  916.         (view_plane - prp->z);
  917.  
  918.     r = matrix_return[0];
  919.     r[0] = sx;
  920.     r[1] = 0.0;
  921.     r[2] = sx * hx;
  922.     r[3] = viewport->min.x - sx * (hx * view_plane + frame[0].x);
  923.  
  924.     r = matrix_return[1];
  925.     r[0] = 0.0;
  926.     r[1] = sy;
  927.     r[2] = sy * hy;
  928.     r[3] = viewport->min.y - sy * (hy * view_plane + frame[0].y);
  929.  
  930.     r  = matrix_return[2];
  931.     r[0] = r[1] = 0.0;
  932.     if (NEAR_ZERO (vvz))
  933.         r[2] = 0.0;
  934.     else
  935.         r[2] = dz / vvz;
  936.     r[3] = viewport->min.z - r[2] * back_plane;
  937.  
  938.     r = matrix_return[3];
  939.     r[0] = r[1] = r[2] = 0.0;
  940.     r[3] = 1.0;
  941.     }
  942.     
  943.     return (0);
  944. }
  945.  
  946.  
  947. int
  948. PEXViewMappingMatrix2D (frame, viewport, matrix_return)
  949.  
  950. INPUT PEXCoord2D    *frame;
  951. INPUT PEXCoord2D    *viewport;
  952. OUTPUT PEXMatrix3x3    matrix_return;
  953.  
  954. {
  955.     /*
  956.      * 1. Translate frame's lower-left-corner to 0,0.
  957.      * 2. Scale size of frame to size of viewport.
  958.      * 3. Translate 0,0 to viewport's lower-left-corner.
  959.      *
  960.      * Matrices are:
  961.      *
  962.      * 1:  1 0 -frame[0].x    2:  scale.x   0    0   3:  1 0  viewport[0].x
  963.      *        0 1 -frame[0].y       0     scale.y 0       0 1  viewport[0].y
  964.      *        0 0   1           0       0     1       0 0   1
  965.      */
  966.  
  967.     /* scale factors: len (viewport) / len (frame) */
  968.     register float    sx, sy;
  969.  
  970.  
  971.     if (!(frame[0].x < frame[1].x) || !(frame[0].y < frame[1].y))
  972.     {
  973.     return (PEXBadLimits);
  974.     }
  975.     else if (!(viewport[0].x < viewport[1].x) ||
  976.          !(viewport[0].y < viewport[1].y))
  977.     {
  978.     return (PEXBadViewport);
  979.     }
  980.     else if (!IN_RANGE (0.0, 1.0, viewport[0].x) ||
  981.          !IN_RANGE (0.0, 1.0, viewport[1].x) ||
  982.          !IN_RANGE (0.0, 1.0, viewport[0].y) ||
  983.          !IN_RANGE (0.0, 1.0, viewport[1].y))
  984.     {
  985.     return (PEXBadViewport);
  986.     }
  987.  
  988.     sx = (viewport[1].x - viewport[0].x) / (frame[1].x - frame[0].x);
  989.     sy = (viewport[1].y - viewport[0].y) / (frame[1].y - frame[0].y);
  990.  
  991.     matrix_return[0][0] = sx;
  992.     matrix_return[0][1] = 0.0;
  993.     matrix_return[0][2] = sx * (-frame[0].x + viewport[0].x);
  994.  
  995.     matrix_return[1][0] = 0.0;
  996.     matrix_return[1][1] = sy;
  997.     matrix_return[1][2] = sy * (-frame[0].y + viewport[0].y);
  998.  
  999.     matrix_return[2][0] = 0.0;
  1000.     matrix_return[2][1] = 0.0;
  1001.     matrix_return[2][2] = 1.0;
  1002.  
  1003.     return (0);
  1004. }
  1005.  
  1006.  
  1007. int
  1008. PEXLookAtViewMatrix (from, to, up, matrix_return)
  1009.  
  1010. INPUT PEXCoord        *from;
  1011. INPUT PEXCoord        *to;
  1012. INPUT PEXVector        *up;
  1013. OUTPUT PEXMatrix    matrix_return;
  1014.  
  1015. {
  1016.     PEXCoord        a, b, c, d, e, f, t;
  1017.     float        magnitude;
  1018.     float        dot_product;
  1019.  
  1020.     /*
  1021.      * This matrix can be thought of as having 2 parts.  The first part (next
  1022.      * to the coordinate point when it is being transformed) moves the to
  1023.      * point to the origin.  The second part performs the rotation of the data.
  1024.      *
  1025.      * The three basis vectors of the rotation are obtained as follows.
  1026.      * The Z basis vector is determined by subtracting from from to and
  1027.      * dividing by its length (b).  The Y basis vector is determined by
  1028.      * calculating the vector perpendicular to b and in the plane defined by
  1029.      * the to and from points and the up vector and then normalizing it (e).
  1030.      * The X basis vector (f) is calculated by e CROSS b.
  1031.      *
  1032.      * The resulting matrix looks like this:
  1033.      *
  1034.      *  | fx fy fz 0 | | 1 0 0 -tox | | fx fy fz tz |
  1035.      *  | ex ey ez 0 |*| 0 1 0 -toy |=| ex ey ez ty |
  1036.      *  | bx by bz 0 | | 0 0 1 -toz | | bx by bz tz |
  1037.      *  |  0  0  0 1 | | 0 0 0   1  | |  0  0  0  1 |
  1038.      *
  1039.      * where tx = -to DOT f, ty = -to DOT e, and tz = -to DOT b.
  1040.      */
  1041.  
  1042.     /*
  1043.      * Calculate the rotations
  1044.      */
  1045.  
  1046.     a.x = from->x - to->x;        /* difference between to and from */
  1047.     a.y = from->y - to->y;
  1048.     a.z = from->z - to->z;
  1049.  
  1050.     magnitude = sqrt (a.x * a.x + a.y * a.y + a.z * a.z);
  1051.  
  1052.     if (ZERO_MAG (magnitude))
  1053.     {
  1054.     return (PEXBadVectors);    /* from and to are the same */
  1055.     }
  1056.  
  1057.  
  1058.     /*
  1059.      * normalize the from-to vector
  1060.      */
  1061.  
  1062.     b.x = a.x / magnitude;
  1063.     b.y = a.y / magnitude;
  1064.     b.z = a.z / magnitude;
  1065.  
  1066.  
  1067.     /*
  1068.      * up is second basis vector
  1069.      */
  1070.  
  1071.     c.x = up->x;
  1072.     c.y = up->y;
  1073.     c.z = up->z;
  1074.  
  1075.  
  1076.     /*
  1077.      * compute the dot product of the previous two vectors
  1078.      */
  1079.  
  1080.     dot_product = (c.x * b.x) + (c.y * b.y) + (c.z * b.z);
  1081.  
  1082.  
  1083.     /*
  1084.      * calculate the vector perpendicular to the up vector and in the
  1085.      * plane defined by the to and from points and the up vector.
  1086.      */
  1087.  
  1088.     d.x = c.x - (dot_product * b.x);
  1089.     d.y = c.y - (dot_product * b.y);
  1090.     d.z = c.z - (dot_product * b.z);
  1091.  
  1092.     magnitude = sqrt (d.x * d.x + d.y * d.y + d.z * d.z);
  1093.  
  1094.     if (ZERO_MAG (magnitude))   /* use the defaults */
  1095.     {
  1096.         c.x = 0.0;
  1097.         c.y = 1.0;
  1098.         c.z = 0.0;
  1099.  
  1100.         dot_product = b.y;
  1101.  
  1102.         d.x = -(dot_product * b.x);
  1103.         d.y = 1.0 - (dot_product * b.y);
  1104.         d.z = -(dot_product * b.z);
  1105.  
  1106.         magnitude = sqrt (d.x * d.x + d.y * d.y + d.z * d.z);
  1107.  
  1108.         if (ZERO_MAG (magnitude))
  1109.         {
  1110.             c.x = 0.0;
  1111.             c.y = 0.0;
  1112.             c.z = 1.0;
  1113.  
  1114.             dot_product = b.z;
  1115.  
  1116.             d.x = -(dot_product * b.x);
  1117.             d.y = -(dot_product * b.y);
  1118.             d.z = 1.0 -(dot_product * b.z);
  1119.  
  1120.             magnitude = sqrt (d.x * d.x + d.y * d.y + d.z * d.z);
  1121.         }
  1122.     }
  1123.  
  1124.     /*
  1125.      * calculate the unit vector in the from, to, and at plane and
  1126.      * perpendicular to the up vector
  1127.      */
  1128.  
  1129.     e.x = d.x / magnitude;
  1130.     e.y = d.y / magnitude;
  1131.     e.z = d.z / magnitude;
  1132.  
  1133.  
  1134.     /*
  1135.      * calculate the unit vector perpendicular to the other two
  1136.      * by crossing them
  1137.      */
  1138.  
  1139.     f.x = (e.y * b.z) - (b.y * e.z);
  1140.     f.y = (e.z * b.x) - (b.z * e.x);
  1141.     f.z = (e.x * b.y) - (b.x * e.y);
  1142.  
  1143.  
  1144.     /*
  1145.      * fill in the rotation values
  1146.      */
  1147.  
  1148.     matrix_return[0][0] = f.x;
  1149.     matrix_return[0][1] = f.y;
  1150.     matrix_return[0][2] = f.z;
  1151.  
  1152.     matrix_return[1][0] = e.x;
  1153.     matrix_return[1][1] = e.y;
  1154.     matrix_return[1][2] = e.z;
  1155.  
  1156.     matrix_return[2][0] = b.x;
  1157.     matrix_return[2][1] = b.y;
  1158.     matrix_return[2][2] = b.z;
  1159.  
  1160.  
  1161.     /*
  1162.      * calculate the translation part of the matrix
  1163.      */
  1164.  
  1165.     t.x = (-to->x * f.x) + (-to->y * f.y) + (-to->z * f.z);
  1166.     t.y = (-to->x * e.x) + (-to->y * e.y) + (-to->z * e.z);
  1167.     t.z = (-to->x * b.x) + (-to->y * b.y) + (-to->z * b.z);
  1168.  
  1169.     matrix_return[0][3] = t.x;
  1170.     matrix_return[1][3] = t.y;
  1171.     matrix_return[2][3] = t.z;
  1172.  
  1173.  
  1174.     /*
  1175.      * and fill in the rest of the matrix
  1176.      */
  1177.  
  1178.     matrix_return[3][0] = 0.0;
  1179.     matrix_return[3][1] = 0.0;
  1180.     matrix_return[3][2] = 0.0;
  1181.     matrix_return[3][3] = 1.0;
  1182.  
  1183.     return (0);
  1184. }
  1185.  
  1186.  
  1187. int
  1188. PEXPolarViewMatrix (from, distance, azimuth, altitude, twist, matrix_return)
  1189.  
  1190. INPUT PEXCoord        *from;
  1191. INPUT double        distance;
  1192. INPUT double        azimuth;
  1193. INPUT double        altitude;
  1194. INPUT double        twist;
  1195. OUTPUT PEXMatrix    matrix_return;
  1196.  
  1197. {
  1198.     PEXCoord    trans;
  1199.     float    cost;
  1200.     float    sint;
  1201.     float    cosaz;
  1202.     float    sinaz;
  1203.     float    cosalt;
  1204.     float    sinalt;
  1205.  
  1206.     if (distance <= ZERO_TOLERANCE)
  1207.     {
  1208.     return (PEXBadDistance);
  1209.     }
  1210.  
  1211.     cost = cos (twist);
  1212.     sint = sin (twist);
  1213.     cosaz = cos (-azimuth);
  1214.     sinaz = sin (-azimuth);
  1215.     cosalt = cos (-altitude);
  1216.     sinalt = sin (-altitude);
  1217.  
  1218.  
  1219.     /*
  1220.      * This matrix can be thought of as having five parts.  The first part
  1221.      * (the part nearest the point to be transformed) translates the from point
  1222.      * to the origin.  The last part translates the rotated data back by
  1223.      * distance so that the to point is at the origin.  (Since the data is
  1224.      * lined up along the Z axis, there are no X and Y parts to this
  1225.      * translation.)
  1226.      *
  1227.      * The three parts in the middle rotate around the Y axis by azimuth,
  1228.      * rotate around the X axis by altitude, and rotate around the Z axis by
  1229.      * twist.
  1230.      *
  1231.      * The matrix calculated in this routine is the result of:
  1232.      *
  1233.      * (trans, -distance)*(twist, Z)*(altitude, X)*(azimuth, Y)*(trans, -from)
  1234.      *
  1235.      *     | cost -sint 0 0 | | 1    0       0   0 | | cosaz 0 sinaz 0 |
  1236.      *    Td*| sint  cost 0 0 |*| 0 cosalt -sinalt 0 |*|   0   1   0   0 |*Tfrom
  1237.      *       |  0     0   1 0 | | 0 sinalt  cosalt 0 | |-sinaz 0 cosaz 0 |
  1238.      *       |  0     0   0 1 | | 0    0       0   1 | |   0   0   0   1 |
  1239.      */
  1240.  
  1241.     matrix_return[0][0] = cost * cosaz + (-sint) * (-sinalt) * (-sinaz);
  1242.     matrix_return[0][1] = (-sint) * cosalt;
  1243.     matrix_return[0][2] = cost * sinaz + (-sint) * (-sinalt) * cosaz;
  1244.  
  1245.     matrix_return[1][0] = sint * cosaz + cost * (-sinalt) * (-sinaz);
  1246.     matrix_return[1][1] = cost * cosalt;
  1247.     matrix_return[1][2] = sint * sinaz + cost * (-sinalt) * cosaz;
  1248.  
  1249.     matrix_return[2][0] = cosalt * (-sinaz);
  1250.     matrix_return[2][1] = sinalt;
  1251.     matrix_return[2][2] = cosalt * cosaz;
  1252.  
  1253.  
  1254.     /*
  1255.      * calculate the translation part of the matrix
  1256.      */
  1257.  
  1258.     trans.x = -from->x * matrix_return[0][0] + -from->y * matrix_return[0][1] +
  1259.           -from->z * matrix_return[0][2];
  1260.     trans.y = -from->x * matrix_return[1][0] + -from->y * matrix_return[1][1] +
  1261.           -from->z * matrix_return[1][2];
  1262.     trans.z = -from->x * matrix_return[2][0] + -from->y * matrix_return[2][1] +
  1263.           -from->z * matrix_return[2][2];
  1264.  
  1265.     matrix_return[0][3] = trans.x;
  1266.     matrix_return[1][3] = trans.y;
  1267.     matrix_return[2][3] = trans.z + distance;
  1268.  
  1269.  
  1270.     /*
  1271.      * finish filling in the matrix
  1272.      */
  1273.  
  1274.     matrix_return[3][0] = 0.0;
  1275.     matrix_return[3][1] = 0.0;
  1276.     matrix_return[3][2] = 0.0;
  1277.     matrix_return[3][3] = 1.0;
  1278.  
  1279.     return (0);
  1280. }
  1281.  
  1282.  
  1283. int
  1284. PEXOrthoProjMatrix (height, aspect, near, far, matrix_return)
  1285.  
  1286. INPUT double        height;
  1287. INPUT double        aspect;
  1288. INPUT double        near;
  1289. INPUT double        far;
  1290. OUTPUT PEXMatrix    matrix_return;
  1291.  
  1292. {
  1293.     float     width;
  1294.     float    depth;
  1295.  
  1296.     width = height * aspect;
  1297.     depth = near - far;
  1298.  
  1299.     if (NEAR_ZERO (depth) || NEAR_ZERO (width) || NEAR_ZERO (height))
  1300.     {
  1301.     return (PEXBadLimits);
  1302.     }
  1303.  
  1304.  
  1305.     /*
  1306.      * This matrix maps the width, height, and depth to the range of zero to
  1307.      * one in all three directions.  It also maps the z values to be
  1308.      * in front of the origin.  The near plane is mapped to z = 1 and the
  1309.      * far plane is mapped to z = 0.  It also translates the x, y coordinates
  1310.      * over by .5 so that x=0 and y=0 is in the middle of the NPC space.
  1311.      */
  1312.  
  1313.     matrix_return[0][0] = 1.0 / width;
  1314.     matrix_return[0][1] = 0.0;
  1315.     matrix_return[0][2] = 0.0;
  1316.     matrix_return[0][3] = 0.5;
  1317.  
  1318.     matrix_return[1][0] = 0.0;
  1319.     matrix_return[1][1] = 1.0 / height;
  1320.     matrix_return[1][2] = 0.0;
  1321.     matrix_return[1][3] = 0.5;
  1322.  
  1323.     matrix_return[2][0] = 0.0;
  1324.     matrix_return[2][1] = 0.0;
  1325.     matrix_return[2][2] = 1.0 / depth;
  1326.     matrix_return[2][3] = 1.0  - (near / depth);
  1327.  
  1328.     matrix_return[3][0] = 0.0;
  1329.     matrix_return[3][1] = 0.0;
  1330.     matrix_return[3][2] = 0.0;
  1331.     matrix_return[3][3] = 1.0;
  1332.  
  1333.     return (0);
  1334. }
  1335.  
  1336.  
  1337. int
  1338. PEXPerspProjMatrix (fovy, distance, aspect, near, far, matrix_return)
  1339.  
  1340. INPUT double        fovy;
  1341. INPUT double        distance;
  1342. INPUT double        aspect;
  1343. INPUT double        near;
  1344. INPUT double        far;
  1345. OUTPUT PEXMatrix    matrix_return;
  1346.  
  1347. {
  1348.     double    fovy2;
  1349.     double    c_hy;
  1350.     double    s_hy;
  1351.     float    height;
  1352.     float    depth;
  1353.     float    width;
  1354.     float    eye_distance;
  1355.  
  1356.     if (near <= far || NEAR_ZERO (fovy) ||
  1357.         NEAR_ZERO (aspect) || distance <= near)
  1358.     {
  1359.     return (PEXBadLimits);
  1360.     }
  1361.  
  1362.  
  1363.     /*
  1364.      * limit the field of view to be less than pi (minus a little) and ensure
  1365.      * that it's positive and then halve it
  1366.      */
  1367.  
  1368.     if ((fovy > 3.140) || (fovy < -3.140))
  1369.     {
  1370.     fovy2 = 3.140 / 2.0;
  1371.     }
  1372.     else if (fovy < 0.0)
  1373.     {
  1374.     fovy2 = -fovy / 2.0;
  1375.     }
  1376.     else
  1377.     {
  1378.     fovy2 = fovy / 2.0;
  1379.     }
  1380.  
  1381.  
  1382.     /*
  1383.      * calculate some dimensions we need
  1384.      */
  1385.  
  1386.     c_hy = cos (fovy2);
  1387.     s_hy = sin (fovy2);
  1388.  
  1389.     eye_distance = distance - near;
  1390.     height = 2.0 * eye_distance * (s_hy / c_hy);
  1391.     depth = near - far;
  1392.     width = height * aspect;
  1393.  
  1394.     /*
  1395.        This matrix is made up of three parts.  The first part is a perspective
  1396.        transformation matrix.  The second part is a matrix to scale and
  1397.        translate the coordinates so that z is between 0 and 1, x is
  1398.        between height/2 and -height/2 and y is between width/2 and
  1399.        -width/2.  The third part is a matrix to translate the eyepoint to
  1400.        .5 in x and y.
  1401.      
  1402.        The viewing frustum looks like this.  We want to project the point
  1403.        (x, y, z) onto the near plane to get (x', y', z').
  1404.  
  1405.   +Z             |      o (x, y, z)
  1406.  <==             |    / :
  1407.                  |  /   :
  1408.       (x',y',z') |/     :
  1409.                 /|      :
  1410.               /  |      :
  1411.             <----|----------------
  1412.                  |      z
  1413.                  |
  1414.            eye  near
  1415.  
  1416.        By similar triangles, x'/eye_dist = x/(eye_dist+near-z)
  1417.                              y'/eye_dist = y/(eye_dist+near-z)
  1418.                              z' = near
  1419.  
  1420.        So the projection matrix, Mproj =
  1421.  
  1422.              | 1   0      0        0                |
  1423.              | 0   1      0        0                |
  1424.              | 0   0      0       near              |
  1425.              | 0   0 -1/eye_dist  1+(near/eye_dist) |
  1426.  
  1427.        (Row vectors are shown below for simplicity.  They're really column
  1428.        vectors.)
  1429.  
  1430.        It can be shown that:
  1431.     Mproj * (0, 0, near, 1) = (0, 0, near, 1)
  1432.     Mproj * (0, 0, far, 1)  = (0, 0, near, 1+near/eye_dist-far/eye_dist)
  1433.  
  1434.        Next, we want to find a matrix, Mst, such that the near plane is
  1435.        transformed to z=1 and the far plane is transformed to z=0.
  1436.     Mst * Mproj * (0, 0, near, 1) = (0, 0, 1, 1)
  1437.     Mst * Mproj * (0, 0, far, 1)  = (0, 0, 0, t)
  1438.                                           where t = (eye_dist-far+near)/eye_dist
  1439.  
  1440.        Using the equations just above, this means that
  1441.     Mst * (0, 0, near, 1) = (0, 0, 1, 1)
  1442.     Mst * (0, 0, near, t) = (0, 0, 0, t)
  1443.  
  1444.        Concentrating on the lower right-hand corner of Mst, this means
  1445.     Mst * | near near | = | 1 0 |
  1446.               |  1    t   |   | 1 t |
  1447.  
  1448.        Solving for Mst, we get
  1449.     Mst = | t/(far(t-1))  -1/(t-1) |
  1450.               |     0            1     |
  1451.  
  1452.        Multiplying and simplifying, we get
  1453.     Mst * Mproj = | 1   0       0               0         |
  1454.                       | 0   1       0               0         |
  1455.                       | 0   0    1/depth       -far/depth     |
  1456.                       | 0   0  -1/eye_dist  1 + near/eye_dist |
  1457.                                                             where depth=near-far
  1458.  
  1459.        Now scale X and Y so that they have a range of "width"
  1460.        in X and "height" in Y.   The resulting matrix is
  1461.     M2 = | 1/width      0        0              0         |
  1462.              |    0     1/height     0              0         |
  1463.              |    0         0    1/depth       -far/depth     |
  1464.              |    0         0  -1/eye_dist  1 + near/eye_dist |
  1465.  
  1466.        Last, we need to translate the results by .5 in X and Y so that the eye
  1467.        point is in the middle of NPC space.
  1468.     matrix_return = | 1 0 0 .5 | * M2
  1469.                     | 0 1 0 .5 |
  1470.                     | 0 0 1  0 |
  1471.                     | 0 0 0  1 |
  1472.  
  1473.     = | 1/width      0    -1/(2*eye_dist) (1+near/eye_dist)/2 |
  1474.           |    0     1/height -1/(2*eye_dist) (1+near/eye_dist)/2 |
  1475.           |    0         0        1/depth          -far/depth     |
  1476.           |    0         0      -1/eye_dist     1+near/eye_dist   |
  1477.     */      
  1478.  
  1479.     matrix_return[0][0] = 1.0 / width;
  1480.     matrix_return[0][1] = 0.0;
  1481.     matrix_return[0][2] = -1.0 / (2.0 * eye_distance);
  1482.     matrix_return[0][3] = (1.0 + (near / eye_distance)) / 2.0;
  1483.  
  1484.     matrix_return[1][0] = 0.0;
  1485.     matrix_return[1][1] = 1.0 / height;
  1486.     matrix_return[1][2] = -1.0 / (2.0 * eye_distance);
  1487.     matrix_return[1][3] = (1.0 + (near / eye_distance)) / 2.0;
  1488.  
  1489.     matrix_return[2][0] = 0.0;
  1490.     matrix_return[2][1] = 0.0;
  1491.     matrix_return[2][2] = 1.0 / depth;
  1492.     matrix_return[2][3] = -far / depth;
  1493.  
  1494.     matrix_return[3][0] = 0.0;
  1495.     matrix_return[3][1] = 0.0;
  1496.     matrix_return[3][2] = -1.0 / eye_distance;
  1497.     matrix_return[3][3] = 1.0 + (near / eye_distance);
  1498.  
  1499.     return (0);
  1500. }
  1501.  
  1502.  
  1503. int
  1504. PEXTransformPoints (mat, count, points, points_return)
  1505.  
  1506. INPUT PEXMatrix        mat;
  1507. INPUT int        count;
  1508. INPUT PEXCoord        *points;
  1509. OUTPUT PEXCoord        *points_return;
  1510.  
  1511. {
  1512.     register PEXCoord    *point_in = points;
  1513.     register PEXCoord    *point_out = points_return;
  1514.     register int    i;
  1515.     PEXCoord        temp;
  1516.     int            status = 0;
  1517.  
  1518.  
  1519.     if (NEAR_ZERO (mat[3][0]) && NEAR_ZERO (mat[3][1]) &&
  1520.     NEAR_ZERO (mat[3][2]) && NEAR_ZERO (mat[3][3] - 1.0))
  1521.     {
  1522.     for (i = 0; i < count; i++, point_in++, point_out++)
  1523.     {
  1524.         temp.x = mat[0][0] * point_in->x +
  1525.              mat[0][1] * point_in->y +
  1526.              mat[0][2] * point_in->z + mat[0][3];
  1527.  
  1528.         temp.y = mat[1][0] * point_in->x +
  1529.              mat[1][1] * point_in->y +
  1530.              mat[1][2] * point_in->z + mat[1][3];
  1531.  
  1532.         temp.z = mat[2][0] * point_in->x +
  1533.              mat[2][1] * point_in->y +
  1534.              mat[2][2] * point_in->z + mat[2][3];
  1535.  
  1536.         point_out->x = temp.x;
  1537.         point_out->y = temp.y;
  1538.         point_out->z = temp.z;
  1539.     }
  1540.     }
  1541.     else
  1542.     {
  1543.     register float    w;
  1544.  
  1545.     for (i = 0; i < count; i++, point_in++, point_out++)
  1546.     {
  1547.         w = mat[3][0] * point_in->x + mat[3][1] * point_in->y +
  1548.             mat[3][2] * point_in->z + mat[3][3];
  1549.  
  1550.         if (NEAR_ZERO (w))
  1551.         {
  1552.         point_out->x = 0.0;
  1553.         point_out->y = 0.0;
  1554.         point_out->z = 0.0;
  1555.  
  1556.         status = PEXBadHomoCoord;   /* return an error */
  1557.         }
  1558.         else
  1559.         {
  1560.         temp.x = (mat[0][0] * point_in->x +
  1561.               mat[0][1] * point_in->y +
  1562.                           mat[0][2] * point_in->z + mat[0][3]) / w;
  1563.  
  1564.         temp.y = (mat[1][0] * point_in->x +
  1565.               mat[1][1] * point_in->y +
  1566.               mat[1][2] * point_in->z + mat[1][3]) / w;
  1567.  
  1568.         temp.z = (mat[2][0] * point_in->x +
  1569.               mat[2][1] * point_in->y +
  1570.               mat[2][2] * point_in->z + mat[2][3]) / w;
  1571.  
  1572.         point_out->x = temp.x;
  1573.         point_out->y = temp.y;
  1574.         point_out->z = temp.z;
  1575.         }
  1576.     }
  1577.     }
  1578.  
  1579.     return (status);
  1580. }
  1581.  
  1582.  
  1583. int
  1584. PEXTransformPoints2D (mat, count, points, points_return)
  1585.  
  1586. INPUT PEXMatrix3x3    mat;
  1587. INPUT int        count;
  1588. INPUT PEXCoord2D    *points;
  1589. OUTPUT PEXCoord2D    *points_return;
  1590.  
  1591. {
  1592.     register PEXCoord2D *point_in = points;
  1593.     register PEXCoord2D    *point_out = points_return;
  1594.     register int    i;
  1595.     PEXCoord2D        temp;
  1596.     int            status = 0;
  1597.  
  1598.  
  1599.     if (NEAR_ZERO (mat[2][0]) && NEAR_ZERO (mat[2][1]) &&
  1600.     NEAR_ZERO (mat[2][2] - 1.0))
  1601.     {
  1602.     for (i = 0; i < count; i++, point_in++, point_out++)
  1603.     {
  1604.         temp.x = mat[0][0] * point_in->x +
  1605.              mat[0][1] * point_in->y + mat[0][2];
  1606.  
  1607.         temp.y = mat[1][0] * point_in->x +
  1608.              mat[1][1] * point_in->y + mat[1][2];
  1609.  
  1610.         point_out->x = temp.x;
  1611.         point_out->y = temp.y;
  1612.     }
  1613.     }
  1614.     else
  1615.     {
  1616.     register float    w;
  1617.  
  1618.     for (i = 0; i < count; i++, point_in++, point_out++)
  1619.     {
  1620.         w = mat[2][0] * point_in->x + mat[2][1] * point_in->y + mat[2][2];
  1621.  
  1622.         if (NEAR_ZERO (w))
  1623.         {
  1624.         point_out->x = 0.0;
  1625.         point_out->y = 0.0;
  1626.  
  1627.         status = PEXBadHomoCoord;   /* return an error */
  1628.         }
  1629.         else
  1630.         {
  1631.         temp.x = (mat[0][0] * point_in->x +
  1632.               mat[0][1] * point_in->y + mat[0][2]) / w;
  1633.  
  1634.         temp.y = (mat[1][0] * point_in->x +
  1635.               mat[1][1] * point_in->y + mat[1][2]) / w;
  1636.  
  1637.         point_out->x = temp.x;
  1638.         point_out->y = temp.y;
  1639.         }
  1640.     }
  1641.     }
  1642.  
  1643.     return (status);
  1644. }
  1645.  
  1646.  
  1647. void
  1648. PEXTransformPoints4D (mat, count, points, points_return)
  1649.  
  1650. INPUT PEXMatrix        mat;
  1651. INPUT int        count;
  1652. INPUT PEXCoord4D    *points;
  1653. OUTPUT PEXCoord4D    *points_return;
  1654.  
  1655. {
  1656.     register PEXCoord4D    *point_in = points;
  1657.     register PEXCoord4D    *point_out = points_return;
  1658.     register int    i;
  1659.     PEXCoord4D        temp;
  1660.  
  1661.  
  1662.     for (i = 0; i < count; i++, point_in++, point_out++)
  1663.     {
  1664.         temp.x = mat[0][0] * point_in->x + mat[0][1] * point_in->y +
  1665.                  mat[0][2] * point_in->z + mat[0][3] * point_in->w;
  1666.  
  1667.         temp.y = mat[1][0] * point_in->x + mat[1][1] * point_in->y +
  1668.                  mat[1][2] * point_in->z + mat[1][3] * point_in->w;
  1669.  
  1670.         temp.z = mat[2][0] * point_in->x + mat[2][1] * point_in->y +
  1671.                  mat[2][2] * point_in->z + mat[2][3] * point_in->w;
  1672.  
  1673.         temp.w = mat[3][0] * point_in->x + mat[3][1] * point_in->y +
  1674.                  mat[3][2] * point_in->z + mat[3][3] * point_in->w;
  1675.  
  1676.     point_out->x = temp.x;
  1677.     point_out->y = temp.y;
  1678.     point_out->z = temp.z;
  1679.     point_out->w = temp.w;
  1680.     }
  1681. }
  1682.  
  1683.  
  1684. void
  1685. PEXTransformPoints2DH (mat, count, points, points_return)
  1686.  
  1687. INPUT PEXMatrix3x3    mat;
  1688. INPUT int        count;
  1689. INPUT PEXCoord        *points;
  1690. OUTPUT PEXCoord        *points_return;
  1691.  
  1692. {
  1693.     register PEXCoord    *point_in = points;
  1694.     register PEXCoord    *point_out = points_return;
  1695.     register int    i;
  1696.     PEXCoord        temp;
  1697.  
  1698.  
  1699.     for (i = 0; i < count; i++, point_in++, point_out++)
  1700.     {
  1701.         temp.x = mat[0][0] * point_in->x + mat[0][1] * point_in->y +
  1702.                  mat[0][2] * point_in->z;
  1703.  
  1704.         temp.y = mat[1][0] * point_in->x + mat[1][1] * point_in->y +
  1705.                  mat[1][2] * point_in->z;
  1706.  
  1707.         temp.z = mat[2][0] * point_in->x + mat[2][1] * point_in->y +
  1708.                  mat[2][2] * point_in->z;
  1709.  
  1710.     point_out->x = temp.x;
  1711.     point_out->y = temp.y;
  1712.     point_out->z = temp.z;
  1713.     }
  1714. }
  1715.  
  1716.  
  1717. void
  1718. PEXTransformVectors (mat, count, vectors, vectors_return)
  1719.  
  1720. INPUT PEXMatrix        mat;
  1721. INPUT int        count;
  1722. INPUT PEXVector        *vectors;
  1723. OUTPUT PEXVector    *vectors_return;
  1724.  
  1725. {
  1726.     register PEXVector    *vec_in = vectors;
  1727.     register PEXVector    *vec_out = vectors_return;
  1728.     register int    i;
  1729.     PEXVector        temp;
  1730.  
  1731.  
  1732.     for (i = 0; i < count; i++, vec_in++, vec_out++)
  1733.     {
  1734.         temp.x = mat[0][0] * vec_in->x + mat[0][1] * vec_in->y +
  1735.                  mat[0][2] * vec_in->z;
  1736.  
  1737.         temp.y = mat[1][0] * vec_in->x + mat[1][1] * vec_in->y +
  1738.                  mat[1][2] * vec_in->z;
  1739.  
  1740.         temp.z = mat[2][0] * vec_in->x + mat[2][1] * vec_in->y +
  1741.                  mat[2][2] * vec_in->z;
  1742.  
  1743.         vec_out->x = temp.x;
  1744.         vec_out->y = temp.y;
  1745.         vec_out->z = temp.z;
  1746.     }
  1747. }
  1748.  
  1749.  
  1750. void
  1751. PEXTransformVectors2D (mat, count, vectors, vectors_return)
  1752.  
  1753. INPUT PEXMatrix3x3    mat;
  1754. INPUT int        count;
  1755. INPUT PEXVector2D    *vectors;
  1756. OUTPUT PEXVector2D    *vectors_return;
  1757.  
  1758. {
  1759.     register PEXVector2D    *vec_in = vectors;
  1760.     register PEXVector2D    *vec_out = vectors_return;
  1761.     register int        i;
  1762.     PEXVector2D            temp;
  1763.  
  1764.  
  1765.     for (i = 0; i < count; i++, vec_in++, vec_out++)
  1766.     {
  1767.         temp.x = mat[0][0] * vec_in->x + mat[0][1] * vec_in->y;
  1768.         temp.y = mat[1][0] * vec_in->x + mat[1][1] * vec_in->y;
  1769.  
  1770.         vec_out->x = temp.x;
  1771.         vec_out->y = temp.y;
  1772.  
  1773.     }
  1774. }
  1775.  
  1776.  
  1777. int
  1778. PEXNormalizeVectors (count, vectors, vectors_return)
  1779.  
  1780. INPUT int         count;
  1781. INPUT PEXVector        *vectors;
  1782. OUTPUT PEXVector    *vectors_return;
  1783.  
  1784. {
  1785.     register int     i;
  1786.     register PEXVector    *vec_in = vectors;
  1787.     register PEXVector    *vec_out = vectors_return;
  1788.     float        sum, length;
  1789.     int         status = 0;
  1790.  
  1791.  
  1792.     for (i = 0; i < count; i++, vec_in++, vec_out++)
  1793.     {
  1794.     sum = vec_in->x * vec_in->x +
  1795.           vec_in->y * vec_in->y +
  1796.               vec_in->z * vec_in->z;
  1797.  
  1798.     if (NEAR_ZERO (sum))
  1799.     {
  1800.         vec_out->x = 0.0;
  1801.         vec_out->y = 0.0;
  1802.         vec_out->z = 0.0;
  1803.         status = PEXBadVector;
  1804.     }
  1805.     else
  1806.     {
  1807.         length = sqrt (sum);
  1808.  
  1809.         vec_out->x = vec_in->x / length;
  1810.         vec_out->y = vec_in->y / length;
  1811.         vec_out->z = vec_in->z / length;
  1812.     }   
  1813.     }
  1814.  
  1815.     return (status);
  1816. }
  1817.  
  1818.  
  1819. int
  1820. PEXNormalizeVectors2D (count, vectors, vectors_return)
  1821.  
  1822. INPUT int         count;
  1823. INPUT PEXVector2D    *vectors;
  1824. OUTPUT PEXVector2D    *vectors_return;
  1825.  
  1826. {
  1827.     register int         i;
  1828.     register PEXVector2D    *vec_in = vectors;
  1829.     register PEXVector2D    *vec_out = vectors_return;
  1830.     float            sum, length;
  1831.     int             status = 0;
  1832.  
  1833.  
  1834.     for (i = 0; i < count; i++, vec_in++, vec_out++)
  1835.     {
  1836.     sum = vec_in->x * vec_in->x +
  1837.           vec_in->y * vec_in->y;
  1838.  
  1839.     if (NEAR_ZERO (sum))
  1840.     {
  1841.         vec_out->x = 0.0;
  1842.         vec_out->y = 0.0;
  1843.         status = PEXBadVector;
  1844.     }
  1845.     else
  1846.     {
  1847.         length = sqrt (sum);
  1848.  
  1849.         vec_out->x = vec_in->x / length;
  1850.         vec_out->y = vec_in->y / length;
  1851.     }   
  1852.     }
  1853.  
  1854.     return (status);
  1855. }
  1856.  
  1857.  
  1858. int
  1859. PEXNPCToXCTransform (npc_sub_volume, viewport,
  1860.     window_height, transform_return)
  1861.  
  1862. INPUT PEXNPCSubVolume    *npc_sub_volume;
  1863. INPUT PEXDeviceCoord    *viewport;
  1864. INPUT unsigned int    window_height;
  1865. OUTPUT PEXMatrix    transform_return;
  1866.  
  1867. {
  1868.     /*
  1869.      *       M4          M3            M2            M1
  1870.      *
  1871.      *    1  0 0 0     1 0 0 Vx     Sx 0  0  0     1 0 0 -Nx
  1872.      *    0 -1 0 H     0 1 0 Vy     0  Sy 0  0     0 1 0 -Ny
  1873.      *    0  0 1 0     0 0 1 Vz     0  0  Sz 0     0 0 1 -Nz
  1874.      *    0  0 0 1     0 0 0  1     0  0  0  1     0 0 0  1
  1875.      *
  1876.      *    M1 : translates NPC subvolume to origin
  1877.      *         (Nx, Ny, Nz) is the lower left corner of the NPC volume.
  1878.      *
  1879.      *    M2 : scales NPC subvolme at origin to DC viewport at origin.
  1880.      *         Sx, Sy, Sz are the scale factors that maintain the aspect ratio.
  1881.      *
  1882.      *    M3 : translates DC viewport at origin to the correct position.
  1883.      *         (Vx, Vy, Vz) is the lower left corner of the DC viewport.
  1884.      *
  1885.      *    M4 : maps DC to X drawable coordinates (flips Y).
  1886.      *         H is the window height.
  1887.      */
  1888.  
  1889.     float         scale_x, scale_y, scale_z;
  1890.     int         dvx, dvy;
  1891.     float        dnx, dny;
  1892.     float        dvz, dnz;
  1893.     PEXDeviceCoord    new_viewport[2];
  1894.  
  1895.  
  1896.     dvx = viewport[1].x - viewport[0].x;
  1897.     dvy = viewport[1].y - viewport[0].y;
  1898.     dvz = viewport[1].z - viewport[0].z;
  1899.  
  1900.     if (dvx <= 0 || dvy <= 0 || !(viewport[0].z <= viewport[1].z))
  1901.     return (PEXBadViewport);
  1902.  
  1903.     if (BAD_SUBVOLUME (npc_sub_volume))
  1904.     return (PEXBadSubVolume);
  1905.  
  1906.     dnx = npc_sub_volume->max.x - npc_sub_volume->min.x;
  1907.     dny = npc_sub_volume->max.y - npc_sub_volume->min.y;
  1908.     dnz = npc_sub_volume->max.z - npc_sub_volume->min.z;
  1909.  
  1910.     scale_x = (float) dvx / dnx;
  1911.     scale_y = (float) dvy / dny;
  1912.     scale_z = NEAR_ZERO (dnz) ? 1.0 : (dvz / dnz);
  1913.  
  1914.     if (!NEAR_ZERO (scale_x - scale_y))
  1915.     {
  1916.     new_viewport[0].x = viewport[0].x;
  1917.     new_viewport[0].y = viewport[0].y;
  1918.     new_viewport[0].z = viewport[0].z;
  1919.  
  1920.     if (scale_y < scale_x)
  1921.     {
  1922.         new_viewport[1].x = viewport[0].x + (float) dvy * dnx / dny;
  1923.         new_viewport[1].y = viewport[1].y;
  1924.         new_viewport[1].z = viewport[1].z;
  1925.     }
  1926.     else
  1927.     {
  1928.         new_viewport[1].x = viewport[1].x;
  1929.         new_viewport[1].y = viewport[0].y + (float) dvx * dny / dnx;
  1930.         new_viewport[1].z = viewport[1].z;
  1931.     }
  1932.  
  1933.     viewport = new_viewport;
  1934.     }
  1935.  
  1936.     transform_return[0][0] = scale_x;
  1937.     transform_return[0][1] = 0.0;
  1938.     transform_return[0][2] = 0.0;
  1939.     transform_return[0][3] =
  1940.     viewport[0].x - (scale_x * npc_sub_volume->min.x);
  1941.  
  1942.     transform_return[1][0] = 0.0;
  1943.     transform_return[1][1] = -scale_y;
  1944.     transform_return[1][2] = 0.0;
  1945.     transform_return[1][3] =
  1946.     window_height - viewport[0].y + (scale_y * npc_sub_volume->min.y);
  1947.  
  1948.     transform_return[2][0] = 0.0;
  1949.     transform_return[2][1] = 0.0;
  1950.     transform_return[2][2] = scale_z;
  1951.     transform_return[2][3] =
  1952.     viewport[0].z - (scale_z * npc_sub_volume->min.z);
  1953.  
  1954.     transform_return[3][0] = 0.0;
  1955.     transform_return[3][1] = 0.0;
  1956.     transform_return[3][2] = 0.0;
  1957.     transform_return[3][3] = 1.0;
  1958.  
  1959.     return (0);
  1960. }
  1961.  
  1962.  
  1963. int
  1964. PEXNPCToXCTransform2D (npc_sub_volume, viewport,
  1965.     window_height, transform_return)
  1966.  
  1967. INPUT PEXNPCSubVolume    *npc_sub_volume;
  1968. INPUT PEXDeviceCoord2D    *viewport;
  1969. INPUT unsigned int    window_height;
  1970. OUTPUT PEXMatrix3x3    transform_return;
  1971.  
  1972. {
  1973.     /*
  1974.      *      M4         M3         M2          M1
  1975.      *
  1976.      *    1  0 0     1 0 Vx     Sx 0  0     1 0 -Nx
  1977.      *    0 -1 H     0 1 Vy     0  Sy 0     0 1 -Ny
  1978.      *    0  0 1     0 0  1     0  0  1     0 0   1 
  1979.      *
  1980.      *    M1 : translates NPC subvolume to origin
  1981.      *         (Nx, Ny) is the lower left corner of the NPC volume.
  1982.      *
  1983.      *    M2 : scales NPC subvolme at origin to DC viewport at origin.
  1984.      *         Sx, Sy are the scale factors that maintain the aspect ratio.
  1985.      *
  1986.      *    M3 : translates DC viewport at origin to the correct position.
  1987.      *         (Vx, Vy) is the lower left corner of the DC viewport.
  1988.      *
  1989.      *    M4 : maps DC to X drawable coordinates (flips Y).
  1990.      *         H is the window height.
  1991.      */
  1992.  
  1993.     float         scale_x, scale_y;
  1994.     int         dvx, dvy;
  1995.     float        dnx, dny;
  1996.     PEXDeviceCoord2D    new_viewport[2];
  1997.  
  1998.  
  1999.     dvx = viewport[1].x - viewport[0].x;
  2000.     dvy = viewport[1].y - viewport[0].y;
  2001.  
  2002.     if (dvx <= 0 || dvy <= 0)
  2003.     return (PEXBadViewport);
  2004.  
  2005.     if (BAD_SUBVOLUME (npc_sub_volume))
  2006.     return (PEXBadSubVolume);
  2007.  
  2008.     dnx = npc_sub_volume->max.x - npc_sub_volume->min.x;
  2009.     dny = npc_sub_volume->max.y - npc_sub_volume->min.y;
  2010.  
  2011.     scale_x = (float) dvx / dnx;
  2012.     scale_y = (float) dvy / dny;
  2013.  
  2014.     if (!NEAR_ZERO (scale_x - scale_y))
  2015.     {
  2016.     new_viewport[0].x = viewport[0].x;
  2017.     new_viewport[0].y = viewport[0].y;
  2018.  
  2019.     if (scale_y < scale_x)
  2020.     {
  2021.         new_viewport[1].x = viewport[0].x + (float) dvy * dnx / dny;
  2022.         new_viewport[1].y = viewport[1].y;
  2023.     }
  2024.     else
  2025.     {
  2026.         new_viewport[1].x = viewport[1].x;
  2027.         new_viewport[1].y = viewport[0].y + (float) dvx * dny / dnx;
  2028.     }
  2029.  
  2030.     viewport = new_viewport;
  2031.     }
  2032.  
  2033.     transform_return[0][0] = scale_x;
  2034.     transform_return[0][1] = 0.0;
  2035.     transform_return[0][2] =
  2036.     viewport[0].x - (scale_x * npc_sub_volume->min.x);
  2037.  
  2038.     transform_return[1][0] = 0.0;
  2039.     transform_return[1][1] = -scale_y;
  2040.     transform_return[1][2] =
  2041.     window_height - viewport[0].y + (scale_y * npc_sub_volume->min.y);
  2042.  
  2043.     transform_return[2][0] = 0.0;
  2044.     transform_return[2][1] = 0.0;
  2045.     transform_return[2][2] = 1.0;
  2046.  
  2047.     return (0);
  2048. }
  2049.  
  2050.  
  2051. int
  2052. PEXXCToNPCTransform (npc_sub_volume, viewport,
  2053.     window_height, transform_return)
  2054.  
  2055. INPUT PEXNPCSubVolume    *npc_sub_volume;
  2056. INPUT PEXDeviceCoord    *viewport;
  2057. INPUT unsigned int    window_height;
  2058. OUTPUT PEXMatrix    transform_return;
  2059.  
  2060. {
  2061.     /*
  2062.      *       M4           M3             M2           M1   
  2063.      *                                                      
  2064.      *    1 0 0 Nx     Sx 0  0  0     1 0 0 -Vx    1  0 0 0
  2065.      *    0 1 0 Ny     0  Sy 0  0     0 1 0 -Vy    0 -1 0 H
  2066.      *    0 0 1 Nz     0  0  Sz 0     0 0 1 -Vz    0  0 1 0
  2067.      *    0 0 0  1     0  0  0  1     0 0 0  1     0  0 0 1
  2068.      *
  2069.      *    M1 : maps X drawable coordinates to DC (flips Y).
  2070.      *         H is the window height.
  2071.      *
  2072.      *    M2 : translates DC viewport to origin
  2073.      *         (Vx, Vy, Vz) is the lower left corner of the DC viewport.
  2074.      *
  2075.      *    M3 : scales DC viewport at origin to NPC subvolme at origin.
  2076.      *         Sx, Sy, Sz are the scale factors that maintain the aspect ratio.
  2077.      *
  2078.      *    M4 : translates NPC subvolume at origin to the correct position.
  2079.      *         (Nx, Ny, Nz) is the lower left corner of the NPC volume.
  2080.      */
  2081.  
  2082.     float         scale_x, scale_y, scale_z;
  2083.     int         dvx, dvy;
  2084.     float        dnx, dny;
  2085.     float        dvz, dnz;
  2086.     PEXDeviceCoord    new_viewport[2];
  2087.  
  2088.  
  2089.     dvx = viewport[1].x - viewport[0].x;
  2090.     dvy = viewport[1].y - viewport[0].y;
  2091.     dvz = viewport[1].z - viewport[0].z;
  2092.  
  2093.     if (dvx <= 0 || dvy <= 0 || !(viewport[0].z <= viewport[1].z))
  2094.     return (PEXBadViewport);
  2095.  
  2096.     if (BAD_SUBVOLUME (npc_sub_volume))
  2097.     return (PEXBadSubVolume);
  2098.  
  2099.     dnx = npc_sub_volume->max.x - npc_sub_volume->min.x;
  2100.     dny = npc_sub_volume->max.y - npc_sub_volume->min.y;
  2101.     dnz = npc_sub_volume->max.z - npc_sub_volume->min.z;
  2102.  
  2103.     scale_x = dnx / (float) dvx;
  2104.     scale_y = dny / (float) dvy;
  2105.     scale_z = NEAR_ZERO (dvz) ? 1.0 : (dnz / dvz);
  2106.  
  2107.     if (!NEAR_ZERO (scale_x - scale_y))
  2108.     {
  2109.     new_viewport[0].x = viewport[0].x;
  2110.     new_viewport[0].y = viewport[0].y;
  2111.     new_viewport[0].z = viewport[0].z;
  2112.  
  2113.     if (scale_x < scale_y)
  2114.     {
  2115.         new_viewport[1].x = viewport[0].x + (float) dvy * dnx / dny;
  2116.         new_viewport[1].y = viewport[1].y;
  2117.         new_viewport[1].z = viewport[1].z;
  2118.     }
  2119.     else
  2120.     {
  2121.         new_viewport[1].x = viewport[1].x;
  2122.         new_viewport[1].y = viewport[0].y + (float) dvx * dny / dnx;
  2123.         new_viewport[1].z = viewport[1].z;
  2124.     }
  2125.  
  2126.     viewport = new_viewport;
  2127.     }
  2128.  
  2129.     transform_return[0][0] = scale_x;
  2130.     transform_return[0][1] = 0.0;
  2131.     transform_return[0][2] = 0.0;
  2132.     transform_return[0][3] =
  2133.     npc_sub_volume->min.x - (scale_x * viewport[0].x);
  2134.  
  2135.     transform_return[1][0] = 0.0;
  2136.     transform_return[1][1] = -scale_y;
  2137.     transform_return[1][2] = 0.0;
  2138.     transform_return[1][3] =
  2139.     npc_sub_volume->min.y + scale_y * (window_height - viewport[0].y);
  2140.  
  2141.     transform_return[2][0] = 0.0;
  2142.     transform_return[2][1] = 0.0;
  2143.     transform_return[2][2] = 1.0;
  2144.     transform_return[2][3] =
  2145.     npc_sub_volume->min.z - (scale_z * viewport[0].z);
  2146.  
  2147.     transform_return[3][0] = 0.0;
  2148.     transform_return[3][1] = 0.0;
  2149.     transform_return[3][2] = 0.0;
  2150.     transform_return[3][3] = 1.0;
  2151.  
  2152.     return (0);
  2153. }
  2154.  
  2155.  
  2156. int
  2157. PEXXCToNPCTransform2D (npc_sub_volume, viewport,
  2158.     window_height, transform_return)
  2159.  
  2160. INPUT PEXNPCSubVolume    *npc_sub_volume;
  2161. INPUT PEXDeviceCoord2D    *viewport;
  2162. INPUT unsigned int    window_height;
  2163. INPUT PEXMatrix3x3    transform_return;
  2164.  
  2165. {
  2166.     /*
  2167.      *      M4         M3          M2          M1   
  2168.      *                                                      
  2169.      *    1 0 Nx     Sx 0  0     1 0 -Vx     1  0 0
  2170.      *    0 1 Ny     0  Sy 0     0 1 -Vy     0 -1 H
  2171.      *    0 0  1     0  0  1     0 0  1      0  0 1
  2172.      *
  2173.      *    M1 : maps X drawable coordinates to DC (flips Y).
  2174.      *         H is the window height.
  2175.      *
  2176.      *    M2 : translates DC viewport to origin
  2177.      *         (Vx, Vy) is the lower left corner of the DC viewport.
  2178.      *
  2179.      *    M3 : scales DC viewport at origin to NPC subvolme at origin.
  2180.      *         Sx, Sy are the scale factors that maintain the aspect ratio.
  2181.      *
  2182.      *    M4 : translates NPC subvolume at origin to the correct position.
  2183.      *         (Nx, Ny) is the lower left corner of the NPC volume.
  2184.      */
  2185.  
  2186.     float         scale_x, scale_y;
  2187.     int         dvx, dvy;
  2188.     float        dnx, dny;
  2189.     PEXDeviceCoord2D    new_viewport[2];
  2190.  
  2191.  
  2192.     dvx = viewport[1].x - viewport[0].x;
  2193.     dvy = viewport[1].y - viewport[0].y;
  2194.  
  2195.     if (dvx <= 0 || dvy <= 0)
  2196.     return (PEXBadViewport);
  2197.  
  2198.     if (BAD_SUBVOLUME (npc_sub_volume))
  2199.     return (PEXBadSubVolume);
  2200.  
  2201.     dnx = npc_sub_volume->max.x - npc_sub_volume->min.x;
  2202.     dny = npc_sub_volume->max.y - npc_sub_volume->min.y;
  2203.  
  2204.     scale_x = dnx / (float) dvx;
  2205.     scale_y = dny / (float) dvy;
  2206.  
  2207.     if (!NEAR_ZERO (scale_x - scale_y))
  2208.     {
  2209.     new_viewport[0].x = viewport[0].x;
  2210.     new_viewport[0].y = viewport[0].y;
  2211.  
  2212.     if (scale_x < scale_y)
  2213.     {
  2214.         new_viewport[1].x = viewport[0].x + (float) dvy * dnx / dny;
  2215.         new_viewport[1].y = viewport[1].y;
  2216.     }
  2217.     else
  2218.     {
  2219.         new_viewport[1].x = viewport[1].x;
  2220.         new_viewport[1].y = viewport[0].y + (float) dvx * dny / dnx;
  2221.     }
  2222.  
  2223.     viewport = new_viewport;
  2224.     }
  2225.  
  2226.     transform_return[0][0] = scale_x;
  2227.     transform_return[0][1] = 0.0;
  2228.     transform_return[0][2] =
  2229.     npc_sub_volume->min.x - (scale_x * viewport[0].x);
  2230.  
  2231.     transform_return[1][0] = 0.0;
  2232.     transform_return[1][1] = -scale_y;
  2233.     transform_return[1][2] =
  2234.     npc_sub_volume->min.y + scale_y * (window_height - viewport[0].y);
  2235.  
  2236.     transform_return[2][0] = 0.0;
  2237.     transform_return[2][1] = 0.0;
  2238.     transform_return[2][2] = 1.0;
  2239.  
  2240.     return (0);
  2241. }
  2242.  
  2243.  
  2244. int
  2245. PEXMapXCToNPC (point_count, points, window_height,
  2246.     z_dc, viewport, npc_sub_volume, view_count, views,
  2247.     view_return, count_return, points_return)
  2248.  
  2249. INPUT int        point_count;
  2250. INPUT PEXDeviceCoord2D    *points;
  2251. INPUT unsigned int    window_height;
  2252. INPUT double        z_dc;
  2253. INPUT PEXDeviceCoord    *viewport;
  2254. INPUT PEXNPCSubVolume    *npc_sub_volume;
  2255. INPUT int        view_count;
  2256. INPUT PEXViewEntry    *views;
  2257. OUTPUT int        *view_return;
  2258. OUTPUT int        *count_return;
  2259. OUTPUT PEXCoord        *points_return;
  2260.  
  2261. {
  2262.     PEXCoord    *xc_wz_points;
  2263.     PEXMatrix     xform;
  2264.     int        pts_in_view;
  2265.     int        max_pts_in_view;
  2266.     int        max_pts_view;
  2267.     int        status, i, j;
  2268.  
  2269.     /*
  2270.      * Fill in the Z value for each XC point.
  2271.      */
  2272.  
  2273.     xc_wz_points = (PEXCoord *) PEXAllocBuf (
  2274.     (unsigned) (point_count * sizeof (PEXCoord)));
  2275.  
  2276.     for (i = 0; i < point_count; i++)
  2277.     {
  2278.     xc_wz_points[i].x = points[i].x;
  2279.     xc_wz_points[i].y = points[i].y;
  2280.     xc_wz_points[i].z = z_dc;
  2281.     }
  2282.  
  2283.  
  2284.     /*
  2285.      * Determine the transformation matrix that takes us from XC to NPC.
  2286.      */
  2287.  
  2288.     status = PEXXCToNPCTransform (npc_sub_volume, viewport,
  2289.     window_height, xform);
  2290.  
  2291.     if (status != 0)
  2292.     return (status);
  2293.  
  2294.  
  2295.     /*
  2296.      * Now transform the XC points to NPC.
  2297.      */
  2298.  
  2299.     status = PEXTransformPoints (xform, point_count,
  2300.     xc_wz_points, points_return);
  2301.  
  2302.     PEXFreeBuf ((char *) xc_wz_points);
  2303.  
  2304.     if (status != 0)
  2305.     return (status);
  2306.  
  2307.  
  2308.     /*
  2309.      * Search for the view containing all (or most) of the NPC points.
  2310.      */
  2311.  
  2312.     max_pts_view = -1;
  2313.     max_pts_in_view = 0;
  2314.  
  2315.     for (i = 0; i < view_count; i++)
  2316.     {
  2317.     for (j = pts_in_view = 0; j < point_count; j++)
  2318.     {
  2319.         if (POINT3D_IN_VIEW (points_return[j], views[i]))
  2320.         pts_in_view++;
  2321.     }
  2322.         
  2323.     if (pts_in_view == point_count)
  2324.     {
  2325.         max_pts_in_view = point_count;
  2326.         max_pts_view = i;
  2327.         break;
  2328.     }
  2329.     else if (pts_in_view > max_pts_in_view)
  2330.     {
  2331.         max_pts_in_view = pts_in_view;
  2332.         max_pts_view = i;
  2333.     }
  2334.     }
  2335.  
  2336.  
  2337.     /*
  2338.      * Make sure we only return points that are in the view we found.
  2339.      */
  2340.  
  2341.     if (max_pts_in_view > 0 && max_pts_in_view != point_count)
  2342.     {
  2343.     int count = 0;
  2344.  
  2345.     for (i = 0; i < point_count && count < max_pts_in_view; i++)
  2346.     {
  2347.         if (POINT3D_IN_VIEW (points_return[i], views[max_pts_view]))
  2348.         {
  2349.         points_return[count].x = points_return[i].x;
  2350.         points_return[count].y = points_return[i].y;
  2351.         points_return[count].z = points_return[i].z;
  2352.         count++;
  2353.         }
  2354.     }
  2355.     }
  2356.         
  2357.     *view_return = max_pts_view;
  2358.     *count_return = max_pts_in_view;
  2359.  
  2360.     return (0);
  2361. }
  2362.  
  2363.  
  2364. int
  2365. PEXMapXCToNPC2D (point_count, points, window_height,
  2366.     viewport, npc_sub_volume, view_count, views,
  2367.     view_return, count_return, points_return)
  2368.  
  2369. INPUT int        point_count;
  2370. INPUT PEXDeviceCoord2D    *points;
  2371. INPUT unsigned int    window_height;
  2372. INPUT PEXDeviceCoord2D  *viewport;
  2373. INPUT PEXNPCSubVolume    *npc_sub_volume;
  2374. INPUT int        view_count;
  2375. INPUT PEXViewEntry    *views;
  2376. OUTPUT int        *view_return;
  2377. OUTPUT int        *count_return;
  2378. OUTPUT PEXCoord2D    *points_return;
  2379.  
  2380. {
  2381.     PEXMatrix3x3    xform;
  2382.     PEXCoord2D        *xc_points;
  2383.     int            pts_in_view;
  2384.     int            max_pts_in_view;
  2385.     int            max_pts_view;
  2386.     int            status, i, j;
  2387.  
  2388.     /*
  2389.      * Fill in the XC point.
  2390.      */
  2391.  
  2392.     xc_points = (PEXCoord2D *) PEXAllocBuf (
  2393.     (unsigned) (point_count * sizeof (PEXCoord2D)));
  2394.  
  2395.     for (i = 0; i < point_count; i++)
  2396.     {
  2397.     xc_points[i].x = points[i].x;
  2398.     xc_points[i].y = points[i].y;
  2399.     }
  2400.  
  2401.  
  2402.     /*
  2403.      * Determine the transformation matrix that takes us from XC to NPC.
  2404.      */
  2405.  
  2406.     status = PEXXCToNPCTransform2D (npc_sub_volume, viewport,
  2407.     window_height, xform);
  2408.  
  2409.     if (status != 0)
  2410.     return (status);
  2411.  
  2412.  
  2413.     /*
  2414.      * Now transform the XC points to NPC.
  2415.      */
  2416.  
  2417.     status = PEXTransformPoints2D (xform, point_count,
  2418.     xc_points, points_return);
  2419.  
  2420.     PEXFreeBuf ((char *) xc_points);
  2421.  
  2422.     if (status != 0)
  2423.     return (status);
  2424.  
  2425.  
  2426.     /*
  2427.      * Search for the view containing all (or most) of the NPC points.
  2428.      */
  2429.  
  2430.     max_pts_view = -1;
  2431.     max_pts_in_view = 0;
  2432.  
  2433.     for (i = 0; i < view_count; i++)
  2434.     {
  2435.     for (j = pts_in_view = 0; j < point_count; j++)
  2436.     {
  2437.         if (POINT2D_IN_VIEW (points_return[j], views[i]))
  2438.         pts_in_view++;
  2439.     }
  2440.         
  2441.     if (pts_in_view == point_count)
  2442.     {
  2443.         max_pts_in_view = point_count;
  2444.         max_pts_view = i;
  2445.         break;
  2446.     }
  2447.     else if (pts_in_view > max_pts_in_view)
  2448.     {
  2449.         max_pts_in_view = pts_in_view;
  2450.         max_pts_view = i;
  2451.     }
  2452.     }
  2453.  
  2454.  
  2455.     /*
  2456.      * Make sure we only return points that are in the view we found.
  2457.      */
  2458.  
  2459.     if (max_pts_in_view > 0 && max_pts_in_view != point_count)
  2460.     {
  2461.     int count = 0;
  2462.  
  2463.     for (i = 0; i < point_count && count < max_pts_in_view; i++)
  2464.     {
  2465.         if (POINT2D_IN_VIEW (points_return[i], views[max_pts_view]))
  2466.         {
  2467.         points_return[count].x = points_return[i].x;
  2468.         points_return[count].y = points_return[i].y;
  2469.         count++;
  2470.         }
  2471.     }
  2472.     }
  2473.         
  2474.     *view_return = max_pts_view;
  2475.     *count_return = max_pts_in_view;
  2476.  
  2477.     return (0);
  2478. }
  2479.  
  2480.  
  2481. int
  2482. PEXInvertMatrix (matrix, inverseReturn)
  2483.  
  2484. INPUT PEXMatrix        matrix;
  2485. OUTPUT PEXMatrix    inverseReturn;
  2486.  
  2487. {
  2488.     /*
  2489.      * This routine calculates a 4x4 inverse matrix.  It uses Gaussian
  2490.      * elimination on the system [matrix][inverse] = [identity].  The values
  2491.      * of the matrix then become the coefficients of the system of equations
  2492.      * that evolves from this equation.  The system is then solved for the
  2493.      * values of [inverse].  The algorithm solves for each column of [inverse]
  2494.      * in turn.  Partial pivoting is also done to reduce the numerical error
  2495.      * involved in the computations.  If singularity is detected, the routine
  2496.      * ends and returns an error.
  2497.      *
  2498.      * (See Numerical Analysis, L.W. Johnson and R.D.Riess, 1982).
  2499.      */
  2500.  
  2501.     int        ipivot, h, i, j, k;
  2502.     float    aug[4][5];
  2503.     float    pivot, temp, q;
  2504.  
  2505.     for (h = 0; h < 4; h++)   /* solve column by column */
  2506.     {
  2507.         /*
  2508.      * Set up the augmented matrix for [matrix][inverse] = [identity]
  2509.      */
  2510.  
  2511.         for (i = 0; i < 4; i++)
  2512.         {
  2513.             aug[i][0] = matrix[i][0];
  2514.             aug[i][1] = matrix[i][1];
  2515.             aug[i][2] = matrix[i][2];
  2516.             aug[i][3] = matrix[i][3];
  2517.             aug[i][4] = (h == i) ? 1.0 : 0.0;
  2518.         }
  2519.  
  2520.         /*
  2521.      * Search for the largest entry in column i, rows i through 3.
  2522.          * ipivot is the row index of the largest entry.
  2523.      */
  2524.  
  2525.         for (i = 0; i < 3; i++)
  2526.         {
  2527.             pivot = 0.0;
  2528.  
  2529.             for (j = i; j < 4; j++)
  2530.             {
  2531.                 temp = ABS (aug[j][i]);
  2532.                 if (pivot < temp)
  2533.                 {
  2534.                     pivot = temp;
  2535.                     ipivot = j;
  2536.                 }
  2537.             }
  2538.             if (NEAR_ZERO (pivot))             /* singularity check */
  2539.                 return (PEXBadMatrix);
  2540.  
  2541.             /* interchange rows i and ipivot */
  2542.  
  2543.             if (ipivot != i)
  2544.             {
  2545.                 for (k = i; k < 5; k++)
  2546.                 {
  2547.                     temp = aug[i][k];
  2548.                     aug[i][k] = aug[ipivot][k];
  2549.                     aug[ipivot][k] = temp;
  2550.                 }
  2551.             }
  2552.  
  2553.             /* put augmented matrix in echelon form */
  2554.  
  2555.             for (k = i + 1; k < 4; k++)
  2556.             {
  2557.                 q = -aug[k][i] / aug[i][i];
  2558.                 aug[k][i] = 0.0;
  2559.                 for (j = i + 1; j < 5; j++)
  2560.                 {
  2561.                     aug[k][j] = q * aug[i][j] + aug[k][j];
  2562.                 }
  2563.             }
  2564.         }
  2565.  
  2566.         if (NEAR_ZERO (aug[3][3]))           /* singularity check */
  2567.             return (PEXBadMatrix);
  2568.  
  2569.         /* backsolve to obtain values for inverse matrix */
  2570.  
  2571.         inverseReturn[3][h] = aug[3][4] / aug[3][3];
  2572.  
  2573.         for (k = 1; k < 4; k++)
  2574.         {
  2575.             q = 0.0;
  2576.             for (j = 1; j <= k; j++)
  2577.             {
  2578.                 q = q + aug[3 - k][4 - j] * inverseReturn[4 - j][h];
  2579.             }
  2580.             inverseReturn[3 - k][h] = (aug[3 - k][4] - q) / aug[3 - k][3 - k];
  2581.         }
  2582.     }
  2583.  
  2584.     return (0);
  2585. }
  2586.  
  2587.  
  2588. int
  2589. PEXInvertMatrix2D (matrix, inverseReturn)
  2590.  
  2591. PEXMatrix3x3    matrix;
  2592. PEXMatrix3x3    inverseReturn;
  2593.  
  2594. {
  2595.     /*
  2596.      * This routine calculates a 4x4 inverse matrix.  It uses Gaussian
  2597.      * elimination on the system [matrix][inverse] = [identity].  The values
  2598.      * of the matrix then become the coefficients of the system of equations
  2599.      * that evolves from this equation.  The system is then solved for the
  2600.      * values of [inverse].  The algorithm solves for each column of [inverse]
  2601.      * in turn.  Partial pivoting is also done to reduce the numerical error
  2602.      * involved in the computations.  If singularity is detected, the routine
  2603.      * ends and returns an error.
  2604.      *
  2605.      * (See Numerical Analysis, L.W. Johnson and R.D.Riess, 1982).
  2606.      */
  2607.  
  2608.     int        ipivot, h, i, j, k;
  2609.     float    aug[3][4];
  2610.     float    pivot, temp, q;
  2611.  
  2612.  
  2613.     for (h = 0; h < 3; h++)   /* solve column by column */
  2614.     {
  2615.         /*
  2616.      * Set up the augmented matrix for [matrix][inverse] = [identity]
  2617.      */
  2618.  
  2619.         for (i = 0; i < 3; i++)
  2620.         {
  2621.             aug[i][0] = matrix[i][0];
  2622.             aug[i][1] = matrix[i][1];
  2623.             aug[i][2] = matrix[i][2];
  2624.             aug[i][3] = (h == i) ? 1.0 : 0.0;
  2625.         }
  2626.  
  2627.         /*
  2628.      * Search for the largest entry in column i, rows i through 3.
  2629.          * ipivot is the row index of the largest entry.
  2630.      */
  2631.  
  2632.         for (i = 0; i < 2; i++)
  2633.         {
  2634.             pivot = 0.0;
  2635.  
  2636.             for (j = i; j < 3; j++)
  2637.             {
  2638.                 temp = ABS (aug[j][i]);
  2639.                 if (pivot < temp)
  2640.                 {
  2641.                     pivot = temp;
  2642.                     ipivot = j;
  2643.                 }
  2644.             }
  2645.             if (NEAR_ZERO (pivot))         /* singularity check */
  2646.                 return (PEXBadMatrix);
  2647.  
  2648.             /* interchange rows i and ipivot */
  2649.  
  2650.             if (ipivot != i)
  2651.             {
  2652.                 for (k = i; k < 4; k++)
  2653.                 {
  2654.                     temp = aug[i][k];
  2655.                     aug[i][k] = aug[ipivot][k];
  2656.                     aug[ipivot][k] = temp;
  2657.                 }
  2658.             }
  2659.  
  2660.             /* put augmented matrix in echelon form */
  2661.  
  2662.             for (k = i + 1; k < 3; k++)
  2663.             {
  2664.                 q = -aug[k][i] / aug[i][i];
  2665.                 aug[k][i] = 0.;
  2666.                 for (j = i + 1; j < 4; j++)
  2667.                 {
  2668.                     aug[k][j] = q * aug[i][j] + aug[k][j];
  2669.                 }
  2670.             }
  2671.         }
  2672.  
  2673.         if (NEAR_ZERO (aug[2][2]))           /* singularity check */
  2674.             return (PEXBadMatrix);
  2675.  
  2676.         /* backsolve to obtain values for inverse matrix */
  2677.  
  2678.         inverseReturn[2][h] = aug[2][3] / aug[2][2];
  2679.  
  2680.         for (k = 1; k < 3; k++)
  2681.         {
  2682.             q = 0.0;
  2683.             for (j = 1; j <= k; j++)
  2684.             {
  2685.                 q = q + aug[2 - k][3 - j] * inverseReturn[3 - j][h];
  2686.             }
  2687.             inverseReturn[2 - k][h] = (aug[2 - k][3] - q) / aug[2 - k][2 - k];
  2688.         }
  2689.     }
  2690.  
  2691.     return (0);
  2692. }
  2693.  
  2694.  
  2695. void
  2696. PEXIdentityMatrix (matrix_return)
  2697.  
  2698. OUTPUT PEXMatrix    matrix_return;
  2699.  
  2700. {
  2701.     matrix_return[0][0] = 1.0;
  2702.     matrix_return[0][1] = 0.0;
  2703.     matrix_return[0][2] = 0.0;
  2704.     matrix_return[0][3] = 0.0;
  2705.  
  2706.     matrix_return[1][0] = 0.0;
  2707.     matrix_return[1][1] = 1.0;
  2708.     matrix_return[1][2] = 0.0;
  2709.     matrix_return[1][3] = 0.0;
  2710.  
  2711.     matrix_return[2][0] = 0.0;
  2712.     matrix_return[2][1] = 0.0;
  2713.     matrix_return[2][2] = 1.0;
  2714.     matrix_return[2][3] = 0.0;
  2715.  
  2716.     matrix_return[3][0] = 0.0;
  2717.     matrix_return[3][1] = 0.0;
  2718.     matrix_return[3][2] = 0.0;
  2719.     matrix_return[3][3] = 1.0;
  2720. }
  2721.  
  2722.  
  2723. void
  2724. PEXIdentityMatrix2D (matrix_return)
  2725.  
  2726. OUTPUT PEXMatrix3x3    matrix_return;
  2727.  
  2728. {
  2729.     matrix_return[0][0] = 1.0;
  2730.     matrix_return[0][1] = 0.0;
  2731.     matrix_return[0][2] = 0.0;
  2732.  
  2733.     matrix_return[1][0] = 0.0;
  2734.     matrix_return[1][1] = 1.0;
  2735.     matrix_return[1][2] = 0.0;
  2736.  
  2737.     matrix_return[2][0] = 0.0;
  2738.     matrix_return[2][1] = 0.0;
  2739.     matrix_return[2][2] = 1.0;
  2740. }
  2741.  
  2742.  
  2743. int
  2744. PEXGeoNormFillArea (facet_attributes, vertex_attributes,
  2745.     color_type, facet_data, count, vertices)    
  2746.  
  2747. INPUT unsigned int    facet_attributes;
  2748. INPUT unsigned int    vertex_attributes;
  2749. INPUT int        color_type;
  2750. INOUT PEXFacetData    *facet_data;
  2751. INPUT unsigned int    count;
  2752. INPUT PEXArrayOfVertex    vertices;
  2753.  
  2754. {
  2755.     PEXCoord    *v1, *v2, *v3;
  2756.     int        found_v2, found_v3;
  2757.     float    dx, dy, dz, length;
  2758.     int        lenofColor, vert_size;
  2759.     PEXVector    *normal;
  2760.     char    *ptr;
  2761.  
  2762.  
  2763.     /*
  2764.      * Check to see if we should compute the normal.
  2765.      */
  2766.  
  2767.     if (!(facet_attributes & PEXGANormal))
  2768.     return (0);
  2769.  
  2770.  
  2771.     /*
  2772.      * Make sure there are enough vertices to compute the normal.
  2773.      */
  2774.  
  2775.     if (count < 3)
  2776.     return (PEXBadPrimitive);
  2777.  
  2778.  
  2779.     /*
  2780.      * Get a pointer to the normal data structure.
  2781.      */
  2782.  
  2783.     lenofColor = GetColorLength (color_type);
  2784.  
  2785.     if (facet_attributes & PEXGAColor)
  2786.     {
  2787.     normal = (PEXVector *) ((char *) facet_data +
  2788.         NUMBYTES (lenofColor));
  2789.     }
  2790.     else
  2791.     normal = (PEXVector *) facet_data;
  2792.  
  2793.  
  2794.     /*
  2795.      * Now find the first 3 non-colinear points and take their
  2796.      * cross product to get the normal.
  2797.      */
  2798.  
  2799.     vert_size = NUMBYTES (GetVertexWithDataLength (
  2800.     vertex_attributes, lenofColor));
  2801.  
  2802.     ptr = (char *) vertices.no_data;
  2803.     v1 = (PEXCoord *) ptr;
  2804.     count--;
  2805.  
  2806.     found_v2 = 0;
  2807.  
  2808.     while (!found_v2 && count > 0)
  2809.     {
  2810.     /* find v2, such that v2 is not coincident with v1 */
  2811.  
  2812.     ptr += vert_size;
  2813.     v2 = (PEXCoord *) ptr;
  2814.     count--;
  2815.  
  2816.     dx = v2->x - v1->x;
  2817.     dy = v2->y - v1->y;
  2818.     dz = v2->z - v1->z;
  2819.  
  2820.     if (!NEAR_ZERO (dx) || !NEAR_ZERO (dy) || !NEAR_ZERO (dz))
  2821.         found_v2 = 1;
  2822.     }
  2823.  
  2824.     found_v3 = 0;
  2825.  
  2826.     while (!found_v3 && count > 0)
  2827.     {
  2828.     /* find v3, such that v3 is non-colinear with v1 and v2 */
  2829.  
  2830.     ptr += vert_size;
  2831.     v3 = (PEXCoord *) ptr;
  2832.     count--;
  2833.  
  2834.     CROSS_PRODUCT (v1, v2, v1, v3, normal);
  2835.     NORMALIZE_VECTOR (normal, length);
  2836.  
  2837.     if (!NEAR_ZERO (length))
  2838.         found_v3 = 1;
  2839.     }
  2840.  
  2841.     if (found_v3)
  2842.     return (0);
  2843.     else
  2844.     return (PEXBadPrimitive);
  2845. }
  2846.  
  2847.  
  2848. int
  2849. PEXGeoNormFillAreaSet (facet_attributes, vertex_attributes,
  2850.     color_type, count, facet_data, vertex_lists)
  2851.  
  2852. INPUT unsigned int    facet_attributes;
  2853. INPUT unsigned int    vertex_attributes;
  2854. INPUT int        color_type;
  2855. INPUT unsigned int    count;
  2856. INOUT PEXFacetData    *facet_data;
  2857. INPUT PEXListOfVertex    *vertex_lists;
  2858.  
  2859. {
  2860.     PEXCoord    *v1, *v2, *v3;
  2861.     int        lenofColor, vert_size, vcount;
  2862.     int        found_v2, done, i;
  2863.     float    dx, dy, dz, length;
  2864.     PEXVector    *normal;
  2865.     char    *ptr;
  2866.  
  2867.  
  2868.     /*
  2869.      * Check to see if we should compute the normal.
  2870.      */
  2871.  
  2872.     if (!(facet_attributes & PEXGANormal))
  2873.     return (0);
  2874.  
  2875.  
  2876.     /*
  2877.      * Get a pointer to the normal data structure.
  2878.      */
  2879.  
  2880.     lenofColor = GetColorLength (color_type);
  2881.  
  2882.     if (facet_attributes & PEXGAColor)
  2883.     {
  2884.     normal = (PEXVector *) ((char *) facet_data +
  2885.         NUMBYTES (lenofColor));
  2886.     }
  2887.     else
  2888.     normal = (PEXVector *) facet_data;
  2889.  
  2890.  
  2891.     /*
  2892.      * Now find the first 3 non-colinear points in one of the fill areas
  2893.      * of the set, and take their cross product to get the normal.
  2894.      */
  2895.  
  2896.     vert_size = NUMBYTES (GetVertexWithDataLength (
  2897.     vertex_attributes, lenofColor));
  2898.  
  2899.     for (i = done = 0; i < count && !done; i++)
  2900.     {
  2901.     if ((vcount = vertex_lists[i].count) > 2)
  2902.     {
  2903.         ptr = (char *) vertex_lists[i].vertices.no_data;
  2904.  
  2905.         v1 = (PEXCoord *) ptr;
  2906.         vcount--;
  2907.  
  2908.         found_v2 = 0;
  2909.  
  2910.         while (!found_v2 && vcount > 0)
  2911.         {
  2912.         /* find v2, such that v2 is not coincident with v1 */
  2913.  
  2914.         ptr += vert_size;
  2915.         v2 = (PEXCoord *) ptr;
  2916.         vcount--;
  2917.  
  2918.         dx = v2->x - v1->x;
  2919.         dy = v2->y - v1->y;
  2920.         dz = v2->z - v1->z;
  2921.  
  2922.         if (!NEAR_ZERO (dx) || !NEAR_ZERO (dy) || !NEAR_ZERO (dz))
  2923.             found_v2 = 1;
  2924.         }
  2925.  
  2926.         while (!done && vcount > 0)
  2927.         {
  2928.         /* find v3, such that v3 is non-colinear with v1 and v2 */
  2929.  
  2930.         ptr += vert_size;
  2931.         v3 = (PEXCoord *) ptr;
  2932.         vcount--;
  2933.  
  2934.         CROSS_PRODUCT (v1, v2, v1, v3, normal);
  2935.         NORMALIZE_VECTOR (normal, length);
  2936.  
  2937.         if (!NEAR_ZERO (length))
  2938.             done = 1;
  2939.         }
  2940.     }
  2941.     }
  2942.  
  2943.     if (done)
  2944.     return (0);
  2945.     else
  2946.     return (PEXBadPrimitive);
  2947. }
  2948.  
  2949.  
  2950. int
  2951. PEXGeoNormTriangleStrip (facet_attributes, vertex_attributes,
  2952.     color_type, facet_data, count, vertices)
  2953.  
  2954. INPUT unsigned int        facet_attributes;
  2955. INPUT unsigned int        vertex_attributes;
  2956. INPUT int            color_type;
  2957. INOUT PEXArrayOfFacetData    facet_data;
  2958. INPUT unsigned int        count;
  2959. INPUT PEXArrayOfVertex        vertices;
  2960.  
  2961. {
  2962.     PEXCoord    *v1, *v2, *v3;
  2963.     int        vert_size, facet_size;
  2964.     int        lenofColor, i;
  2965.     PEXVector    *normal;
  2966.     float    length;
  2967.     char    *ptr;
  2968.     int        status = 0;
  2969.  
  2970.  
  2971.     /*
  2972.      * Check to see if we should compute the normals.
  2973.      */
  2974.  
  2975.     if (!(facet_attributes & PEXGANormal))
  2976.     return (0);
  2977.  
  2978.  
  2979.     /*
  2980.      * Make sure there are enough vertices to compute the normals.
  2981.      */
  2982.  
  2983.     if (count < 3)
  2984.     return (PEXBadPrimitive);
  2985.  
  2986.  
  2987.     /*
  2988.      * Get a pointer to the first normal.
  2989.      */
  2990.  
  2991.     lenofColor = GetColorLength (color_type);
  2992.  
  2993.     if (facet_attributes & PEXGAColor)
  2994.     {
  2995.     normal = (PEXVector *) ((char *) facet_data.index +
  2996.         NUMBYTES (lenofColor));
  2997.     }
  2998.     else
  2999.     normal = (PEXVector *) facet_data.normal;
  3000.  
  3001.  
  3002.     /*
  3003.      * Now compute all of the normals in the strip.
  3004.      */
  3005.  
  3006.     vert_size = NUMBYTES (GetVertexWithDataLength (
  3007.     vertex_attributes, lenofColor));
  3008.  
  3009.     facet_size = NUMBYTES (GetFacetDataLength (
  3010.     facet_attributes, lenofColor));
  3011.  
  3012.     ptr = (char *) vertices.no_data;
  3013.  
  3014.     for (i = 0; i < count - 2; i++)
  3015.     {
  3016.     v1 = (PEXCoord *) ptr;
  3017.     ptr += vert_size;
  3018.     v2 = (PEXCoord *) ptr;
  3019.     ptr += vert_size;
  3020.     v3 = (PEXCoord *) ptr;
  3021.     ptr -= vert_size;
  3022.  
  3023.     if (i % 2)
  3024.     {
  3025.         /* cross product of v1v3 x v1v2 */
  3026.  
  3027.         CROSS_PRODUCT (v1, v3, v1, v2, normal);
  3028.     }
  3029.     else
  3030.     {
  3031.         /* cross product of v1v2 x v1v3 */
  3032.  
  3033.         CROSS_PRODUCT (v1, v2, v1, v3, normal);
  3034.     }
  3035.  
  3036.     NORMALIZE_VECTOR (normal, length);
  3037.  
  3038.     if (NEAR_ZERO (length))
  3039.     {
  3040.         normal->x = normal->y = normal->z = 0.0;
  3041.         status = PEXBadPrimitive;
  3042.     }
  3043.  
  3044.     normal = (PEXVector *) ((char *) normal + facet_size);
  3045.     }
  3046.  
  3047.     return (status);
  3048. }
  3049.  
  3050.  
  3051. int
  3052. PEXGeoNormQuadrilateralMesh (facet_attributes, vertex_attributes,
  3053.     color_type, facet_data, col_count, row_count, vertices)
  3054.  
  3055. INPUT unsigned int        facet_attributes;
  3056. INPUT unsigned int        vertex_attributes;
  3057. INPUT int            color_type;
  3058. INOUT PEXArrayOfFacetData    facet_data;
  3059. INPUT unsigned int        col_count;
  3060. INPUT unsigned int        row_count;
  3061. INPUT PEXArrayOfVertex        vertices;
  3062.  
  3063. {
  3064.     PEXCoord    *v1, *v2, *v3, *v4;
  3065.     int        vert_size, facet_size;
  3066.     int        lenofColor, row, col;
  3067.     PEXVector    *normal;
  3068.     float    length;
  3069.     int        status = 0;
  3070.  
  3071.  
  3072.     /*
  3073.      * Check to see if we should compute the normals.
  3074.      */
  3075.  
  3076.     if (!(facet_attributes & PEXGANormal))
  3077.     return (0);
  3078.  
  3079.  
  3080.     /*
  3081.      * Make sure there are enough vertices to compute the normals.
  3082.      */
  3083.  
  3084.     if (row_count < 2 || col_count < 2)
  3085.     return (PEXBadPrimitive);
  3086.  
  3087.  
  3088.     /*
  3089.      * Get a pointer to the first normal.
  3090.      */
  3091.  
  3092.     lenofColor = GetColorLength (color_type);
  3093.  
  3094.     if (facet_attributes & PEXGAColor)
  3095.     {
  3096.     normal = (PEXVector *) ((char *) facet_data.index +
  3097.         NUMBYTES (lenofColor));
  3098.     }
  3099.     else
  3100.     normal = (PEXVector *) facet_data.normal;
  3101.  
  3102.  
  3103.     /*
  3104.      * Now compute all of the normals in the quad mesh.
  3105.      */
  3106.  
  3107.     vert_size = NUMBYTES (GetVertexWithDataLength (
  3108.     vertex_attributes, lenofColor));
  3109.  
  3110.     facet_size = NUMBYTES (GetFacetDataLength (
  3111.     facet_attributes, lenofColor));
  3112.  
  3113.     for (row = 0; row < row_count - 1; row++)
  3114.     for (col = 0; col < col_count - 1; col++)
  3115.     {
  3116.         /*
  3117.          * v1 = vert[row    , col    ]
  3118.          * v2 = vert[row + 1, col + 1]
  3119.          * v3 = vert[row + 1, col    ] 
  3120.          * v4 = vert[row    , col + 1]
  3121.          *
  3122.          * Take cross product of v1v2 x v3v4, then normalize.
  3123.          */
  3124.  
  3125.         v1 = (PEXCoord *) ((char *) vertices.no_data +
  3126.         (row * col_count + col) * vert_size);
  3127.         
  3128.         v4 = (PEXCoord *) ((char *) v1 + vert_size);
  3129.  
  3130.         v3 = (PEXCoord *) ((char *) v1 + col_count * vert_size);
  3131.  
  3132.         v2 = (PEXCoord *) ((char *) v3 + vert_size);
  3133.         
  3134.         CROSS_PRODUCT (v1, v2, v3, v4, normal);
  3135.         NORMALIZE_VECTOR (normal, length);
  3136.  
  3137.         if (NEAR_ZERO (length))
  3138.         {
  3139.         normal->x = normal->y = normal->z = 0.0;
  3140.         status = PEXBadPrimitive;
  3141.         }
  3142.  
  3143.         normal = (PEXVector *) ((char *) normal + facet_size);
  3144.     }
  3145.  
  3146.     return (status);
  3147. }
  3148.  
  3149.  
  3150. int
  3151. PEXGeoNormSetOfFillAreaSets (facet_attributes, vertex_attributes,
  3152.     color_type, set_count, facet_data, vertex_count, vertices,
  3153.     index_count, connectivity)
  3154.  
  3155. INPUT unsigned int        facet_attributes;
  3156. INPUT unsigned int        vertex_attributes;
  3157. INPUT int            color_type;
  3158. INPUT unsigned int        set_count;
  3159. INOUT PEXArrayOfFacetData    facet_data;
  3160. INPUT unsigned int        vertex_count;
  3161. INPUT PEXArrayOfVertex        vertices;
  3162. INPUT unsigned int        index_count;
  3163. INPUT PEXConnectivityData    *connectivity;
  3164. {
  3165.     PEXConnectivityData *pConnectivity;
  3166.     PEXListOfUShort     *pList;
  3167.     PEXCoord        *v1, *v2, *v3;
  3168.     int            vert_size, facet_size;
  3169.     float        dx, dy, dz, length;
  3170.     int            lenofColor, done;
  3171.     int            index, found_v2, i, j;
  3172.     PEXVector        *normal;
  3173.     int            status = 0;
  3174.  
  3175.  
  3176.     /*
  3177.      * Check to see if we should compute the normals.
  3178.      */
  3179.  
  3180.     if (!(facet_attributes & PEXGANormal))
  3181.     return (0);
  3182.  
  3183.  
  3184.     /*
  3185.      * Make sure there are enough vertices/indices to compute the normals.
  3186.      */
  3187.  
  3188.     if (index_count < 3 || vertex_count < 3)
  3189.     return (PEXBadPrimitive);
  3190.  
  3191.  
  3192.     /*
  3193.      * Get a pointer to the first normal.
  3194.      */
  3195.  
  3196.     lenofColor = GetColorLength (color_type);
  3197.  
  3198.     if (facet_attributes & PEXGAColor)
  3199.     {
  3200.     normal = (PEXVector *) ((char *) facet_data.index +
  3201.         NUMBYTES (lenofColor));
  3202.     }
  3203.     else
  3204.     normal = (PEXVector *) facet_data.normal;
  3205.  
  3206.  
  3207.     /*
  3208.      * Now compute a normal for each fill area set.
  3209.      */
  3210.  
  3211.     vert_size = NUMBYTES (GetVertexWithDataLength (
  3212.     vertex_attributes, lenofColor));
  3213.  
  3214.     facet_size = NUMBYTES (GetFacetDataLength (
  3215.     facet_attributes, lenofColor));
  3216.  
  3217.     pConnectivity = connectivity;
  3218.  
  3219.     for (i = 0; i < set_count; i++)
  3220.     {
  3221.     pList = pConnectivity->lists;
  3222.     done = 0;
  3223.  
  3224.     for (j = 0; j < (int) pConnectivity->count && !done; j++, pList++)
  3225.     {
  3226.         if (pList->count > 2)
  3227.         {
  3228.         v1 = (PEXCoord *) ((char *) vertices.no_data +
  3229.             vert_size * pList->shorts[0]);
  3230.  
  3231.         index = 1;
  3232.         found_v2 = 0;
  3233.  
  3234.         while (!found_v2 && index < (int) pList->count)
  3235.         {
  3236.             /* find v2, such that v2 is not coincident with v1 */
  3237.  
  3238.             v2 = (PEXCoord *) ((char *) vertices.no_data +
  3239.                 vert_size * pList->shorts[index]);
  3240.  
  3241.             index++;
  3242.  
  3243.             dx = v2->x - v1->x;
  3244.             dy = v2->y - v1->y;
  3245.             dz = v2->z - v1->z;
  3246.  
  3247.             if (!NEAR_ZERO (dx) || !NEAR_ZERO (dy) || !NEAR_ZERO (dz))
  3248.             found_v2 = 1;
  3249.         }
  3250.  
  3251.         while (!done && index < (int) pList->count)
  3252.         {
  3253.             /* find v3, such that v3 is non-colinear with v1 and v2 */
  3254.  
  3255.             v3 = (PEXCoord *) ((char *) vertices.no_data +
  3256.                 vert_size * pList->shorts[index]);
  3257.  
  3258.             index++;
  3259.  
  3260.             CROSS_PRODUCT (v1, v2, v1, v3, normal);
  3261.             NORMALIZE_VECTOR (normal, length);
  3262.  
  3263.             if (!NEAR_ZERO (length))
  3264.             done = 1;
  3265.         }
  3266.         }
  3267.     }
  3268.  
  3269.     if (!done)
  3270.     {
  3271.         normal->x = normal->y = normal->z = 0.0;
  3272.         status = PEXBadPrimitive;
  3273.     }
  3274.  
  3275.     normal = (PEXVector *) ((char *) normal + facet_size);
  3276.     pConnectivity++;
  3277.     }
  3278.  
  3279.     return (status);
  3280. }
  3281.