home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Resource Library: Graphics
/
graphics-16000.iso
/
general
/
raytrace
/
renaisnc
/
delaunay.lha
/
Delaunay
/
k-Dtree.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-01-04
|
9KB
|
354 lines
/**
** Maintain k-D tree
**/
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include "k-Dtree.h"
#ifndef TRUE
# define TRUE 1
# define FALSE 0
#endif
/*
** Test to see if two rectangles overlap. Return TRUE if the do, FALSE
** otherwise.
*/
#define RectOverlap(Rect1,Rect2) \
( ! ( (Rect1)->xH < (Rect2)->xL || (Rect2)->xH < (Rect1)->xL || \
(Rect1)->yH < (Rect2)->yL || (Rect2)->yH < (Rect1)->yL ))
/*------------------------------------
Check to see if the point X,Y is in
the rectangle Rect.
------------------------------------*/
#define PointInRectangle(Xs,Ys,Rect) \
( ((Xs) >= (Rect)->xL) && ((Xs) < (Rect)->xH) && \
((Ys) >= (Rect)->yL) && ((Ys) < (Rect)->yH) )
/* Number of nodes/samples to allocate at a time */
#define GLOB_SIZE 1024
/*----------------------------------------
Subdivision level
--------------------------------------*/
static
int level;
int AdaptiveSplits = FALSE;
int Animating = FALSE;
HierarchicalRegion Root;
RectType RootBoundary;
extern double atof();
extern HierarchicalRegion *PropagateSample();
/* --------------------------------------------------------------------------
Split a node boundary rectangle into the rectangle for the Left
(if LeftOrRight == TRUE) or Right (if LeftOrRight == FALSE) subnode.
---------------------------------------------------------------------------*/
SplitBoundary(LeftOrRight, splitDirection, splitValue,
OldBoundary, NewBoundary)
int LeftOrRight;
double splitValue;
RectType *OldBoundary, *NewBoundary;
{
double Xs, Ys;
*NewBoundary = *OldBoundary;
if ( splitDirection ) /* Odd levels split in X */
{ /* Split in X */
Xs = splitValue;
if (LeftOrRight) { /* Left Child */
NewBoundary->xH = Xs;
} else { /* Right child */
NewBoundary->xL = Xs;
}
}
else
{ /* Split in Y */
Ys = splitValue;
if (LeftOrRight) { /* Left Child */
NewBoundary->yH = Ys;
} else { /* Right Child */
NewBoundary->yL = Ys;
}
}
}
/*-----------------------
allocate a node
----------------------*/
static
HierarchicalRegion *
CreateNode()
{
char *calloc();
static HierarchicalRegion *FreeNodes;
static nFreeNodes = 0;
if (nFreeNodes <= 0) {
FreeNodes = (HierarchicalRegion *)
calloc( GLOB_SIZE, sizeof(HierarchicalRegion));
if(FreeNodes == NULL)
{
fprintf(stderr,"Fatal error - Can't allocate nodes\n");
abort();
}
nFreeNodes = GLOB_SIZE;
}
return &(FreeNodes[--nFreeNodes]);
}
static SampleData *SampleFreeList = NULL;
FreeSample( Sample )
SampleData *Sample;
{
/* Link the sample onto the free list */
*( (SampleData **) Sample) = SampleFreeList;
SampleFreeList = Sample;
}
SampleData *CreateSample()
{
char *calloc();
static SampleData *FreeSamples, *Sample;
static int nFreeSamples = 0;
/* Get one off the free list if possible */
if (SampleFreeList != NULL) {
Sample = SampleFreeList;
SampleFreeList = *( (SampleData **) SampleFreeList );
bzero ( Sample, sizeof(SampleData) );
return Sample;
}
if (nFreeSamples <= 0) {
FreeSamples = (SampleData *) calloc( GLOB_SIZE, sizeof(SampleData));
if(FreeSamples == NULL)
{
fprintf(stderr,"Fatal error - Can't allocate sample data\n");
abort();
}
nFreeSamples = GLOB_SIZE;
}
return & (FreeSamples[--nFreeSamples]);
}
/* Split a node into two subnodes */
SplitNode(Node)
HierarchicalRegion *Node;
{
Node->Left = CreateNode();
Node->Right = CreateNode();
}
/*-----------------------------
propagate the current node's
sample to one of the subnodes
return the EMPTY SUBNODE
---------------------------*/
HierarchicalRegion *PropagateSample(Node, Boundary, NewSample)
HierarchicalRegion *Node;
RectType *Boundary;
SampleData *NewSample;
{
RectType LeftBoundary;
double dx, dy;
if (AdaptiveSplits) {
/** Choose a split direction which separates the new sample
** from the old and maintains an aspect ratio as close to square
** as possible for the new sub cells.
*/
double xsplit, ysplit, x1, x2, y1, y2, xratio, xratio2, yratio, yratio2;
double width, height;
/* Split at the mid point between samples */
xsplit = 0.5*(Node->Sample->Xs + NewSample->Xs);
ysplit = 0.5*(Node->Sample->Ys + NewSample->Ys);
/* These are the side lengths of the sub cells */
x1 = xsplit - Boundary->xL;
x2 = Boundary->xH - xsplit;
y1 = ysplit - Boundary->yL;
y2 = Boundary->yH - ysplit;
/* These are the side lengths of the whole cell */
width = (Boundary->xH - Boundary->xL);
height = (Boundary->yH - Boundary->yL);
/* These are the aspect ratios if we split in x */
if (x1 > height)
xratio = (height < 1.0E-20) ? 1.0E20 : x1 / height;
else
xratio = (x1 < 1.0E-20) ? 1.0E20 : height / x1;
if (x2 > height)
xratio2 = (height < 1.0E-20) ? 1.0E20 : x2 / height;
else
xratio2 = (x2 < 1.0E-20) ? 1.0E20 : height / x2;
/* Use the worst of the two for comparison */
if (xratio2 > xratio) xratio = xratio2;
/* These are the aspect ratios if we split in y */
if (y1 > width)
yratio = (width < 1.0E-20) ? 1.0E20 : y1 / width;
else
yratio = (y1 < 1.0E-20) ? 1.0E20 : width / y1;
if (y2 > width)
yratio2 = (width < 1.0E-20) ? 1.0E20 : y2 / width;
else
yratio2 = (y2 < 1.0E-20) ? 1.0E20 : width / y2;
/* Use the worst of the two for comparison */
if (yratio2 > yratio) yratio = yratio2;
if (xratio < yratio) { /* X split is better */
Node->splitDirection = 1; /* Split in X */
Node->splitValue = 0.5*(Node->Sample->Xs + NewSample->Xs);
} else {
Node->splitDirection = 0; /* Split in Y */
Node->splitValue = 0.5*(Node->Sample->Ys + NewSample->Ys);
}
} else {
Node->splitDirection = (level & 1); /* Odd levels split in X */
if (Node->splitDirection)
Node->splitValue = 0.5*(Boundary->xL + Boundary->xH);
else
Node->splitValue = 0.5*(Boundary->yL + Boundary->yH);
}
SplitBoundary( TRUE, Node->splitDirection, Node->splitValue,
Boundary, &LeftBoundary );
if( (Node->Sample->Xs >= LeftBoundary.xL) &&
(Node->Sample->Xs < LeftBoundary.xH) &&
(Node->Sample->Ys >= LeftBoundary.yL) &&
(Node->Sample->Ys < LeftBoundary.yH) )
{
Node->Left->Sample = Node->Sample;
return Node->Right;
}
else
{
Node->Right->Sample = Node->Sample;
return Node->Left;
}
}
/*---------------------------------
Insert the new node in the tree.
----------------------------------*/
InsertNode(NewSample, Root, RootBoundary, InterestingBoundary)
SampleData *NewSample;
HierarchicalRegion *Root;
RectType *RootBoundary, *InterestingBoundary;
{
HierarchicalRegion *Node = Root, *EmptyNode;
RectType Boundarys[2], *Boundary, *NewBoundary;
int old, new;
Boundarys[0] = *RootBoundary;
old = 0; new = 1;
Boundary = Boundarys+0;
NewBoundary = Boundarys+1;
/* Search down to the leaf level for the cell this sample belongs in */
level = 0;
while (!IsLeaf(Node))
{
if (!RectOverlap( InterestingBoundary, Boundary )) {
/* Not in an interesting part of the image, ignore it */
FreeSample( NewSample );
return;
}
SplitBoundary( TRUE, Node->splitDirection, Node->splitValue,
Boundary, NewBoundary );
if (PointInRectangle( NewSample->Xs, NewSample->Ys, NewBoundary )) {
Node = Node->Left;
} else {
SplitBoundary( FALSE, Node->splitDirection, Node->splitValue,
Boundary, NewBoundary );
Node = Node->Right;
}
old = (old +1) %2;
new = (new +1) %2;
Boundary = Boundarys+old;
NewBoundary = Boundarys+new;
level++;
}
/* Split the Node */
SplitNode( Node );
/* Fill in the two new cells */
EmptyNode = PropagateSample(Node, Boundary, NewSample);
EmptyNode->Sample = NewSample;
AnimateShadeCell( Boundary, NewSample );
}
/*-----------------------
Initialize samples
----------------------*/
InitializeTree( xL, yL, xH, yH )
float xL, yL, xH, yH;
{
RootBoundary.xL = xL;
RootBoundary.yL = yL;
RootBoundary.xH = xH;
RootBoundary.yH = yH;
Root.Left = Root.Right = (HierarchicalRegion *) NULL;
Root.Sample = NULL;
}
AddSampleToTree( x, y, index )
float x,y;
long index;
{
if (Root.Sample == NULL)
{
Root.Sample = CreateSample();
Root.Sample->Xs = x;
Root.Sample->Ys = y;
Root.Sample->index = index;
}
else
{
SampleData *Sample = CreateSample();
Sample->Xs = x;
Sample->Ys = y;
Sample->index = index;
/* Insert this node in the tree */
InsertNode( Sample, &Root, &RootBoundary, &RootBoundary );
}
}