/* Copyright (c) 1986 Regents of the University of California */

#ifndef lint
static char SCCSid[] = "@(#)octree.c 2.1 11/12/91 LBL";
#endif

/*
 *  octree.c - routines dealing with octrees and cubes.
 *
 *     7/28/85
 */

#include  "standard.h"

#include  "octree.h"

OCTREE  *octblock[MAXOBLK];		/* our octree */
static OCTREE  ofreelist = EMPTY;	/* freed octree nodes */
static OCTREE  treetop = 0;		/* next free node */


OCTREE
octalloc()			/* allocate an octree */
{
	register OCTREE  freet;

	if ((freet = ofreelist) != EMPTY) {
		ofreelist = octkid(freet, 0);
		return(freet);
	}
	freet = treetop;
	if (octti(freet) == 0) {
		errno = 0;
		if (octbi(freet) >= MAXOBLK)
			return(EMPTY);
		if ((octblock[octbi(freet)] = (OCTREE *)bmalloc(
				(unsigned)256*8*sizeof(OCTREE))) == NULL)
			return(EMPTY);
	}
	treetop += 8;
	return(freet);
}


octfree(ot)			/* free an octree */
register OCTREE  ot;
{
	register int  i;

	if (!istree(ot))
		return;
	for (i = 0; i < 8; i++)
		octfree(octkid(ot, i));
	octkid(ot, 0) = ofreelist;
	ofreelist = ot;
}


OCTREE
combine(ot)			/* recursively combine nodes */
register OCTREE  ot;
{
	register int  i;
	register OCTREE  ores;

	if (!istree(ot))	/* not a tree */
		return(ot);
	ores = octkid(ot, 0) = combine(octkid(ot, 0));
	for (i = 1; i < 8; i++)
		if ((octkid(ot, i) = combine(octkid(ot, i))) != ores)
			ores = ot;
	if (!istree(ores)) {	/* all were identical leaves */
		octkid(ot, 0) = ofreelist;
		ofreelist = ot;
	}
	return(ores);
}


culocate(cu, pt)		/* locate point within cube */
register CUBE  *cu;
register FVECT  pt;
{
	register int  i;
	int  branch;

	while (istree(cu->cutree)) {
		cu->cusize *= 0.5;
		branch = 0;
		for (i = 0; i < 3; i++)
			if (cu->cuorg[i] + cu->cusize <= pt[i]) {
				cu->cuorg[i] += cu->cusize;
				branch |= 1 << i;
			}
		cu->cutree = octkid(cu->cutree, branch);
	}
}


cucopy(cu1, cu2)		/* copy cu2 into cu1 */
register CUBE  *cu1, *cu2;
{
	cu1->cutree = cu2->cutree;
	cu1->cusize = cu2->cusize;
	VCOPY(cu1->cuorg, cu2->cuorg);
}


incube(cu, pt)			/* determine if a point is inside a cube */
register CUBE  *cu;
register FVECT  pt;
{
	if (cu->cuorg[0] > pt[0] || pt[0] >= cu->cuorg[0] + cu->cusize)
		return(0);
	if (cu->cuorg[1] > pt[1] || pt[1] >= cu->cuorg[1] + cu->cusize)
		return(0);
	if (cu->cuorg[2] > pt[2] || pt[2] >= cu->cuorg[2] + cu->cusize)
		return(0);
	return(1);
}
