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

GIS编程

开发平台:

Visual C++

  1. /*
  2.  * MODULE: extrude.c
  3.  *
  4.  * FUNCTION:
  5.  * Provides  code for the cylinder, cone and extrusion routines. 
  6.  * The cylinders/cones/etc. are built on top of general purpose
  7.  * extrusions. The code that handles the general purpose extrusions 
  8.  * is in other modules.
  9.  * 
  10.  * AUTHOR:
  11.  * written by Linas Vepstas August/September 1991
  12.  * added polycone, February 1993
  13.  */
  14. #include <stdlib.h>
  15. #include <math.h>
  16. #include <string.h> /* for the memcpy() subroutine */
  17. #include <GL/tube.h>
  18. #include "gutil.h"
  19. #include "vvector.h"
  20. #include "tube_gc.h"
  21. #include "extrude.h"
  22. #include "intersect.h"
  23. /* ============================================================ */
  24. /* The routine below  determines the type of join style that will be
  25.  * used for tubing. */
  26. void gleSetJoinStyle (int style) 
  27. {
  28.    INIT_GC();
  29.    extrusion_join_style = style;
  30. }
  31. int gleGetJoinStyle (void)
  32. {
  33.    INIT_GC();
  34.    return (extrusion_join_style);
  35. }
  36. /* ============================================================ */
  37. /*
  38.  * draw a general purpose extrusion 
  39.  */
  40. void gleSuperExtrusion (int ncp,               /* number of contour points */
  41.                 gleDouble contour[][2],    /* 2D contour */
  42.                 gleDouble cont_normal[][2], /* 2D contour normals */
  43.                 gleDouble up[3],           /* up vector for contour */
  44.                 int npoints,           /* numpoints in poly-line */
  45.                 gleDouble point_array[][3],        /* polyline */
  46.                 float color_array[][3],        /* color of polyline */
  47.                 gleDouble xform_array[][2][3])   /* 2D contour xforms */
  48. {   
  49.    INIT_GC();
  50.    _gle_gc -> ncp = ncp;
  51.    _gle_gc -> contour = contour;
  52.    _gle_gc -> cont_normal = cont_normal;
  53.    _gle_gc -> up = up;
  54.    _gle_gc -> npoints = npoints;
  55.    _gle_gc -> point_array = point_array;
  56.    _gle_gc -> color_array = color_array;
  57.    _gle_gc -> xform_array = xform_array;
  58.    switch (__TUBE_STYLE) {
  59.       case TUBE_JN_RAW:
  60.          (void) extrusion_raw_join (ncp, contour, cont_normal, up,
  61.                                     npoints,
  62.                                     point_array, color_array,
  63.                                     xform_array);
  64.          break;
  65.       case TUBE_JN_ANGLE:
  66.          (void) extrusion_angle_join (ncp, contour, cont_normal, up,
  67.                                     npoints,
  68.                                     point_array, color_array,
  69.                                     xform_array);
  70.          break;
  71.       case TUBE_JN_CUT:
  72.       case TUBE_JN_ROUND:
  73.          /* This routine used for both cut and round styles */
  74.          (void) extrusion_round_or_cut_join (ncp, contour, cont_normal, up,
  75.                                     npoints,
  76.                                     point_array, color_array,
  77.                                     xform_array);
  78.          break;
  79.       default:
  80.          break;
  81.    }
  82. }
  83. /* ============================================================ */
  84. void gleExtrusion (int ncp,               /* number of contour points */
  85.                 gleDouble contour[][2],    /* 2D contour */
  86.                 gleDouble cont_normal[][2], /* 2D contour normals */
  87.                 gleDouble up[3],           /* up vector for contour */
  88.                 int npoints,           /* numpoints in poly-line */
  89.                 gleDouble point_array[][3],        /* polyline */
  90.                 float color_array[][3])        /* color of polyline */
  91. {   
  92.    gleSuperExtrusion (ncp, contour, cont_normal, up,
  93.                     npoints,
  94.                     point_array, color_array,
  95.                     NULL);
  96. }
  97. /* ============================================================ */
  98. /* should really make this an adaptive algorithm ... */
  99. static int __gleSlices = 20;
  100. int
  101. gleGetNumSlices(void)
  102. {
  103.   return __gleSlices;
  104. }
  105. void
  106. gleSetNumSlices(int slices)
  107. {
  108.   __gleSlices = slices;
  109. }
  110. void gen_polycone (int npoints,
  111.                gleDouble point_array[][3],
  112.                float color_array[][3],
  113.                gleDouble radius,
  114.                gleDouble xform_array[][2][3])
  115. {
  116.    int saved_style;
  117.    glePoint *circle = (glePoint*) malloc(sizeof(glePoint)*2*__gleSlices);
  118.    glePoint *norm = &circle[__gleSlices];
  119.    double c, s;
  120.    int i;
  121.    double v21[3];
  122.    double len;
  123.    gleDouble up[3];
  124.    INIT_GC();
  125.    /* this if statement forces this routine into double-duty for
  126.     * both the polycone and the polycylinder routines */
  127.    if (xform_array != NULL) radius = 1.0;
  128.    s = sin (2.0*M_PI/ ((double) __gleSlices));
  129.    c = cos (2.0*M_PI/ ((double) __gleSlices));
  130.    norm [0][0] = 1.0;
  131.    norm [0][1] = 0.0;
  132.    circle [0][0] = radius;
  133.    circle [0][1] = 0.0;
  134.    /* draw a norm using recursion relations */
  135.    for (i=1; i<__gleSlices; i++) {
  136.       norm [i][0] = norm[i-1][0] * c - norm[i-1][1] * s;
  137.       norm [i][1] = norm[i-1][0] * s + norm[i-1][1] * c;
  138.       circle [i][0] = radius * norm[i][0];
  139.       circle [i][1] = radius * norm[i][1];
  140.    }
  141.    /* avoid degenerate vectors */
  142.    /* first, find a non-zero length segment */
  143.    i=0;
  144.    FIND_NON_DEGENERATE_POINT(i,npoints,len,v21,point_array)
  145.    if (i == npoints) return;
  146.    /* next, check to see if this segment lies along x-axis */
  147.    if ((v21[0] == 0.0) && (v21[2] == 0.0)) {
  148.       up[0] = up[1] = up[2] = 1.0;
  149.    } else {
  150.       up[0] = up[2] = 0.0;
  151.       up[1] = 1.0;
  152.    }
  153.    /* save the current join style */
  154.    saved_style = extrusion_join_style;
  155.    extrusion_join_style |= TUBE_CONTOUR_CLOSED;
  156.    /* if lighting is not turned on, don't send normals.  
  157.     * MMODE is a good indicator of whether lighting is active */
  158.    if (!__IS_LIGHTING_ON) {
  159.        gleSuperExtrusion (__gleSlices, circle, NULL, up,
  160.                      npoints, point_array, color_array,
  161.                      xform_array);
  162.    } else {
  163.        gleSuperExtrusion (__gleSlices, circle, norm, up,
  164.                      npoints, point_array, color_array,
  165.                      xform_array);
  166.    }
  167.    
  168.    /* restore the join style */
  169.    extrusion_join_style = saved_style;
  170.    free(circle);
  171. }
  172. /* ============================================================ */
  173. void glePolyCylinder (int npoints,
  174.                    gleDouble point_array[][3],
  175.                    float color_array[][3],
  176.                    gleDouble radius)
  177. {
  178.    gen_polycone (npoints, point_array, color_array, radius, NULL);
  179. }
  180. /* ============================================================ */
  181. void glePolyCone (int npoints,
  182.                gleDouble point_array[][3],
  183.                float color_array[][3],
  184.                gleDouble radius_array[])
  185. {
  186.    gleAffine * xforms;
  187.    int j;
  188.    /* build 2D affine matrices from radius array */
  189.    xforms = (gleAffine *) malloc (npoints * sizeof(gleAffine));
  190.    for (j=0; j<npoints; j++) {
  191.       AVAL(xforms,j,0,0) = radius_array[j];
  192.       AVAL(xforms,j,0,1) = 0.0;
  193.       AVAL(xforms,j,0,2) = 0.0;
  194.       AVAL(xforms,j,1,0) = 0.0;
  195.       AVAL(xforms,j,1,1) = radius_array[j];
  196.       AVAL(xforms,j,1,2) = 0.0;
  197.    }
  198.    gen_polycone (npoints, point_array, color_array, 1.0, xforms);
  199.    free (xforms);
  200. }
  201. /* ============================================================ */
  202. void gleTwistExtrusion (int ncp,         /* number of contour points */
  203.                 gleDouble contour[][2],    /* 2D contour */
  204.                 gleDouble cont_normal[][2], /* 2D contour normals */
  205.                 gleDouble up[3],           /* up vector for contour */
  206.                 int npoints,           /* numpoints in poly-line */
  207.                 gleDouble point_array[][3],        /* polyline */
  208.                 float color_array[][3],        /* color of polyline */
  209.                 gleDouble twist_array[])   /* countour twists (in degrees) */
  210. {
  211.    int j;
  212.    double angle;
  213.    double si, co;
  214.    gleAffine *xforms;
  215.    /* build 2D affine matrices from radius array */
  216.    xforms = (gleAffine *) malloc (npoints * sizeof(gleAffine));
  217.    for (j=0; j<npoints; j++) {
  218.       angle = (M_PI/180.0) * twist_array[j];
  219.       si = sin (angle);
  220.       co = cos (angle);
  221.       AVAL(xforms,j,0,0) = co;
  222.       AVAL(xforms,j,0,1) = -si;
  223.       AVAL(xforms,j,0,2) = 0.0;
  224.       AVAL(xforms,j,1,0) = si;
  225.       AVAL(xforms,j,1,1) = co;
  226.       AVAL(xforms,j,1,2) = 0.0;
  227.    }
  228.    gleSuperExtrusion (ncp,               /* number of contour points */
  229.                 contour,    /* 2D contour */
  230.                 cont_normal, /* 2D contour normals */
  231.                 up,           /* up vector for contour */
  232.                 npoints,           /* numpoints in poly-line */
  233.                 point_array,        /* polyline */
  234.                 color_array,        /* color of polyline */
  235.                 xforms);
  236.    free (xforms);
  237. }
  238. /* ============================================================ */
  239. /* 
  240.  * The spiral primitive forms the basis for the helicoid primitive.
  241.  *
  242.  * Note that this primitive sweeps a contour along a helical path.
  243.  * The algorithm assumes that the path is embedded in Euclidean space,
  244.  * and uses parallel transport along the path.  Parallel transport
  245.  * provides the simplest mathematical model for moving a coordinate 
  246.  * system along a curved path, but some of the effects of doing so 
  247.  * may prove to be surprising to one uninitiated to the concept.
  248.  *
  249.  * Thus, we provide another, related, algorithm below, called "lathe"
  250.  * which introduces a torsion component along the path, correcting for
  251.  * the rotation induced by the helical path.
  252.  *
  253.  * If the above sounds like gobldy-gook to you, you may want to brush 
  254.  * up on differential geometry. Recommend Spivak, Differential Geometry,
  255.  * Volume 1, pages xx-xx.
  256.  */
  257. void gleSpiral (int ncp,               /* number of contour points */
  258.              gleDouble contour[][2],    /* 2D contour */
  259.              gleDouble cont_normal[][2], /* 2D contour normals */
  260.              gleDouble up[3],           /* up vector for contour */
  261.              gleDouble startRadius,
  262.              gleDouble drdTheta,        /* change in radius per revolution */
  263.              gleDouble startZ,
  264.              gleDouble dzdTheta,        /* change in Z per revolution */
  265.              gleDouble startXform[2][3],
  266.              gleDouble dXformdTheta[2][3], /* tangent change xform per revolution */
  267.              gleDouble startTheta,       /* start angle, in degrees */
  268.              gleDouble sweepTheta)        /* sweep angle, in degrees */
  269. {
  270.    int npoints;
  271.    gleDouble deltaAngle;
  272.    char * mem_anchor;
  273.    gleDouble *pts;
  274.    gleAffine *xforms;
  275.    double delta;
  276.    int saved_style;
  277.    double ccurr, scurr;
  278.    double cprev, sprev;
  279.    double cdelta, sdelta;
  280.    double mA[2][2], mB[2][2];
  281.    double run[2][2];
  282.    double deltaTrans[2];
  283.    double trans[2];
  284.    int i;
  285.    /* allocate sufficient memory to store path */
  286.    npoints = (int) ((((double) __gleSlices) /360.0) * fabs(sweepTheta)) + 4;
  287.    if (startXform == NULL) {
  288.       mem_anchor = malloc (3*npoints * sizeof (gleDouble));
  289.       pts = (gleDouble *) mem_anchor;
  290.       xforms = NULL;
  291.    } else {
  292.       mem_anchor = malloc ((1+2)* 3*npoints * sizeof (gleDouble));
  293.       pts = (gleDouble *) mem_anchor;
  294.       xforms = (gleAffine *) (pts + 3*npoints);
  295.    }
  296.    /* compute delta angle based on number of points */
  297.    deltaAngle = (M_PI / 180.0) * sweepTheta / ((gleDouble) (npoints-3));
  298.    startTheta *= M_PI / 180.0;
  299.    startTheta -= deltaAngle;
  300.    /* initialize factors */
  301.    cprev = cos ((double) startTheta);
  302.    sprev = sin ((double) startTheta);
  303.    cdelta = cos ((double) deltaAngle);
  304.    sdelta = sin ((double) deltaAngle);
  305.    /* renormalize differential factors */
  306.    delta = deltaAngle / (2.0 * M_PI);
  307.    dzdTheta *= delta;
  308.    drdTheta *= delta;
  309.    /* remember, the first point is hidden, so back-step */
  310.    startZ -=  dzdTheta;
  311.    startRadius -=  drdTheta;
  312.    /* draw spiral path using recursion relations for sine, cosine */
  313.    for (i=0; i<npoints; i++) {
  314.       pts [3*i] =  startRadius * cprev;
  315.       pts [3*i+1] =  startRadius * sprev;
  316.       pts [3*i+2] = (gleDouble) startZ;
  317.       startZ +=  dzdTheta;
  318.       startRadius +=  drdTheta;
  319.       ccurr = cprev * cdelta - sprev * sdelta;
  320.       scurr = cprev * sdelta + sprev * cdelta;
  321.       cprev = ccurr;
  322.       sprev = scurr;
  323.    }
  324.    /* If there is a deformation matrix specified, then a deformation
  325.     * path must be generated also */
  326.    if (startXform != NULL) {
  327.       if (dXformdTheta == NULL) {
  328.          for (i=0; i<npoints; i++) {
  329.             xforms[i][0][0] = startXform[0][0];
  330.             xforms[i][0][1] = startXform[0][1];
  331.             xforms[i][0][2] = startXform[0][2];
  332.             xforms[i][1][0] = startXform[1][0];
  333.             xforms[i][1][1] = startXform[1][1];
  334.             xforms[i][1][2] = startXform[1][2];
  335.          }
  336.       } else {
  337.          /* 
  338.           * if there is a differential matrix specified, treat it a 
  339.           * a tangent (algebraic, infinitessimal) matrix.  We need to
  340.           * project it into the group of real 2x2 matricies.  (Note that
  341.           * the specified matrix is affine.  We treat the translation 
  342.           * components linearly, and only treat the 2x2 submatrix as an 
  343.           * algebraic tangenet).
  344.           *
  345.           * For exponentiaition, we use the well known approx:
  346.           * exp(x) = lim (N->inf) (1+x/N) ** N
  347.           * and take N=32. 
  348.           */
  349.          /* initialize translation and delta translation */
  350.          deltaTrans[0] = delta * dXformdTheta[0][2];
  351.          deltaTrans[1] = delta * dXformdTheta[1][2];
  352.          trans[0] = startXform[0][2];
  353.          trans[1] = startXform[1][2];
  354.    
  355.          /* prepare the tangent matrix */
  356.          delta /= 32.0;
  357.          mA[0][0] = 1.0 + delta * dXformdTheta[0][0];
  358.          mA[0][1] = delta * dXformdTheta[0][1];
  359.          mA[1][0] = delta * dXformdTheta[1][0];
  360.          mA[1][1] = 1.0 + delta * dXformdTheta[1][1];
  361.    
  362.          /* compute exponential of matrix */
  363.          MATRIX_PRODUCT_2X2 (mB, mA, mA);  /* squared */
  364.          MATRIX_PRODUCT_2X2 (mA, mB, mB);  /* 4th power */
  365.          MATRIX_PRODUCT_2X2 (mB, mA, mA);  /* 8th power */
  366.          MATRIX_PRODUCT_2X2 (mA, mB, mB);  /* 16th power */
  367.          MATRIX_PRODUCT_2X2 (mB, mA, mA);  /* 32nd power */
  368.    
  369.          /* initialize running matrix */
  370.          COPY_MATRIX_2X2 (run, startXform);
  371.    
  372.          /* remember, the first point is hidden -- load some, any 
  373.           * xform for the first point */
  374.          xforms[0][0][0] = startXform[0][0];
  375.          xforms[0][0][1] = startXform[0][1];
  376.          xforms[0][0][2] = startXform[0][2];
  377.          xforms[0][1][0] = startXform[1][0];
  378.          xforms[0][1][1] = startXform[1][1];
  379.          xforms[0][1][2] = startXform[1][2];
  380.          for (i=1; i<npoints; i++) {
  381. #ifdef FUNKY_C
  382.             xforms[6*i] = run[0][0];
  383.             xforms[6*i+1] = run[0][1];
  384.             xforms[6*i+3] = run[1][0];
  385.             xforms[6*i+4] = run[1][1];
  386. #endif /* FUNKY_C */
  387.             xforms[i][0][0] = run[0][0];
  388.             xforms[i][0][1] = run[0][1];
  389.             xforms[i][1][0] = run[1][0];
  390.             xforms[i][1][1] = run[1][1];
  391.             /* integrate to get exponential matrix */
  392.             /* (Note that the group action is a left-action --
  393.              * i.e. multiply on the left (not the right)) */
  394.             MATRIX_PRODUCT_2X2 (mA, mB, run);
  395.             COPY_MATRIX_2X2 (run, mA);
  396.          
  397. #ifdef FUNKY_C
  398.             xforms[6*i+2] = trans [0];
  399.             xforms[6*i+5] = trans [1];
  400. #endif /* FUNKY_C */
  401.             xforms[i][0][2] = trans [0];
  402.             xforms[i][1][2] = trans [1];
  403.             trans[0] += deltaTrans[0];
  404.             trans[1] += deltaTrans[1];
  405.          }
  406.       }
  407.    }
  408.    /* save the current join style */
  409.    saved_style = extrusion_join_style;
  410.    /* Allow only angle joins (for performance reasons).
  411.     * The idea is that if the tesselation is fine enough, then an angle
  412.     * join should be sufficient to get the desired visual quality.  A 
  413.     * raw join would look terrible, an cut join would leave garbage 
  414.     * everywhere, and a round join will over-tesselate (and thus 
  415.     * should be avoided for performance reasons). 
  416.     */
  417.    extrusion_join_style  &= ~TUBE_JN_MASK; 
  418.    extrusion_join_style  |= TUBE_JN_ANGLE;
  419.    gleSuperExtrusion (ncp, contour, cont_normal, up,
  420.                   npoints, (gleVector *) pts, NULL, xforms);
  421.    /* restore the join style */
  422.    extrusion_join_style = saved_style;
  423.    free (mem_anchor);
  424. }
  425. /* ============================================================ */
  426. /* 
  427.  */
  428. void gleLathe (int ncp,               /* number of contour points */
  429.              gleDouble contour[][2],    /* 2D contour */
  430.              gleDouble cont_normal[][2], /* 2D contour normals */
  431.              gleDouble up[3],           /* up vector for contour */
  432.              gleDouble startRadius,
  433.              gleDouble drdTheta,        /* change in radius per revolution */
  434.              gleDouble startZ,
  435.              gleDouble dzdTheta,        /* change in Z per revolution */
  436.              gleDouble startXform[2][3],
  437.              gleDouble dXformdTheta[2][3], /* tangent change xform per revln */
  438.              gleDouble startTheta,       /* start angle, in degrees */
  439.              gleDouble sweepTheta)        /* sweep angle, in degrees */
  440. {
  441.    gleDouble localup[3];
  442.    gleDouble len;
  443.    gleDouble trans[2];
  444.    gleDouble start[2][3], delt[2][3];
  445.    /* Because the spiral always starts on the axis, and proceeds in the
  446.     * positive y direction, we can see that valid up-vectors must lie 
  447.     * in the x-z plane. Therefore, we make sure we have a valid up
  448.     * vector by projecting it onto the x-z plane, and normalizing. */
  449.    if (up[1] != 0.0) {
  450.       localup[0] = up[0];
  451.       localup[1] = 0.0;
  452.       localup[2] = up[2];
  453.       VEC_LENGTH (len, localup);
  454.       if (len != 0.0) {
  455.          len = 1.0/len;
  456.          localup[0] *= len;
  457.          localup[2] *= len;
  458.          VEC_SCALE (localup, len, localup);
  459.       } else {
  460.          /* invalid up vector was passed in */
  461.          localup[0] = 0.0;
  462.          localup[2] = 1.0;
  463.       }
  464.    } else {
  465.       VEC_COPY (localup, up);
  466.    }
  467.    /* the dzdtheta derivative and the drdtheta derivative form a vector
  468.     * in the x-z plane.  dzdtheta is the z component, and drdtheta is 
  469.     * the x component.  We need to convert this vector into the local 
  470.     * coordinate system defined by the up vector.  We do this by 
  471.     * applying a 2D rotation matrix. 
  472.     */
  473.    trans[0] = localup[2] * drdTheta - localup[0] * dzdTheta;
  474.    trans[1] = localup[0] * drdTheta + localup[2] * dzdTheta;
  475.    /* now, add this translation vector into the affine xform */
  476.    if (startXform != NULL) {
  477.       if (dXformdTheta != NULL) {
  478.          COPY_MATRIX_2X3 (delt, dXformdTheta);
  479.          delt[0][2] += trans[0];
  480.          delt[1][2] += trans[1];
  481.       } else {
  482.          /*Hmm- the transforms don't exist */
  483.          delt[0][0] = 0.0;
  484.          delt[0][1] = 0.0;
  485.          delt[0][2] = trans[0];
  486.          delt[1][0] = 0.0;
  487.          delt[1][1] = 0.0;
  488.          delt[1][2] = trans[1];
  489.       }
  490.       gleSpiral (ncp, contour, cont_normal, up, 
  491.               startRadius, 0.0, startZ, 0.0,
  492.               startXform, delt,
  493.               startTheta, sweepTheta);
  494.    } else {
  495.       /* Hmm- the transforms don't exist */
  496.       start[0][0] = 1.0;
  497.       start[0][1] = 0.0;
  498.       start[0][2] = 0.0;
  499.       start[1][0] = 0.0;
  500.       start[1][1] = 1.0;
  501.       start[1][2] = 0.0;
  502.       delt[0][0] = 0.0;
  503.       delt[0][1] = 0.0;
  504.       delt[0][2] = trans[0];
  505.       delt[1][0] = 0.0;
  506.       delt[1][1] = 0.0;
  507.       delt[1][2] = trans[1];
  508.       gleSpiral (ncp, contour, cont_normal, up, 
  509.               startRadius, 0.0, startZ, 0.0,
  510.               start, delt,
  511.               startTheta, sweepTheta);
  512.    }
  513. }
  514. /* ============================================================ */
  515. /*
  516.  * Super-Helicoid primitive 
  517.  */
  518. typedef void (*HelixCallback) (
  519.              int ncp,               
  520.              gleDouble contour[][2],
  521.              gleDouble cont_normal[][2],
  522.              gleDouble up[3],
  523.              gleDouble startRadius,
  524.              gleDouble drdTheta,
  525.              gleDouble startZ,
  526.              gleDouble dzdTheta,
  527.              gleDouble startXform[2][3],
  528.              gleDouble dXformdTheta[2][3],
  529.              gleDouble startTheta,
  530.              gleDouble sweepTheta);
  531. void super_helix (gleDouble rToroid,
  532.              gleDouble startRadius,
  533.              gleDouble drdTheta,        /* change in radius per revolution */
  534.              gleDouble startZ,
  535.              gleDouble dzdTheta,        /* change in Z per revolution */
  536.              gleDouble startXform[2][3],
  537.              gleDouble dXformdTheta[2][3], /* tangent change xform per revol */
  538.              gleDouble startTheta,       /* start angle, in degrees */
  539.              gleDouble sweepTheta,        /* sweep angle, in degrees */
  540.      HelixCallback helix_callback)
  541. {
  542.    int saved_style;
  543.    glePoint *circle = (glePoint*) malloc(sizeof(glePoint)*2*__gleSlices);
  544.    glePoint *norm = &circle[__gleSlices];
  545.    double c, s;
  546.    int i;
  547.    gleDouble up[3];
  548.    /* initialize sine and cosine for circle recusrion equations */
  549.    s = sin (2.0*M_PI/ ((double) __gleSlices));
  550.    c = cos (2.0*M_PI/ ((double) __gleSlices));
  551.    norm [0][0] = 1.0;
  552.    norm [0][1] = 0.0;
  553.    circle [0][0] = rToroid;
  554.    circle [0][1] = 0.0;
  555.    /* draw a norm using recursion relations */
  556.    for (i=1; i<__gleSlices; i++) {
  557.       norm [i][0] = norm[i-1][0] * c - norm[i-1][1] * s;
  558.       norm [i][1] = norm[i-1][0] * s + norm[i-1][1] * c;
  559.       circle [i][0] = rToroid * norm[i][0];
  560.       circle [i][1] = rToroid * norm[i][1];
  561.    }
  562.    /* make up vector point along x axis */
  563.    up[1] = up[2] = 0.0;
  564.    up[0] = 1.0;
  565.    /* save the current join style */
  566.    saved_style = extrusion_join_style;
  567.    extrusion_join_style |= TUBE_CONTOUR_CLOSED;
  568.    extrusion_join_style |= TUBE_NORM_PATH_EDGE;
  569.    /* if lighting is not turned on, don't send normals.  
  570.     * MMODE is a good indicator of whether lighting is active */
  571.    if (!__IS_LIGHTING_ON) {
  572.       (*helix_callback) (__gleSlices, circle, NULL, up,
  573.              startRadius,
  574.              drdTheta,
  575.              startZ,
  576.              dzdTheta,
  577.              startXform,
  578.              dXformdTheta,
  579.              startTheta,
  580.              sweepTheta);
  581.    } else {
  582.       (*helix_callback) (__gleSlices, circle, norm, up,
  583.              startRadius,
  584.              drdTheta,
  585.              startZ,
  586.              dzdTheta,
  587.              startXform,
  588.              dXformdTheta,
  589.              startTheta,
  590.              sweepTheta);
  591.    }
  592.    
  593.    /* restore the join style */
  594.    extrusion_join_style = saved_style;
  595.    free(circle);
  596. }
  597. /* ============================================================ */
  598. /*
  599.  * Helicoid primitive 
  600.  * Uses Parallel Transport to take a circular contour along a helical
  601.  * path.
  602.  */
  603. void gleHelicoid (gleDouble rToroid,
  604.              gleDouble startRadius,
  605.              gleDouble drdTheta,        /* change in radius per revolution */
  606.              gleDouble startZ,
  607.              gleDouble dzdTheta,        /* change in Z per revolution */
  608.              gleDouble startXform[2][3],
  609.              gleDouble dXformdTheta[2][3], /* tangent change xform per revol */
  610.              gleDouble startTheta,       /* start angle, in degrees */
  611.              gleDouble sweepTheta)        /* sweep angle, in degrees */
  612. {
  613.    super_helix (rToroid,
  614.              startRadius,
  615.              drdTheta,        /* change in radius per revolution */
  616.              startZ,
  617.              dzdTheta,        /* change in Z per revolution */
  618.              startXform,
  619.              dXformdTheta, /* tangent change xform per revolution */
  620.              startTheta,       /* start angle, in degrees */
  621.              sweepTheta,       /* sweep angle, in degrees */
  622.              gleSpiral);
  623. }
  624. /* ============================================================ */
  625. /*
  626.  * Toroid primitive 
  627.  * Uses a helical coordinate system dislocation to take a circular 
  628.  * contour along a helical path.
  629.  */
  630. void gleToroid (gleDouble rToroid,
  631.              gleDouble startRadius,
  632.              gleDouble drdTheta,        /* change in radius per revolution */
  633.              gleDouble startZ,
  634.              gleDouble dzdTheta,        /* change in Z per revolution */
  635.              gleDouble startXform[2][3],
  636.              gleDouble dXformdTheta[2][3], /* tangent change xform per revol */
  637.              gleDouble startTheta,       /* start angle, in degrees */
  638.              gleDouble sweepTheta)        /* sweep angle, in degrees */
  639. {
  640.    super_helix (rToroid,
  641.              startRadius,
  642.              drdTheta,        /* change in radius per revolution */
  643.              startZ,
  644.              dzdTheta,        /* change in Z per revolution */
  645.              startXform,
  646.              dXformdTheta, /* tangent change xform per revolution */
  647.              startTheta,       /* start angle, in degrees */
  648.              sweepTheta,       /* sweep angle, in degrees */
  649.              gleLathe);
  650. }
  651. /* ============================================================ */
  652. void gleScrew (int ncp, 
  653.                gleDouble contour[][2], 
  654.                gleDouble cont_normal[][2], 
  655.                gleDouble up[3],
  656.                gleDouble startz,
  657.                gleDouble endz,
  658.                gleDouble twist) 
  659. {
  660.    int i, numsegs;
  661.    gleVector * path; 
  662.    gleDouble *twarr;
  663.    gleDouble currz, delta; 
  664.    gleDouble currang, delang; 
  665.    /* no segment should rotate more than 18 degrees */
  666.    numsegs = (int) fabs (twist / 18.0) + 4;
  667.    /* malloc the extrusion array and the twist array */
  668.    path = (gleVector *) malloc (numsegs * sizeof (gleVector));
  669.    twarr = (gleDouble *) malloc (numsegs * sizeof (gleDouble));
  670.    /* fill in the extrusion array and the twist array uniformly */
  671.    delta = (endz-startz) / ((gleDouble) (numsegs-3));
  672.    currz = startz-delta;
  673.    delang = twist / ((gleDouble) (numsegs-3));
  674.    currang = -delang;
  675.    for (i=0; i<numsegs; i++) {
  676.       path [i][0] = 0.0;
  677.       path [i][1] = 0.0;
  678.       path [i][2] = currz;
  679.       currz += delta;
  680.       twarr[i] = currang;
  681.       currang +=delang;
  682.    }
  683.    gleTwistExtrusion (ncp, contour, cont_normal, up, numsegs, path, NULL, twarr);
  684.    free (path);
  685.    free (twarr);
  686. }
  687. /* ============================================================ */