home *** CD-ROM | disk | FTP | other *** search
- /*
-
- SHAPE.C General shapes
-
- */
-
- /*...sincludes:0:*/
- #include <stdio.h>
- #include <stdlib.h>
- #include <stddef.h>
- #include <malloc.h>
- #include <memory.h>
- #include <math.h>
- #include "standard.h"
- #include "rt.h"
- #include "fio.h"
- #include "tex.h"
- #include "vector.h"
- #include "rgbvec.h"
- #include "col.h"
- #include "surf.h"
- #include "sil.h"
- #include "plane.h"
- #include "sphere.h"
- #include "quad.h"
- #define _SHAPE_
- #include "shape.h"
-
- /*...vrt\46\h:0:*/
- /*...vfio\46\h:0:*/
- /*...vtex\46\h:0:*/
- /*...vvector\46\h:0:*/
- /*...vrgbvec\46\h:0:*/
- /*...vcol\46\h:0:*/
- /*...vsurf\46\h:0:*/
- /*...vsil\46\h:0:*/
- /*...vplane\46\h:0:*/
- /*...vsphere\46\h:0:*/
- /*...vquad\46\h:0:*/
- /*...vshape\46\h:0:*/
- /*...e*/
-
- /*...screate_plane_shape \45\ create a shape tree consisting of a single plane:0:*/
- SHAPE *create_plane_shape(PLANE *plane, SURF *surf)
- {
- SHAPE *shape;
-
- if ( (shape = malloc(sizeof(SHAPE))) == NULL )
- return ( NULL );
-
- shape -> stype = STYPE_PLANE;
- shape -> u.plane = plane;
- shape -> surf = surf;
- return ( shape );
- }
- /*...e*/
- /*...screate_sphere_shape \45\ create a shape tree consisting of a single sphere:0:*/
- SHAPE *create_sphere_shape(SPHERE *sphere, SURF *surf)
- {
- SHAPE *shape;
-
- if ( (shape = malloc(sizeof(SHAPE))) == NULL )
- return ( NULL );
-
- shape -> stype = STYPE_SPHERE;
- shape -> u.sphere = sphere;
- shape -> surf = surf;
- return ( shape );
- }
- /*...e*/
- /*...screate_quad_shape \45\ create a shape tree consisting of a single quadratic:0:*/
- SHAPE *create_quad_shape(QUAD *quad, SURF *surf)
- {
- SHAPE *shape;
-
- if ( (shape = malloc(sizeof(SHAPE))) == NULL )
- return ( NULL );
-
- shape -> stype = STYPE_QUAD;
- shape -> u.quad = quad;
- shape -> surf = surf;
- return ( shape );
- }
- /*...e*/
- /*...screate_bin_shape \45\ create a binary shape tree made of 2 shapes:0:*/
- SHAPE *create_bin_shape(STYPE stype, SHAPE *shape0, SHAPE *shape1)
- {
- SHAPE *shape;
-
- if ( (shape = malloc(sizeof(SHAPE))) == NULL )
- return ( NULL );
-
- shape -> stype = stype;
- shape -> u.shapes [0] = shape0;
- shape -> u.shapes [1] = shape1;
- return ( shape );
- }
- /*...e*/
- /*...scopy_shape \45\ make a complete copy of a shape tree:0:*/
- SHAPE *copy_shape(SHAPE *shape)
- {
- SHAPE *copy;
-
- if ( (copy = malloc(sizeof(SHAPE))) == NULL )
- return ( NULL );
-
- copy -> stype = shape -> stype;
-
- if ( shape -> stype <= STYPE_QUAD )
- /* Leaf node */
- {
- if ( (copy -> surf = copy_surf(shape -> surf)) == NULL )
- {
- free(copy);
- return ( NULL );
- }
- switch ( shape -> stype )
- {
- /*...sSTYPE_PLANE:24:*/
- case STYPE_PLANE:
- if ( (copy -> u.plane = copy_plane(shape -> u.plane)) == NULL )
- {
- destroy_surf(copy -> surf);
- free(copy);
- return ( NULL );
- }
- break;
- /*...e*/
- /*...sSTYPE_SPHERE:24:*/
- case STYPE_SPHERE:
- if ( (copy -> u.sphere = copy_sphere(shape -> u.sphere)) == NULL )
- {
- destroy_surf(copy -> surf);
- free(copy);
- return ( NULL );
- }
- break;
- /*...e*/
- /*...sSTYPE_QUAD:24:*/
- case STYPE_QUAD:
- if ( (copy -> u.quad = copy_quad(shape -> u.quad)) == NULL )
- {
- destroy_surf(copy -> surf);
- free(copy);
- return ( NULL );
- }
- break;
- /*...e*/
- }
- }
- else
- /*...sboolean combinations:16:*/
- {
- if ( (copy -> u.shapes [0] = copy_shape(shape -> u.shapes [0])) == NULL )
- {
- free(copy);
- return ( NULL );
- }
- if ( (copy -> u.shapes [1] = copy_shape(shape -> u.shapes [1])) == NULL )
- {
- free(copy -> u.shapes [0]);
- free(copy);
- return ( NULL );
- }
- }
- /*...e*/
-
- return ( copy );
- }
- /*...e*/
- /*...sdestroy_shape \45\ delete a shape tree:0:*/
- void destroy_shape(SHAPE *shape)
- {
- if ( shape -> stype <= STYPE_QUAD )
- /* Leaf node */
- {
- destroy_surf(shape -> surf);
- switch ( shape -> stype )
- {
- /*...sSTYPE_PLANE:24:*/
- case STYPE_PLANE:
- destroy_plane(shape -> u.plane);
- break;
- /*...e*/
- /*...sSTYPE_SPHERE:24:*/
- case STYPE_SPHERE:
- destroy_sphere(shape -> u.sphere);
- break;
- /*...e*/
- /*...sSTYPE_QUAD:24:*/
- case STYPE_QUAD:
- destroy_quad(shape -> u.quad);
- break;
- /*...e*/
- }
- }
- else
- {
- destroy_shape(shape -> u.shapes [0]);
- destroy_shape(shape -> u.shapes [1]);
- }
-
- free(shape);
- }
- /*...e*/
- /*...ssphere_to_quad \45\ convert sphere to quad:0:*/
- /*
- Spheres cannot be rescaled in each direction and remain a sphere.
- Hence this code will convert a sphere into the equivelent quadratic.
-
- 2 2 2
- Sphere: (x-a) +(y-b) +(z-c) -d <=0
-
- 2 2 2 2 2 2
- x -2ax+a +y -2by+b +z -2cz+c -d <= 0
-
- 2 2 2
- Quadratic: ax +by +cz +dxy+eyz+fzx+gx+hy+iz+j<=0
-
- */
-
- static BOOLEAN sphere_to_quad(SHAPE *shape)
- {
- SPHERE *sphere = shape -> u.sphere;
- QUAD *quad;
-
- if ( (quad = create_quad(1.0, 1.0, 1.0, 0.0, 0.0, 0.0,
- -2.0 * sphere -> a, -2.0 * sphere -> b, -2.0 * sphere -> c,
- - sphere -> d)) == NULL )
- return ( FALSE );
-
- destroy_sphere(shape -> u.sphere);
- shape -> stype = STYPE_QUAD;
- shape -> u.quad = quad;
-
- return ( TRUE );
- }
- /*...e*/
-
- /*...strans_x \45\ translate by amount in x direction:0:*/
- void trans_x(SHAPE *shape, double t)
- {
- if ( shape -> stype <= STYPE_QUAD )
- {
- switch ( shape -> stype )
- {
- case STYPE_PLANE:
- trans_x_plane(shape -> u.plane, t);
- break;
- case STYPE_SPHERE:
- trans_x_sphere(shape -> u.sphere, t);
- break;
- case STYPE_QUAD:
- trans_x_quad(shape -> u.quad, t);
- break;
- }
- trans_x_surf(shape -> surf, t);
- }
- else
- {
- trans_x(shape -> u.shapes [0], t);
- trans_x(shape -> u.shapes [1], t);
- }
- }
- /*...e*/
- /*...strans_y \45\ translate by amount in y direction:0:*/
- void trans_y(SHAPE *shape, double t)
- {
- if ( shape -> stype <= STYPE_QUAD )
- {
- switch ( shape -> stype )
- {
- case STYPE_PLANE:
- trans_y_plane(shape -> u.plane, t);
- break;
- case STYPE_SPHERE:
- trans_y_sphere(shape -> u.sphere, t);
- break;
- case STYPE_QUAD:
- trans_y_quad(shape -> u.quad, t);
- break;
- }
- trans_y_surf(shape -> surf, t);
- }
- else
- {
- trans_y(shape -> u.shapes [0], t);
- trans_y(shape -> u.shapes [1], t);
- }
- }
- /*...e*/
- /*...strans_z \45\ translate by amount in z direction:0:*/
- void trans_z(SHAPE *shape, double t)
- {
- if ( shape -> stype <= STYPE_QUAD )
- {
- switch ( shape -> stype )
- {
- case STYPE_PLANE:
- trans_z_plane(shape -> u.plane, t);
- break;
- case STYPE_SPHERE:
- trans_z_sphere(shape -> u.sphere, t);
- break;
- case STYPE_QUAD:
- trans_z_quad(shape -> u.quad, t);
- break;
- }
- trans_z_surf(shape -> surf, t);
- }
- else
- {
- trans_z(shape -> u.shapes [0], t);
- trans_z(shape -> u.shapes [1], t);
- }
- }
- /*...e*/
- /*...strans \45\ translate by vector:0:*/
- void trans(SHAPE *shape, VECTOR v)
- {
- trans_x(shape, v.x);
- trans_y(shape, v.y);
- trans_z(shape, v.z);
- }
- /*...e*/
- /*...sscale_x \45\ scale by factor in x direction:0:*/
- BOOLEAN scale_x(SHAPE *shape, double factor)
- {
- if ( factor == 1.0 )
- return ( TRUE );
-
- if ( shape -> stype <= STYPE_QUAD )
- {
- switch ( shape -> stype )
- {
- case STYPE_PLANE:
- scale_x_plane(shape -> u.plane, factor);
- break;
- case STYPE_SPHERE:
- if ( !sphere_to_quad(shape) )
- return ( FALSE );
- scale_x_quad(shape -> u.quad, factor);
- break;
- case STYPE_QUAD:
- scale_x_quad(shape -> u.quad, factor);
- break;
- }
- scale_x_surf(shape -> surf, factor);
- }
- else
- {
- if ( !scale_x(shape -> u.shapes [0], factor) ||
- !scale_x(shape -> u.shapes [1], factor) )
- return ( FALSE );
- }
- return ( TRUE );
- }
- /*...e*/
- /*...sscale_y \45\ scale by factor in y direction:0:*/
- BOOLEAN scale_y(SHAPE *shape, double factor)
- {
- if ( factor == 1.0 )
- return ( TRUE );
-
- if ( shape -> stype <= STYPE_QUAD )
- {
- switch ( shape -> stype )
- {
- case STYPE_PLANE:
- scale_y_plane(shape -> u.plane, factor);
- break;
- case STYPE_SPHERE:
- if ( !sphere_to_quad(shape) )
- return ( FALSE );
- scale_y_quad(shape -> u.quad, factor);
- break;
- case STYPE_QUAD:
- scale_y_quad(shape -> u.quad, factor);
- break;
- }
- scale_y_surf(shape -> surf, factor);
- }
- else
- {
- if ( !scale_y(shape -> u.shapes [0], factor) ||
- !scale_y(shape -> u.shapes [1], factor) )
- return ( FALSE );
- }
- return ( TRUE );
- }
- /*...e*/
- /*...sscale_z \45\ scale by factor in z direction:0:*/
- BOOLEAN scale_z(SHAPE *shape, double factor)
- {
- if ( factor == 1.0 )
- return ( TRUE );
-
- if ( shape -> stype <= STYPE_QUAD )
- {
- switch ( shape -> stype )
- {
- case STYPE_PLANE:
- scale_z_plane(shape -> u.plane, factor);
- break;
- case STYPE_SPHERE:
- if ( !sphere_to_quad(shape) )
- return ( FALSE );
- scale_z_quad(shape -> u.quad, factor);
- break;
- case STYPE_QUAD:
- scale_z_quad(shape -> u.quad, factor);
- break;
- }
- scale_z_surf(shape -> surf, factor);
- }
- else
- {
- if ( !scale_z(shape -> u.shapes [0], factor) ||
- !scale_z(shape -> u.shapes [1], factor) )
- return ( FALSE );
- }
- return ( TRUE );
- }
- /*...e*/
- /*...sscale \45\ scale by vector factor:0:*/
- BOOLEAN scale(SHAPE *shape, VECTOR factor)
- {
- if ( shape -> stype == STYPE_SPHERE &&
- factor.x == factor.y && factor.y == factor.z )
- {
- scale_sphere(shape -> u.sphere, factor.x);
- scale_x_surf(shape -> surf, factor.x);
- scale_y_surf(shape -> surf, factor.y);
- scale_z_surf(shape -> surf, factor.z);
- }
- else
- {
- if ( !scale_x(shape, factor.x) ||
- !scale_y(shape, factor.y) ||
- !scale_z(shape, factor.z) )
- return ( FALSE );
- }
- return ( TRUE );
- }
- /*...e*/
- /*...srot_x \45\ rotate about x axis by given angle:0:*/
- void rot_x(SHAPE *shape, double angle)
- {
- if ( shape -> stype <= STYPE_QUAD )
- {
- switch ( shape -> stype )
- {
- case STYPE_PLANE:
- rot_x_plane(shape -> u.plane, angle);
- break;
- case STYPE_SPHERE:
- rot_x_sphere(shape -> u.sphere, angle);
- break;
- case STYPE_QUAD:
- rot_x_quad(shape -> u.quad, angle);
- break;
- }
- rot_x_surf(shape -> surf, angle);
- }
- else
- {
- rot_x(shape -> u.shapes [0], angle);
- rot_x(shape -> u.shapes [1], angle);
- }
- }
- /*...e*/
- /*...srot_y \45\ rotate about y axis by given angle:0:*/
- void rot_y(SHAPE *shape, double angle)
- {
- if ( shape -> stype <= STYPE_QUAD )
- {
- switch ( shape -> stype )
- {
- case STYPE_PLANE:
- rot_y_plane(shape -> u.plane, angle);
- break;
- case STYPE_SPHERE:
- rot_y_sphere(shape -> u.sphere, angle);
- break;
- case STYPE_QUAD:
- rot_y_quad(shape -> u.quad, angle);
- break;
- }
- rot_y_surf(shape -> surf, angle);
- }
- else
- {
- rot_y(shape -> u.shapes [0], angle);
- rot_y(shape -> u.shapes [1], angle);
- }
- }
- /*...e*/
- /*...srot_z \45\ rotate about z axis by given angle:0:*/
- void rot_z(SHAPE *shape, double angle)
- {
- if ( shape -> stype <= STYPE_QUAD )
- {
- switch ( shape -> stype )
- {
- case STYPE_PLANE:
- rot_z_plane(shape -> u.plane, angle);
- break;
- case STYPE_SPHERE:
- rot_z_sphere(shape -> u.sphere, angle);
- break;
- case STYPE_QUAD:
- rot_z_quad(shape -> u.quad, angle);
- break;
- }
- rot_z_surf(shape -> surf, angle);
- }
- else
- {
- rot_z(shape -> u.shapes [0], angle);
- rot_z(shape -> u.shapes [1], angle);
- }
- }
- /*...e*/
-
- /*...sresurf \45\ change the surface of a shape:0:*/
- BOOLEAN resurf(SHAPE *shape, SURF *surf)
- {
- if ( shape -> stype <= STYPE_QUAD )
- {
- SURF *surf_copy;
-
- if ( (surf_copy = copy_surf(surf)) == NULL )
- return ( FALSE );
-
- destroy_surf(shape -> surf);
- shape -> surf = surf_copy;
- }
- else
- {
- if ( !resurf(shape -> u.shapes [0], surf) )
- return ( FALSE );
- if ( !resurf(shape -> u.shapes [1], surf) )
- return ( FALSE );
- }
-
- return ( TRUE );
- }
- /*...e*/
-
- /*...sis_empty_isectl \45\ is intersection list empty:0:*/
- BOOLEAN is_empty_isectl(ISECTL *il)
- {
- return ( il -> n_isects == 0 );
- }
- /*...e*/
- /*...sis_solid_isectl \45\ is intersection list solid:0:*/
- /*
- We will allow t from -INFINITE onwards or t from -INFINITE to INFINITE.
- */
-
- BOOLEAN is_solid_isectl(ISECTL *il)
- {
- if ( il -> n_isects > 2 )
- return ( FALSE );
-
- if ( il -> isects [0].t != -INFINITE )
- return ( FALSE );
-
- return ( il -> n_isects == 1 || il -> isects [1].t == INFINITE );
- }
- /*...e*/
- /*...st_after_isectl \45\ eliminate all intersections before a t value:0:*/
- void t_after_isectl(ISECTL *il, double t)
- {
- int i;
-
- for ( i = 0; i < il -> n_isects; i++ )
- if ( il -> isects [i].t >= t )
- break;
-
- if ( i == il -> n_isects )
- /* All behind t */
- il -> n_isects = 0;
- else if ( i != 0 )
- /* Some behind and some after t */
- {
- int j = 0;
-
- if ( il -> isects [i].entering == FALSE )
- /* Had better make an isect case first */
- {
- il -> isects [j ] = il -> isects [i - 1];
- il -> isects [j++].t = t;
- }
-
- while ( i < il -> n_isects )
- il -> isects [j++] = il -> isects [i++];
- il -> n_isects = j;
- }
- }
- /*...e*/
-
- /*...screate_isectl \45\ create an isectl:0:*/
- ISECTL *create_isectl(int n_isects)
- {
- return ( malloc(sizeof(ISECTL) + (n_isects - 1) * sizeof(ISECT)) );
- }
- /*...e*/
- /*...sdestroy_isectl \45\ destroy an isectl:0:*/
- void destroy_isectl(ISECTL *il)
- {
- free(il);
- }
- /*...e*/
-
- /*...spreprocess_shape \45\ preprocess shape tree to save work when tracing:0:*/
- /*...sextent_shape:0:*/
- /*
- If we can find shapes that do not overlap, we can avoid tracing time later.
- This type of function is only made possible because the code that implements
- spheres etc. export their internal representations of the shapes.
- */
-
- /*...sspheres_overlap:0:*/
- /*
- 2 spheres overlap if the sum of the radii > distance between the centres.
- We square both sides of this equation.
- */
-
- static BOOLEAN spheres_overlap(SPHERE *sphere_a, SPHERE *sphere_b)
- {
- double dx = sphere_a -> a - sphere_b -> a;
- double dy = sphere_a -> b - sphere_b -> b;
- double dz = sphere_a -> c - sphere_b -> c;
- double rr = sphere_a -> d + sphere_b -> d;
-
- return ( rr*rr >= dx*dx + dy*dy + dz*dz );
- }
- /*...e*/
-
- typedef struct { VECTOR min, max; } EXTENT;
-
- /*...sextent_infinite:0:*/
- static EXTENT extent_infinite(void)
- {
- EXTENT extent;
-
- extent.min.x = extent.min.y = extent.min.z = -INFINITE;
- extent.max.x = extent.max.y = extent.max.z = INFINITE;
- return ( extent );
- }
- /*...e*/
- /*...sextent_of_sphere:0:*/
- static EXTENT extent_of_sphere(SPHERE *sphere)
- {
- double a = sphere -> a;
- double b = sphere -> b;
- double c = sphere -> c;
- double d = sphere -> d;
- EXTENT extent;
-
- extent.min.x = a - d; extent.max.x = a + d;
- extent.min.y = b - d; extent.max.y = b + d;
- extent.min.z = c - d; extent.max.z = c + d;
-
- return ( extent );
- }
- /*...e*/
- /*...sextents_overlap:0:*/
- static BOOLEAN extents_overlap(EXTENT *extent_a, EXTENT *extent_b)
- {
- return ( extent_a -> max.x > extent_b -> min.x &&
- extent_a -> max.y > extent_b -> min.y &&
- extent_a -> max.z > extent_b -> min.z &&
- extent_b -> max.x > extent_a -> min.x &&
- extent_b -> max.y > extent_a -> min.y &&
- extent_b -> max.z > extent_a -> min.z );
- }
- /*...e*/
- /*...sextents_union:0:*/
- static EXTENT extents_union(EXTENT *extent_a, EXTENT *extent_b)
- {
- EXTENT extent;
-
- extent.min.x = min(extent_a -> min.x, extent_b -> min.x);
- extent.min.y = min(extent_a -> min.y, extent_b -> min.y);
- extent.min.z = min(extent_a -> min.z, extent_b -> min.z);
- extent.max.x = max(extent_a -> max.x, extent_b -> max.x);
- extent.max.y = max(extent_a -> max.y, extent_b -> max.y);
- extent.max.z = max(extent_a -> max.z, extent_b -> max.z);
-
- return ( extent );
- }
- /*...e*/
- /*...sextents_isect:0:*/
- static EXTENT extents_isect(EXTENT *extent_a, EXTENT *extent_b)
- {
- EXTENT extent;
-
- extent.min.x = max(extent_a -> min.x, extent_b -> min.x);
- extent.min.y = max(extent_a -> min.y, extent_b -> min.y);
- extent.min.z = max(extent_a -> min.z, extent_b -> min.z);
- extent.max.x = min(extent_a -> max.x, extent_b -> max.x);
- extent.max.y = min(extent_a -> max.y, extent_b -> max.y);
- extent.max.z = min(extent_a -> max.z, extent_b -> max.z);
-
- return ( extent );
- }
- /*...e*/
-
- static EXTENT extent_shape(SHAPE *shape)
- {
- static EXTENT dummy_extent = { { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } };
-
- if ( shape -> stype <= STYPE_QUAD )
- {
- switch ( shape -> stype )
- {
- /*...sSTYPE_PLANE\44\ STYPE_QUAD \45\ too difficult:24:*/
- case STYPE_PLANE:
- case STYPE_QUAD:
- return ( extent_infinite() );
- /*...e*/
- /*...sSTYPE_SPHERE:24:*/
- case STYPE_SPHERE:
- return ( extent_of_sphere(shape -> u.sphere) );
- /*...e*/
- }
- }
- else if ( shape -> stype == STYPE_EXTENT )
- {
- EXTENT extent;
-
- extent = extent_shape(shape -> u.shapes [0]);
- /* Performed for side effect of extent_shape() call */
-
- return ( extent_shape(shape -> u.shapes [1]) );
- }
- else
- {
- SHAPE *shape_a = shape -> u.shapes [0];
- SHAPE *shape_b = shape -> u.shapes [1];
- EXTENT extent_a;
- EXTENT extent_b;
- EXTENT extent;
-
- extent_a = extent_shape(shape_a);
- extent_b = extent_shape(shape_b);
-
- switch ( shape -> stype )
- {
- /*...sSTYPE_UNION\44\ STYPE_SDIFF:24:*/
- case STYPE_UNION:
- case STYPE_SDIFF:
- extent = extents_union(&extent_a, &extent_b);
- break;
- /*...e*/
- /*...sSTYPE_ISECT:24:*/
- case STYPE_ISECT:
- extent = extents_isect(&extent_a, &extent_b);
- break;
- /*...e*/
- /*...sSTYPE_DIFF:24:*/
- case STYPE_DIFF:
- extent = extent_a;
- break;
- /*...e*/
- }
-
- if ( shape_a -> stype == STYPE_SPHERE &&
- shape_b -> stype == STYPE_SPHERE )
- shape -> overlap = spheres_overlap(
- shape_a -> u.sphere, shape_b -> u.sphere);
- else
- shape -> overlap = extents_overlap(&extent_a, &extent_b);
-
- return ( extent );
- }
-
- return ( dummy_extent ); /* Keep fussy C compiler happy */
- }
- /*...e*/
- /*...sn_isectls_reqd_shape:0:*/
- /*
- We use this function so that we can work out how many intersection lists
- we will need to pre-allocate for tracing the shape.
- */
-
- int n_isectls_reqd_shape(SHAPE *shape)
- {
- int nest0, nest1;
-
- if ( shape -> stype <= STYPE_QUAD )
- return ( 1 );
-
- nest0 = n_isectls_reqd_shape(shape -> u.shapes [0]);
- nest1 = n_isectls_reqd_shape(shape -> u.shapes [1]);
-
- return ( 2 + max(nest0, nest1) );
- }
- /*...e*/
- /*...sisects_reqd_shape:0:*/
- /*
- Determine largest needed intersection list.
- */
-
- int isects_reqd_shape(SHAPE *shape)
- {
- if ( shape -> stype <= STYPE_QUAD )
- switch ( shape -> stype )
- {
- /*...sSTYPE_PLANE:24:*/
- case STYPE_PLANE:
- return ( isects_reqd_plane(shape -> u.plane) );
- /*...e*/
- /*...sSTYPE_SPHERE:24:*/
- case STYPE_SPHERE:
- return ( isects_reqd_sphere(shape -> u.sphere) );
- /*...e*/
- /*...sSTYPE_QUAD:24:*/
- case STYPE_QUAD:
- return ( isects_reqd_quad(shape -> u.quad) );
- /*...e*/
- }
- else
- {
- int reqd0 = isects_reqd_shape(shape -> u.shapes [0]);
- int reqd1 = isects_reqd_shape(shape -> u.shapes [1]);
-
- switch ( shape -> stype )
- {
- /*...sSTYPE_UNION:24:*/
- case STYPE_UNION:
- return ( reqd0 + reqd1 );
- /*...e*/
- /*...sSTYPE_ISECT:24:*/
- case STYPE_ISECT:
- return ( ( shape -> overlap ) ? reqd0 + reqd1 : 0 );
- /*...e*/
- /*...sSTYPE_DIFF:24:*/
- case STYPE_DIFF:
- return ( ( shape -> overlap ) ? reqd0 + reqd1 : reqd0 );
- /*...e*/
- /*...sSTYPE_SDIFF:24:*/
- case STYPE_SDIFF:
- return ( reqd0 + reqd1 );
- /*...e*/
- /*...sSTYPE_EXTENT:24:*/
- case STYPE_EXTENT:
- return ( max(reqd0, reqd1) );
- /*...e*/
- }
- }
- return ( 0 ); /* Keep fussy C compiler happy */
- }
- /*...e*/
-
- void preprocess_shape(SHAPE *shape, int *n_isectls, int *n_isects)
- {
- EXTENT extent;
-
- extent = extent_shape(shape);
- /* The side effect is to label the shape tree */
-
- *n_isectls = n_isectls_reqd_shape(shape);
- *n_isects = isects_reqd_shape(shape);
- }
- /*...e*/
- /*...sintersect_shape \45\ intersect with a shape to give a ISECTL:0:*/
- /*
- Given a shape tree, find the intersection list of a vector with it.
- If the shape tree is not a leaf node, then combine the intersection lists of
- the subtrees. We can make several optimisations in this area.
- */
-
- /*...smake_empty_isectl:0:*/
- static void make_empty_isectl(ISECTL *il)
- {
- il -> n_isects = 0;
- }
- /*...e*/
- /*...scopy_isectl:0:*/
- static void copy_isectl(ISECTL *il_dst, ISECTL *il_src)
- {
- int i;
-
- il_dst -> n_isects = il_src -> n_isects;
- for ( i = 0; i < il_dst -> n_isects; i++ )
- il_dst -> isects [i] = il_src -> isects [i];
- }
- /*...e*/
- /*...scombine_isectl:0:*/
- /*
- Given 2 intersection lists, produce a new one that is a combination of them.
-
- The in_old flag is used to determine if the point of intersection changes
- meaning from in->out to out->in, or vice-versa. If this happens, the
- sense of the normal vector must change :-
-
- ..... ..... .....
- . . . . .
- . A . . B . . A-B .
- . . . . . .
- <-. <-. .-> .-> <-. .-> This vector changes direction!
- . . . . . .
- . . . . . .
- . . . . .
- ..... ..... .....
-
- */
-
- static void combine_isectl(
- BOOLEAN (*combine)(BOOLEAN in_a, BOOLEAN in_b),
- ISECTL *il_a, ISECTL *il_b, ISECTL *il)
- {
- BOOLEAN in_a = FALSE; /* When t = -INFINITE, in_a = FALSE */
- BOOLEAN in_b = FALSE; /* When t = -INFINITE, in_b = FALSE */
- BOOLEAN in = FALSE; /* Therefore combination starts as FALSE */
- int ptr_a = 0;
- int ptr_b = 0;
- BOOLEAN in_new, in_old;
-
- il -> n_isects = 0;
-
- /* Work through both a and b, looking at nearest ones first */
-
- while ( ptr_a < il_a -> n_isects && ptr_b < il_b -> n_isects )
- {
- ISECT *isect;
- double t_a = il_a -> isects [ptr_a].t;
- double t_b = il_b -> isects [ptr_b].t;
-
- if ( t_a < t_b )
- {
- in_old = in_a = !in_a;
- isect = &(il_a -> isects [ptr_a++]);
- }
- else if ( t_a > t_b )
- {
- in_old = in_b = !in_b;
- isect = &(il_b -> isects [ptr_b++]);
- }
- else
- /* Two surfaces at exactly the same place */
- /* Not a very frequent event, but problematical */
- /* Just label intersection arbitrarily as with B */
- {
- in_a = !in_a; ptr_a++;
- in_old = in_b = !in_b;
- isect = &(il_b -> isects [ptr_b++]);
- }
-
- if ( (in_new = (*combine)(in_a, in_b)) != in )
- /* Need to keep a record of this transition */
- {
- il -> isects [il -> n_isects] = *isect;
- il -> isects [il -> n_isects].entering = in = in_new;
- if ( in_new != in_old )
- il -> isects [il -> n_isects].negate_normal ^= TRUE;
- il -> n_isects++;
- }
- }
-
- /* Either a or b is exhausted, so one of a or b may be left */
-
- while ( ptr_a < il_a -> n_isects )
- {
- in_old = in_a = !in_a;
- if ( (in_new = (*combine)(in_a, in_b)) != in )
- /* Need to keep a record of this transition */
- {
- il -> isects [il -> n_isects] = il_a -> isects [ptr_a];
- il -> isects [il -> n_isects].entering = in = in_new;
- if ( in_new != in_old )
- il -> isects [il -> n_isects].negate_normal ^= TRUE;
- il -> n_isects++;
- }
- ptr_a++;
- }
-
- while ( ptr_b < il_b -> n_isects )
- {
- in_old = in_b = !in_b;
- if ( (in_new = (*combine)(in_a, in_b)) != in )
- /* Need to keep a record of this transition */
- {
- il -> isects [il -> n_isects] = il_b -> isects [ptr_b];
- il -> isects [il -> n_isects].entering = in = in_new;
- if ( in_new != in_old )
- il -> isects [il -> n_isects].negate_normal ^= TRUE;
- il -> n_isects++;
- }
- ptr_b++;
- }
- }
- /*...e*/
- /*...sunion_isectl:0:*/
- /*...scombine_union:0:*/
- static BOOLEAN combine_union(BOOLEAN in_a, BOOLEAN in_b)
- {
- return ( in_a || in_b );
- }
- /*...e*/
-
- static void union_isectl(ISECTL *il_a, ISECTL *il_b, ISECTL *il)
- {
- combine_isectl(combine_union, il_a, il_b, il);
- }
- /*...e*/
- /*...sisect_isectl:0:*/
- /*...scombine_isect:0:*/
- static BOOLEAN combine_isect(BOOLEAN in_a, BOOLEAN in_b)
- {
- return ( in_a && in_b );
- }
- /*...e*/
-
- static void isect_isectl(ISECTL *il_a, ISECTL *il_b, ISECTL *il)
- {
- combine_isectl(combine_isect, il_a, il_b, il);
- }
- /*...e*/
- /*...sdiff_isectl:0:*/
- /*...scombine_diff:0:*/
- static BOOLEAN combine_diff(BOOLEAN in_a, BOOLEAN in_b)
- {
- return ( in_a && !in_b );
- }
- /*...e*/
-
- static void diff_isectl(ISECTL *il_a, ISECTL *il_b, ISECTL *il)
- {
- combine_isectl(combine_diff, il_a, il_b, il);
- }
- /*...e*/
- /*...ssdiff_isectl:0:*/
- /*...scombine_sdiff:0:*/
- static BOOLEAN combine_sdiff(BOOLEAN in_a, BOOLEAN in_b)
- {
- return ( in_a ^ in_b );
- }
- /*...e*/
-
- static void sdiff_isectl(ISECTL *il_a, ISECTL *il_b, ISECTL *il)
- {
- combine_isectl(combine_sdiff, il_a, il_b, il);
- }
- /*...e*/
- /*...sconcat_isectl:0:*/
- /*
- This is a quick case of unioning two intersection lists for use when it is
- known that they do not overlap.
- */
-
- static void concat_isectl(ISECTL *il_a, ISECTL *il_b, ISECTL *il)
- {
- ISECTL *il_rest;
- int i, j;
-
- if ( il_a -> n_isects == 0 )
- {
- copy_isectl(il, il_b);
- return;
- }
-
- if ( il_b -> n_isects == 0 )
- {
- copy_isectl(il, il_a);
- return;
- }
-
- if ( il_a -> isects [0].t < il_b -> isects [0].t )
- {
- copy_isectl(il, il_a);
- il_rest = il_b;
- }
- else
- {
- copy_isectl(il, il_b);
- il_rest = il_a;
- }
-
- for ( i = 0, j = il -> n_isects; i < il_rest -> n_isects; i++, j++ )
- il -> isects [j] = il_rest -> isects [i];
-
- il -> n_isects = j;
- }
- /*...e*/
-
- void intersect_shape(SHAPE *shape, VECTOR p, VECTOR q, ISECTL *ils [])
- {
- if ( shape -> stype <= STYPE_QUAD )
- /* Is a leaf node */
- {
- SIL sil;
- int i;
-
- switch ( shape -> stype )
- {
- /*...sSTYPE_PLANE:24:*/
- case STYPE_PLANE:
- intersect_plane(shape -> u.plane, p, q, &sil);
- break;
- /*...e*/
- /*...sSTYPE_SPHERE:24:*/
- case STYPE_SPHERE:
- intersect_sphere(shape -> u.sphere, p, q, &sil);
- break;
- /*...e*/
- /*...sSTYPE_QUAD:24:*/
- case STYPE_QUAD:
- intersect_quad(shape -> u.quad, p, q, &sil);
- break;
- /*...e*/
- }
- ils [0] -> n_isects = sil.n_sis;
- for ( i = 0; i < sil.n_sis; i++ )
- {
- ils [0] -> isects [i].t = sil.sis [i].t;
- ils [0] -> isects [i].entering = sil.sis [i].entering;
- ils [0] -> isects [i].shape = shape;
- ils [0] -> isects [i].negate_normal = FALSE;
- }
- }
- else
- /* Binary combination of two subtrees */
- {
- SHAPE *shape_a = shape -> u.shapes [0];
- SHAPE *shape_b = shape -> u.shapes [1];
-
- switch ( shape -> stype )
- {
- /*...sSTYPE_UNION:24:*/
- case STYPE_UNION:
- if ( shape -> overlap )
- {
- intersect_shape(shape_b, p, q, ils + 1);
- if ( is_empty_isectl(ils [1]) )
- intersect_shape(shape_a, p, q, ils);
- else if ( is_solid_isectl(ils [1]) )
- copy_isectl(ils [0], ils [1]);
- else
- {
- intersect_shape(shape_a, p, q, ils + 2);
- union_isectl(ils [2], ils [1], ils [0]);
- }
- }
- else
- /* No overlap, treat like concatentation */
- {
- intersect_shape(shape_a, p, q, ils + 1);
- intersect_shape(shape_b, p, q, ils + 2);
- concat_isectl(ils [1], ils [2], ils [0]);
- }
- break;
- /*...e*/
- /*...sSTYPE_ISECT:24:*/
- case STYPE_ISECT:
- if ( shape -> overlap )
- {
- intersect_shape(shape_b, p, q, ils + 1);
- if ( is_empty_isectl(ils [1]) )
- make_empty_isectl(ils [0]);
- else if ( is_solid_isectl(ils [1]) )
- intersect_shape(shape_a, p, q, ils);
- else
- {
- intersect_shape(shape_a, p, q, ils + 2);
- isect_isectl(ils [2], ils [1], ils [0]);
- }
- }
- else
- make_empty_isectl(ils [0]);
- break;
- /*...e*/
- /*...sSTYPE_DIFF:24:*/
- case STYPE_DIFF:
- if ( shape -> overlap )
- {
- intersect_shape(shape_b, p, q, ils + 1);
- if ( is_empty_isectl(ils [1]) )
- intersect_shape(shape_a, p, q, ils);
- else if ( is_solid_isectl(ils [1]) )
- make_empty_isectl(ils [0]);
- else
- {
- intersect_shape(shape_a, p, q, ils + 2);
- diff_isectl(ils [2], ils [1], ils [0]);
- }
- }
- else
- intersect_shape(shape_a, p, q, ils);
- break;
- /*...e*/
- /*...sSTYPE_SDIFF:24:*/
- case STYPE_SDIFF:
- if ( shape -> overlap )
- {
- intersect_shape(shape_b, p, q, ils + 1);
- if ( is_empty_isectl(ils [1]) )
- intersect_shape(shape_a, p, q, ils);
- else
- {
- intersect_shape(shape_a, p, q, ils + 2);
- sdiff_isectl(ils [2], ils [1], ils [0]);
- }
- }
- else
- /* No overlap, treat like concatentation */
- {
- intersect_shape(shape_a, p, q, ils + 1);
- intersect_shape(shape_b, p, q, ils + 2);
- concat_isectl(ils [1], ils [2], ils [0]);
- }
- break;
- /*...e*/
- /*...sSTYPE_EXTENT:24:*/
- case STYPE_EXTENT:
- intersect_shape(shape_b, p, q, ils);
- if ( !is_empty_isectl(ils [0]) )
- intersect_shape(shape_a, p, q, ils);
- break;
- /*...e*/
- }
- }
- }
- /*...e*/
- /*...snormal_to_shape \45\ find normal at point on edge of shape:0:*/
- VECTOR normal_to_shape(SHAPE *shape, VECTOR p)
- {
- static VECTOR dummy_vector = { 0.0, 0.0, 0.0 };
-
- switch ( shape -> stype )
- {
- case STYPE_PLANE:
- return ( normal_to_plane(shape -> u.plane) );
- case STYPE_SPHERE:
- return ( normal_to_sphere(shape -> u.sphere, p) );
- case STYPE_QUAD:
- return ( normal_to_quad(shape -> u.quad, p) );
- }
- return ( dummy_vector ); /* Keep fussy C compiler happy */
- }
- /*...e*/
-