home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / GRAPHICS / rayshade.lzh / cylinder.c < prev    next >
Text File  |  1990-05-08  |  6KB  |  252 lines

  1. /*
  2.  * cylinder.c
  3.  *
  4.  * Copyright (C) 1989, Craig E. Kolb
  5.  *
  6.  * This software may be freely copied, modified, and redistributed,
  7.  * provided that this copyright notice is preserved on all copies.
  8.  *
  9.  * There is no warranty or other guarantee of fitness for this software,
  10.  * it is provided solely .  Bug reports or fixes may be sent
  11.  * to the author, who may or may not act on them as he desires.
  12.  *
  13.  * You may not include this software in a program or other software product
  14.  * without supplying the source, or without informing the end-user that the
  15.  * source is available for no extra charge.
  16.  *
  17.  * If you modify this software, you should include a notice giving the
  18.  * name of the person performing the modification, the date of modification,
  19.  * and the reason for such modification.
  20.  *
  21.  * $Id: cylinder.c,v 3.0.1.5 90/04/09 14:29:43 craig Exp $
  22.  *
  23.  * $Log:    cylinder.c,v $
  24.  * Revision 3.0.1.5  90/04/09  14:29:43  craig
  25.  * patch5: Transformation information now stored locally.
  26.  * patch5: Canonical cylinder now truly canonical.
  27.  * 
  28.  * Revision 3.0.1.4  90/03/07  22:43:04  craig
  29.  * patch4: Fixed typo in previous fix.
  30.  * 
  31.  * Revision 3.0.1.3  90/02/12  13:27:30  craig
  32.  * patch4: Changes to avoid rotation about null axis.
  33.  * 
  34.  * Revision 3.0.1.2  89/12/06  16:33:41  craig
  35.  * patch2: Added calls to new error/warning routines.
  36.  * 
  37.  * Revision 3.0.1.1  89/11/18  14:07:52  craig
  38.  * patch1: Changes to reflect new names of transformation routines.
  39.  * 
  40.  * Revision 3.0  89/10/27  02:05:48  craig
  41.  * Baseline for first official release.
  42.  * 
  43.  */
  44. #include <stdio.h>
  45. #include <math.h>
  46. #include "typedefs.h"
  47. #include "funcdefs.h"
  48. #include "constants.h"
  49.  
  50. Object *
  51. makcyl(surf, cent, ax, r)
  52. char *surf;
  53. Vector *cent, *ax;
  54. double r;
  55. {
  56.     Cylinder *cyl;
  57.     Primitive *prim;
  58.     Object *newobj;
  59.     double len;
  60.     Vector axis, dir;
  61.  
  62.     if (r <= 0.) {
  63.         yywarning("Invalid cylinder radius.\n");
  64.         return (Object *)0;
  65.     }
  66.  
  67.     prim = mallocprim();
  68.     newobj = new_object(NULL, CYL, (char *)prim, (Trans *)NULL);
  69.     prim->surf = find_surface(surf);
  70.     prim->type = CYL;
  71.     cyl = (Cylinder *)Malloc(sizeof(Cylinder));
  72.     prim->objpnt.p_cylinder = cyl;
  73.  
  74.     axis.x = ax->x - cent->x;
  75.     axis.y = ax->y - cent->y;
  76.     axis.z = ax->z - cent->z;
  77.  
  78.     len = normalize(&axis);
  79.     if(len < EPSILON) {
  80.         yywarning("Degenerate cylinder.\n");
  81.         free((char *)cyl);
  82.         free((char *)prim);
  83.         return (Object *)0;
  84.     }
  85.  
  86.     /*
  87.      * Define matrix to transform from Z axis aligned unit cylinder
  88.      * to desired cylinder.
  89.      */
  90.     if (abs(axis.z) == 1.) {
  91.         dir.x = 1.;
  92.         dir.y = dir.z = 0.;
  93.     } else {
  94.         dir.x = axis.y;
  95.         dir.y = -axis.x;
  96.         dir.z = 0.;
  97.     }
  98.     init_trans(&cyl->trans.obj2world);
  99.     RS_scale(&cyl->trans.obj2world, r, r, len);
  100.     RS_rotate(&cyl->trans.obj2world, &dir, acos(axis.z));
  101.     RS_translate(&cyl->trans.obj2world, cent);
  102.     invert_trans(&cyl->trans.world2obj, &cyl->trans.obj2world);
  103.     return newobj;
  104. }
  105.  
  106. /*
  107.  * Ray-cylinder intersection test.
  108.  */
  109. double
  110. intcyl(pos, ray, obj)
  111. Vector           *pos, *ray;
  112. Primitive       *obj;
  113. {
  114.     double t1, t2, a, b, c, zpos1, zpos2, et1, et2, x, y, disc;
  115.     double distfact;
  116.     extern unsigned long primtests[];
  117.     extern double TransformRay();
  118.     Ray newray;
  119.     Vector nray, npos;
  120.     Cylinder *cyl;
  121.  
  122.     primtests[CYL]++;
  123.     cyl = obj->objpnt.p_cylinder;
  124.  
  125.     /*
  126.      * Transform ray into canonical cylinder space.
  127.      */
  128.     newray.dir = *ray;
  129.     newray.pos = *pos;
  130.     distfact = TransformRay(&newray, &cyl->trans.world2obj);
  131.     nray = newray.dir;
  132.     npos = newray.pos;
  133.  
  134.     a = nray.x * nray.x + nray.y * nray.y;
  135.     c = npos.x*npos.x + npos.y*npos.y - 1;
  136.  
  137.     if (a < EPSILON*EPSILON) {    /* |nray.z| == 1. */
  138.         if(c < EPSILON*EPSILON)    /* Within endcap */
  139.             /* Wrong if origin is inside cylinder. */
  140.             return min(-npos.z / nray.z,
  141.                   (1. - npos.z) / nray.z) / distfact;
  142.         return 0.;
  143.     }
  144.  
  145.     b = nray.x * npos.x + nray.y * npos.y;
  146.     disc = b*b - a*c;
  147.     if(disc < 0.)
  148.         return 0.;
  149.     disc = sqrt(disc);
  150.     t1 = (-b + disc) / a;
  151.     t2 = (-b - disc) / a;
  152.     if(t1 < EPSILON && t2 < EPSILON)
  153.         return 0.;
  154.     zpos1 = npos.z + t1 * nray.z;
  155.     zpos2 = npos.z + t2 * nray.z;
  156.     if ((zpos1 > 1 && zpos2 > 1) ||
  157.         (zpos1 < 0. && zpos2 < 0.))
  158.         return 0.;
  159.     if (t1 < EPSILON)
  160.         t1 = FAR_AWAY;
  161.     if (t2 < EPSILON)
  162.         t2 = FAR_AWAY;
  163.     /*
  164.      * Don't bother checking endcaps if both intersection points
  165.      * are on the cylinder.
  166.      */
  167.     if ((zpos1 > 0. && zpos1 < 1. && zpos2 > 0. && zpos2 < 1.))
  168.         return min(t1, t2) / distfact;
  169.     /*
  170.       * It's possible to get rid of the ray-disc intersection tests
  171.      * (by looking at t1, t2 and zpos1, zpos), but the code gets messy.
  172.      */
  173.     if (zpos1 < 0. || zpos1 > 1.)
  174.         t1 = FAR_AWAY;
  175.     if (zpos2 < 0. || zpos2 > 1.)
  176.         t2 = FAR_AWAY;
  177.     et1 = -npos.z / nray.z;
  178.     x = npos.x + et1 * nray.x;
  179.     y = npos.y + et1 * nray.y;
  180.     if (x*x + y*y > 1.)
  181.         et1 = FAR_AWAY;
  182.     et2 = (1. - npos.z) / nray.z;
  183.     x = npos.x + et2 * nray.x;
  184.     y = npos.y + et2 * nray.y;
  185.     if (x*x + y*y > 1.)
  186.         et2 = FAR_AWAY;
  187.     t1 = min(t1, min(t2, min(et1, et2)));
  188.     return (t1 == FAR_AWAY ? 0. : t1 / distfact);
  189. }
  190.  
  191. nrmcyl(pos, obj, nrm)
  192. Vector *pos, *nrm;
  193. Primitive *obj;
  194. {
  195.     Cylinder *cyl;
  196.     Vector npos;
  197.     double dist;
  198.  
  199.     cyl = obj->objpnt.p_cylinder;
  200.  
  201.     /*
  202.      * Transform position into cylinder space.
  203.      */
  204.     npos = *pos;
  205.     transform_point(&npos, &cyl->trans.world2obj);
  206.  
  207.     dist = npos.x*npos.x + npos.y*npos.y;
  208.     if (dist+EPSILON < 1) {
  209.         if (equal(npos.z,0.)) {
  210.             /*
  211.              * Hit on lower endcap.
  212.              */
  213.             nrm->x = nrm->y = 0.;
  214.             nrm->z = -1.;
  215.         } else {
  216.             /*
  217.              * Hit on upper endcap.
  218.              */
  219.             nrm->x = nrm->y = 0.;
  220.             nrm->z = 1.;
  221.         }
  222.     } else {    /* Hit along cylinder. */
  223.         nrm->x = npos.x;
  224.         nrm->y = npos.y;
  225.         nrm->z = 0.;
  226.         /* Will be normalized by ShadeRay(). */
  227.     }
  228.  
  229.     /*
  230.      * Tranform normal back to world space.
  231.      */
  232.     TransformNormal(nrm, &cyl->trans.world2obj);
  233. }
  234.  
  235. cylextent(o, bounds)
  236. Primitive *o;
  237. double bounds[2][3];
  238. {
  239.     Cylinder *cyl;
  240.  
  241.     cyl = o->objpnt.p_cylinder;
  242.  
  243.     bounds[LOW][X] = bounds[LOW][Y] = -1;
  244.     bounds[HIGH][X] = bounds[HIGH][Y] = 1;
  245.     bounds[LOW][Z] = 0.;
  246.     bounds[HIGH][Z] = 1;
  247.     /*
  248.      * Transform bounding box to world space.
  249.      */
  250.     transform_bounds(&cyl->trans.obj2world, bounds);
  251. }
  252.