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 >
Wrap
Text File
|
1990-05-08
|
6KB
|
252 lines
/*
* cylinder.c
*
* Copyright (C) 1989, Craig E. Kolb
*
* This software may be freely copied, modified, and redistributed,
* provided that this copyright notice is preserved on all copies.
*
* There is no warranty or other guarantee of fitness for this software,
* it is provided solely . Bug reports or fixes may be sent
* to the author, who may or may not act on them as he desires.
*
* You may not include this software in a program or other software product
* without supplying the source, or without informing the end-user that the
* source is available for no extra charge.
*
* If you modify this software, you should include a notice giving the
* name of the person performing the modification, the date of modification,
* and the reason for such modification.
*
* $Id: cylinder.c,v 3.0.1.5 90/04/09 14:29:43 craig Exp $
*
* $Log: cylinder.c,v $
* Revision 3.0.1.5 90/04/09 14:29:43 craig
* patch5: Transformation information now stored locally.
* patch5: Canonical cylinder now truly canonical.
*
* Revision 3.0.1.4 90/03/07 22:43:04 craig
* patch4: Fixed typo in previous fix.
*
* Revision 3.0.1.3 90/02/12 13:27:30 craig
* patch4: Changes to avoid rotation about null axis.
*
* Revision 3.0.1.2 89/12/06 16:33:41 craig
* patch2: Added calls to new error/warning routines.
*
* Revision 3.0.1.1 89/11/18 14:07:52 craig
* patch1: Changes to reflect new names of transformation routines.
*
* Revision 3.0 89/10/27 02:05:48 craig
* Baseline for first official release.
*
*/
#include <stdio.h>
#include <math.h>
#include "typedefs.h"
#include "funcdefs.h"
#include "constants.h"
Object *
makcyl(surf, cent, ax, r)
char *surf;
Vector *cent, *ax;
double r;
{
Cylinder *cyl;
Primitive *prim;
Object *newobj;
double len;
Vector axis, dir;
if (r <= 0.) {
yywarning("Invalid cylinder radius.\n");
return (Object *)0;
}
prim = mallocprim();
newobj = new_object(NULL, CYL, (char *)prim, (Trans *)NULL);
prim->surf = find_surface(surf);
prim->type = CYL;
cyl = (Cylinder *)Malloc(sizeof(Cylinder));
prim->objpnt.p_cylinder = cyl;
axis.x = ax->x - cent->x;
axis.y = ax->y - cent->y;
axis.z = ax->z - cent->z;
len = normalize(&axis);
if(len < EPSILON) {
yywarning("Degenerate cylinder.\n");
free((char *)cyl);
free((char *)prim);
return (Object *)0;
}
/*
* Define matrix to transform from Z axis aligned unit cylinder
* to desired cylinder.
*/
if (abs(axis.z) == 1.) {
dir.x = 1.;
dir.y = dir.z = 0.;
} else {
dir.x = axis.y;
dir.y = -axis.x;
dir.z = 0.;
}
init_trans(&cyl->trans.obj2world);
RS_scale(&cyl->trans.obj2world, r, r, len);
RS_rotate(&cyl->trans.obj2world, &dir, acos(axis.z));
RS_translate(&cyl->trans.obj2world, cent);
invert_trans(&cyl->trans.world2obj, &cyl->trans.obj2world);
return newobj;
}
/*
* Ray-cylinder intersection test.
*/
double
intcyl(pos, ray, obj)
Vector *pos, *ray;
Primitive *obj;
{
double t1, t2, a, b, c, zpos1, zpos2, et1, et2, x, y, disc;
double distfact;
extern unsigned long primtests[];
extern double TransformRay();
Ray newray;
Vector nray, npos;
Cylinder *cyl;
primtests[CYL]++;
cyl = obj->objpnt.p_cylinder;
/*
* Transform ray into canonical cylinder space.
*/
newray.dir = *ray;
newray.pos = *pos;
distfact = TransformRay(&newray, &cyl->trans.world2obj);
nray = newray.dir;
npos = newray.pos;
a = nray.x * nray.x + nray.y * nray.y;
c = npos.x*npos.x + npos.y*npos.y - 1;
if (a < EPSILON*EPSILON) { /* |nray.z| == 1. */
if(c < EPSILON*EPSILON) /* Within endcap */
/* Wrong if origin is inside cylinder. */
return min(-npos.z / nray.z,
(1. - npos.z) / nray.z) / distfact;
return 0.;
}
b = nray.x * npos.x + nray.y * npos.y;
disc = b*b - a*c;
if(disc < 0.)
return 0.;
disc = sqrt(disc);
t1 = (-b + disc) / a;
t2 = (-b - disc) / a;
if(t1 < EPSILON && t2 < EPSILON)
return 0.;
zpos1 = npos.z + t1 * nray.z;
zpos2 = npos.z + t2 * nray.z;
if ((zpos1 > 1 && zpos2 > 1) ||
(zpos1 < 0. && zpos2 < 0.))
return 0.;
if (t1 < EPSILON)
t1 = FAR_AWAY;
if (t2 < EPSILON)
t2 = FAR_AWAY;
/*
* Don't bother checking endcaps if both intersection points
* are on the cylinder.
*/
if ((zpos1 > 0. && zpos1 < 1. && zpos2 > 0. && zpos2 < 1.))
return min(t1, t2) / distfact;
/*
* It's possible to get rid of the ray-disc intersection tests
* (by looking at t1, t2 and zpos1, zpos), but the code gets messy.
*/
if (zpos1 < 0. || zpos1 > 1.)
t1 = FAR_AWAY;
if (zpos2 < 0. || zpos2 > 1.)
t2 = FAR_AWAY;
et1 = -npos.z / nray.z;
x = npos.x + et1 * nray.x;
y = npos.y + et1 * nray.y;
if (x*x + y*y > 1.)
et1 = FAR_AWAY;
et2 = (1. - npos.z) / nray.z;
x = npos.x + et2 * nray.x;
y = npos.y + et2 * nray.y;
if (x*x + y*y > 1.)
et2 = FAR_AWAY;
t1 = min(t1, min(t2, min(et1, et2)));
return (t1 == FAR_AWAY ? 0. : t1 / distfact);
}
nrmcyl(pos, obj, nrm)
Vector *pos, *nrm;
Primitive *obj;
{
Cylinder *cyl;
Vector npos;
double dist;
cyl = obj->objpnt.p_cylinder;
/*
* Transform position into cylinder space.
*/
npos = *pos;
transform_point(&npos, &cyl->trans.world2obj);
dist = npos.x*npos.x + npos.y*npos.y;
if (dist+EPSILON < 1) {
if (equal(npos.z,0.)) {
/*
* Hit on lower endcap.
*/
nrm->x = nrm->y = 0.;
nrm->z = -1.;
} else {
/*
* Hit on upper endcap.
*/
nrm->x = nrm->y = 0.;
nrm->z = 1.;
}
} else { /* Hit along cylinder. */
nrm->x = npos.x;
nrm->y = npos.y;
nrm->z = 0.;
/* Will be normalized by ShadeRay(). */
}
/*
* Tranform normal back to world space.
*/
TransformNormal(nrm, &cyl->trans.world2obj);
}
cylextent(o, bounds)
Primitive *o;
double bounds[2][3];
{
Cylinder *cyl;
cyl = o->objpnt.p_cylinder;
bounds[LOW][X] = bounds[LOW][Y] = -1;
bounds[HIGH][X] = bounds[HIGH][Y] = 1;
bounds[LOW][Z] = 0.;
bounds[HIGH][Z] = 1;
/*
* Transform bounding box to world space.
*/
transform_bounds(&cyl->trans.obj2world, bounds);
}