#ifndef lint
static char *sccsid = "@(#)shapes.c	1.5 (Steve Hill) 4/6/90";
#endif

/* shapes.c
 *
 * A library of predefined solids.
 */

#include <stdio.h>
#include <math.h>

#include "basetype.h"
#include "error.h"
#include "cartesian.h"
#include "matrix.h"
#include "point.h"
#include "vector.h"
#include "indexlist.h"
#include "ray.h"
#include "quadric.h"
#include "colour.h"
#include "surface.h"
#include "bitmap.h"
#include "pattern.h"
#include "solid.h"
#include "bbox.h"
#include "shapes.h"


/* Everywhere
 *
 * This is the solid that is omnipresent.
 */

solid_t *
Everywhere()
{
	quadric_t	*q;

	q = QuadricZero();
	QuadricSet(q, QJ, -REAL_ONE);
	return(Solid(q, OTHER));
}


/* Nowhere
 *
 * This solid is not there at all.
 */

solid_t *
Nowhere()
{
	return(SolidNegate(Everywhere()));
}


/* Sphere
 *
 * A sphere at the origin of unit radius.
 */

solid_t *
Sphere()
{
	quadric_t	*q;

	q = QuadricZero();
	QuadricSet(q, QA,  REAL_ONE);
	QuadricSet(q, QE,  REAL_ONE);
	QuadricSet(q, QH,  REAL_ONE);
	QuadricSet(q, QJ, -REAL_ONE);

	return(Solid(q, ELLIPSOID));
}


/* Cylinder
 *
 * A Cylinder of unit radius, along the given axis.
 */

solid_t *
Cylinder(axis)
axis_t	axis;
{
	quadric_t	*q;
	real_t		a, e, h;

	q = QuadricZero();

	switch (axis)
	{
	case X_AXIS:
		a = REAL_ZERO;
		e = REAL_ONE;
		h = REAL_ONE;
		break;
	case Y_AXIS:
		a = REAL_ONE;
		e = REAL_ZERO;
		h = REAL_ONE;
		break;
	case Z_AXIS:
		a = REAL_ONE;
		e = REAL_ONE;
		h = REAL_ZERO;
		break;
	default:
		FatalError(__FILE__, __LINE__, "Cylinder: bad axis type");
	}

	QuadricSet(q, QA, a);
	QuadricSet(q, QE, e);
	QuadricSet(q, QH, h);
	QuadricSet(q, QJ, -REAL_ONE);

	return(Solid(q, OTHER));
}


/* Cone
 *
 * A cone with unit slope along the given axis.
 */

solid_t *
Cone(axis)
axis_t	axis;
{
	quadric_t	*q;
	real_t		a, e, h;
	
	q = QuadricZero();

	switch (axis)
	{
	case X_AXIS:
		a = -REAL_ONE;
		e = REAL_ONE;
		h = REAL_ONE;
		break;
	case Y_AXIS:
		a = REAL_ONE;
		e = -REAL_ONE;
		h = REAL_ONE;
		break;
	case Z_AXIS:
		a = REAL_ONE;
		e = REAL_ONE;
		h = -REAL_ONE;
		break;
	default:
		FatalError(__FILE__, __LINE__, "Cone: bad axis type");
	}

	QuadricSet(q, QA, a);
	QuadricSet(q, QE, e);
	QuadricSet(q, QH, h);

	return(Solid(q, OTHER));
}


/* SemiSpace
 *
 * Occupies half of the world.  Its surface lies perpendicular to
 * the specified axis.
 */

solid_t *
SemiSpace(axis)
axis_t	axis;
{
	quadric_t	*q;
	real_t		d, g, i;

	q = QuadricZero();

	switch (axis)
	{
	case X_AXIS:
		d = REAL_ONE;
		g = REAL_ZERO;
		i = REAL_ZERO;
		break;
	case Y_AXIS:
		d = REAL_ZERO;
		g = REAL_ONE;
		i = REAL_ZERO;
		break;
	case Z_AXIS:
		d = REAL_ZERO;
		g = REAL_ZERO;
		i = REAL_ONE;
		break;
	default:
		FatalError(__FILE__, __LINE__, "Plane: bad axis type");
	}

	QuadricSet(q, QD, d);
	QuadricSet(q, QG, g);
	QuadricSet(q, QI, i);

	return(Solid(q, OTHER));
}

/* Plane3
 *
 * A plane specified by three points (it is infinite in extent)
 * the specified axis.
 */

solid_t *
Plane3(point1, point2, point3)
point_t	*point1, *point2, *point3;
{
	quadric_t	*q;
	real_t		A, B, C, D;

	q = QuadricZero();


	A = point1->y * (point2->z - point3->z) +
			point2->y * (point3->z - point1->z) +
			point3->y * (point1->z - point2->z);

	B = -(point1->x * (point2->z - point3->z) +
			  point2->x * (point3->z - point1->z) +
			  point3->x * (point1->z - point2->z));

	C = point1->x * (point2->y - point3->y) +
			point2->x * (point3->y - point1->y) +
			point3->x * (point1->y - point2->y);

	D = -(point1->x * (point2->y*point3->z - point3->y*point2->z) +
			  point2->x * (point3->y*point1->z - point1->y*point3->z) +
			  point3->x * (point1->y*point2->z - point2->y*point1->z));

	QuadricSet(q, QD, A);
	QuadricSet(q, QG, B);
	QuadricSet(q, QI, C);
	QuadricSet(q, QJ, D);

	return(Solid(q, OTHER));
}

solid_t *
Plane4(point1, point2, point3, point4)
point_t	*point1, *point2, *point3, *point4;
{
	solid_t	*solid;

	solid = Plane3(point1, point2, point3);

	if (QuadricInstantiate(solid->body.atom.quadric, point4->x, point4->y, point4->z) > 0)
		solid = SolidNegate(solid);

	return(solid);
}

/* General
 *
 * General shape give access to the full quadric representation.
 */

solid_t	*
General(a, b, c, d, e, f, g, h, i, j)
real_t	a, b, c, d, e, f, g, h, i, j;
{
	return(Solid(Quadric(a, b, c, d, e, f, g, h, i, j), OTHER));
}
