blob: cc36b132e20241d02d0df74f9848b75e96c2b14c [file] [log] [blame]
/******************************************************************************
** Filename: kdtree.c
** Purpose: Routines for managing K-D search trees
** Author: Dan Johnson
** History: 3/10/89, DSJ, Created.
** 5/23/89, DSJ, Added circular feature capability.
** 7/13/89, DSJ, Made tree nodes invisible to outside.
**
** (c) Copyright Hewlett-Packard Company, 1988.
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
** http://www.apache.org/licenses/LICENSE-2.0
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
******************************************************************************/
/**----------------------------------------------------------------------------
Include Files and Type Defines
----------------------------------------------------------------------------**/
#include "kdtree.h"
#include "const.h"
#include "emalloc.h"
#include "freelist.h"
#include <stdio.h>
#include <math.h>
#include <setjmp.h>
#define Magnitude(X) ((X) < 0 ? -(X) : (X))
#define MIN(A,B) ((A) < (B) ? (A) : (B))
#define NodeFound(N,K,D) (( (N)->Key == (K) ) && ( (N)->Data == (D) ))
/**----------------------------------------------------------------------------
Global Data Definitions and Declarations
----------------------------------------------------------------------------**/
#define MINSEARCH -MAX_FLOAT32
#define MAXSEARCH MAX_FLOAT32
static int NumberOfNeighbors;
static inT16 N; /* number of dimensions in the kd tree */
static FLOAT32 *QueryPoint;
static int MaxNeighbors;
static FLOAT32 Radius;
static int Furthest;
static char **Neighbor;
static FLOAT32 *Distance;
static int MaxDimension = 0;
static FLOAT32 *SBMin;
static FLOAT32 *SBMax;
static FLOAT32 *LBMin;
static FLOAT32 *LBMax;
static PARAM_DESC *KeyDesc;
static jmp_buf QuickExit;
static void_proc WalkAction;
// Helper function to find the next essential dimension in a cycle.
static int NextLevel(int level) {
do {
++level;
if (level >= N)
level = 0;
} while (KeyDesc[level].NonEssential);
return level;
}
// Helper function to find the previous essential dimension in a cycle.
static int PrevLevel(int level) {
do {
--level;
if (level < 0)
level = N - 1;
} while (KeyDesc[level].NonEssential);
return level;
}
/**----------------------------------------------------------------------------
Public Code
----------------------------------------------------------------------------**/
/*---------------------------------------------------------------------------*/
KDTREE *
MakeKDTree (inT16 KeySize, PARAM_DESC KeyDesc[]) {
/*
** Parameters:
** KeySize # of dimensions in the K-D tree
** KeyDesc array of params to describe key dimensions
** Globals:
** MaxDimension largest # of dimensions in any K-D tree
** SBMin small search region box
** SBMax
** LBMin large search region box
** LBMax
** Key description of key dimensions
** Operation:
** This routine allocates and returns a new K-D tree data
** structure. It also reallocates the small and large
** search region boxes if they are not large enough to
** accomodate the size of the new K-D tree. KeyDesc is
** an array of key descriptors that indicate which dimensions
** are circular and, if they are circular, what the range is.
** Return:
** Pointer to new K-D tree
** Exceptions:
** None
** History:
** 3/13/89, DSJ, Created.
*/
int i;
void *NewMemory;
KDTREE *KDTree;
if (KeySize > MaxDimension) {
NewMemory = Emalloc (KeySize * 4 * sizeof (FLOAT32));
if (MaxDimension > 0) {
memfree ((char *) SBMin);
memfree ((char *) SBMax);
memfree ((char *) LBMin);
memfree ((char *) LBMax);
}
SBMin = (FLOAT32 *) NewMemory;
SBMax = SBMin + KeySize;
LBMin = SBMax + KeySize;
LBMax = LBMin + KeySize;
}
KDTree =
(KDTREE *) Emalloc (sizeof (KDTREE) +
(KeySize - 1) * sizeof (PARAM_DESC));
for (i = 0; i < KeySize; i++) {
KDTree->KeyDesc[i].NonEssential = KeyDesc[i].NonEssential;
KDTree->KeyDesc[i].Circular = KeyDesc[i].Circular;
if (KeyDesc[i].Circular) {
KDTree->KeyDesc[i].Min = KeyDesc[i].Min;
KDTree->KeyDesc[i].Max = KeyDesc[i].Max;
KDTree->KeyDesc[i].Range = KeyDesc[i].Max - KeyDesc[i].Min;
KDTree->KeyDesc[i].HalfRange = KDTree->KeyDesc[i].Range / 2;
KDTree->KeyDesc[i].MidRange = (KeyDesc[i].Max + KeyDesc[i].Min) / 2;
}
else {
KDTree->KeyDesc[i].Min = MINSEARCH;
KDTree->KeyDesc[i].Max = MAXSEARCH;
}
}
KDTree->KeySize = KeySize;
KDTree->Root.Left = NULL;
KDTree->Root.Right = NULL;
return (KDTree);
} /* MakeKDTree */
/*---------------------------------------------------------------------------*/
void KDStore(KDTREE *Tree, FLOAT32 *Key, void *Data) {
/*
** Parameters:
** Tree K-D tree in which data is to be stored
** Key ptr to key by which data can be retrieved
** Data ptr to data to be stored in the tree
** Globals:
** N dimension of the K-D tree
** KeyDesc descriptions of tree dimensions
** StoreCount debug variables for performance tests
** StoreUniqueCount
** StoreProbeCount
** Operation:
** This routine stores Data in the K-D tree specified by Tree
** using Key as an access key.
** Return: none
** Exceptions: none
** History: 3/10/89, DSJ, Created.
** 7/13/89, DSJ, Changed return to void.
*/
int Level;
KDNODE *Node;
KDNODE **PtrToNode;
N = Tree->KeySize;
KeyDesc = &(Tree->KeyDesc[0]);
PtrToNode = &(Tree->Root.Left);
Node = *PtrToNode;
Level = NextLevel(-1);
while (Node != NULL) {
if (Key[Level] < Node->BranchPoint) {
PtrToNode = &(Node->Left);
if (Key[Level] > Node->LeftBranch)
Node->LeftBranch = Key[Level];
}
else {
PtrToNode = &(Node->Right);
if (Key[Level] < Node->RightBranch)
Node->RightBranch = Key[Level];
}
Level = NextLevel(Level);
Node = *PtrToNode;
}
*PtrToNode = MakeKDNode (Key, (char *) Data, Level);
} /* KDStore */
/*---------------------------------------------------------------------------*/
void
KDDelete (KDTREE * Tree, FLOAT32 Key[], void *Data) {
/*
** Parameters:
** Tree K-D tree to delete node from
** Key key of node to be deleted
** Data data contents of node to be deleted
** Globals:
** N dimension of the K-D tree
** KeyDesc description of each dimension
** DeleteCount debug variables for performance tests
** DeleteProbeCount
** Operation:
** This routine deletes a node from Tree. The node to be
** deleted is specified by the Key for the node and the Data
** contents of the node. These two pointers must be identical
** to the pointers that were used for the node when it was
** originally stored in the tree. A node will be deleted from
** the tree only if its key and data pointers are identical
** to Key and Data respectively. The empty space left in the tree
** is filled by pulling a leaf up from the bottom of one of
** the subtrees of the node being deleted. The leaf node will
** be pulled from left subtrees whenever possible (this was
** an arbitrary decision). No attempt is made to pull the leaf
** from the deepest subtree (to minimize length). The branch
** point for the replacement node is changed to be the same as
** the branch point of the deleted node. This keeps us from
** having to rearrange the tree every time we delete a node.
** Also, the LeftBranch and RightBranch numbers of the
** replacement node are set to be the same as the deleted node.
** The makes the delete easier and more efficient, but it may
** make searches in the tree less efficient after many nodes are
** deleted. If the node specified by Key and Data does not
** exist in the tree, then nothing is done.
** Return: none
** None
** Exceptions: none
** None
** History: 3/13/89, DSJ, Created.
** 7/13/89, DSJ, Specify node indirectly by key and data.
*/
int Level;
KDNODE *Current;
KDNODE *Father;
KDNODE *Replacement;
KDNODE *FatherReplacement;
/* initialize search at root of tree */
N = Tree->KeySize;
KeyDesc = &(Tree->KeyDesc[0]);
Father = &(Tree->Root);
Current = Father->Left;
Level = NextLevel(-1);
/* search tree for node to be deleted */
while ((Current != NULL) && (!NodeFound (Current, Key, Data))) {
Father = Current;
if (Key[Level] < Current->BranchPoint)
Current = Current->Left;
else
Current = Current->Right;
Level = NextLevel(Level);
}
if (Current != NULL) { /* if node to be deleted was found */
Replacement = Current;
FatherReplacement = Father;
/* search for replacement node (a leaf under node to be deleted */
while (TRUE) {
if (Replacement->Left != NULL) {
FatherReplacement = Replacement;
Replacement = Replacement->Left;
}
else if (Replacement->Right != NULL) {
FatherReplacement = Replacement;
Replacement = Replacement->Right;
}
else
break;
Level = NextLevel(Level);
}
/* compute level of replacement node's father */
Level = PrevLevel(Level);
/* disconnect replacement node from it's father */
if (FatherReplacement->Left == Replacement) {
FatherReplacement->Left = NULL;
FatherReplacement->LeftBranch = KeyDesc[Level].Min;
}
else {
FatherReplacement->Right = NULL;
FatherReplacement->RightBranch = KeyDesc[Level].Max;
}
/* replace deleted node with replacement (unless they are the same) */
if (Replacement != Current) {
Replacement->BranchPoint = Current->BranchPoint;
Replacement->LeftBranch = Current->LeftBranch;
Replacement->RightBranch = Current->RightBranch;
Replacement->Left = Current->Left;
Replacement->Right = Current->Right;
if (Father->Left == Current)
Father->Left = Replacement;
else
Father->Right = Replacement;
}
FreeKDNode(Current);
}
} /* KDDelete */
/*---------------------------------------------------------------------------*/
int
KDNearestNeighborSearch (KDTREE * Tree,
FLOAT32 Query[],
int QuerySize,
FLOAT32 MaxDistance,
void *NBuffer, FLOAT32 DBuffer[]) {
/*
** Parameters:
** Tree ptr to K-D tree to be searched
** Query ptr to query key (point in D-space)
** QuerySize number of nearest neighbors to be found
** MaxDistance all neighbors must be within this distance
** NBuffer ptr to QuerySize buffer to hold nearest neighbors
** DBuffer ptr to QuerySize buffer to hold distances
** from nearest neighbor to query point
** Globals:
** NumberOfNeighbors # of neighbors found so far
** N # of features in each key
** KeyDesc description of tree dimensions
** QueryPoint point in D-space to find neighbors of
** MaxNeighbors maximum # of neighbors to find
** Radius current distance of furthest neighbor
** Furthest index of furthest neighbor
** Neighbor buffer of current neighbors
** Distance buffer of neighbor distances
** SBMin lower extent of small search region
** SBMax upper extent of small search region
** LBMin lower extent of large search region
** LBMax upper extent of large search region
** QuickExit quick exit from recursive search
** Operation:
** This routine searches the K-D tree specified by Tree and
** finds the QuerySize nearest neighbors of Query. All neighbors
** must be within MaxDistance of Query. The data contents of
** the nearest neighbors
** are placed in NBuffer and their distances from Query are
** placed in DBuffer.
** Return: Number of nearest neighbors actually found
** Exceptions: none
** History:
** 3/10/89, DSJ, Created.
** 7/13/89, DSJ, Return contents of node instead of node itself.
*/
int i;
NumberOfNeighbors = 0;
N = Tree->KeySize;
KeyDesc = &(Tree->KeyDesc[0]);
QueryPoint = Query;
MaxNeighbors = QuerySize;
Radius = MaxDistance;
Furthest = 0;
Neighbor = (char **) NBuffer;
Distance = DBuffer;
for (i = 0; i < N; i++) {
SBMin[i] = KeyDesc[i].Min;
SBMax[i] = KeyDesc[i].Max;
LBMin[i] = KeyDesc[i].Min;
LBMax[i] = KeyDesc[i].Max;
}
if (Tree->Root.Left != NULL) {
if (setjmp (QuickExit) == 0)
Search (0, Tree->Root.Left);
}
return (NumberOfNeighbors);
} /* KDNearestNeighborSearch */
/*---------------------------------------------------------------------------*/
void KDWalk(KDTREE *Tree, void_proc Action) {
/*
** Parameters:
** Tree ptr to K-D tree to be walked
** Action ptr to function to be executed at each node
** Globals:
** WalkAction action to be performed at every node
** Operation:
** This routine stores the desired action in a global
** variable and starts a recursive walk of Tree. The walk
** is started at the root node.
** Return:
** None
** Exceptions:
** None
** History:
** 3/13/89, DSJ, Created.
*/
WalkAction = Action;
if (Tree->Root.Left != NULL)
Walk (Tree->Root.Left, NextLevel(-1));
} /* KDWalk */
/*---------------------------------------------------------------------------*/
void FreeKDTree(KDTREE *Tree) {
/*
** Parameters:
** Tree tree data structure to be released
** Globals: none
** Operation:
** This routine frees all memory which is allocated to the
** specified KD-tree. This includes the data structure for
** the kd-tree itself plus the data structures for each node
** in the tree. It does not include the Key and Data items
** which are pointed to by the nodes. This memory is left
** untouched.
** Return: none
** Exceptions: none
** History:
** 5/26/89, DSJ, Created.
*/
FreeSubTree (Tree->Root.Left);
memfree(Tree);
} /* FreeKDTree */
/**----------------------------------------------------------------------------
Private Code
----------------------------------------------------------------------------**/
/*---------------------------------------------------------------------------*/
int
Equal (FLOAT32 Key1[], FLOAT32 Key2[]) {
/*
** Parameters:
** Key1,Key2 search keys to be compared for equality
** Globals:
** N number of parameters per key
** Operation:
** This routine returns TRUE if Key1 = Key2.
** Return:
** TRUE if Key1 = Key2, else FALSE.
** Exceptions:
** None
** History:
** 3/11/89, DSJ, Created.
*/
int i;
for (i = N; i > 0; i--, Key1++, Key2++)
if (*Key1 != *Key2)
return (FALSE);
return (TRUE);
} /* Equal */
/*---------------------------------------------------------------------------*/
KDNODE *
MakeKDNode (FLOAT32 Key[], char *Data, int Index) {
/*
** Parameters:
** Key Access key for new node in KD tree
** Data ptr to data to be stored in new node
** Index index of Key to branch on
** Globals:
** KeyDesc descriptions of key dimensions
** Operation:
** This routine allocates memory for a new K-D tree node
** and places the specified Key and Data into it. The
** left and right subtree pointers for the node are
** initialized to empty subtrees.
** Return:
** pointer to new K-D tree node
** Exceptions:
** None
** History:
** 3/11/89, DSJ, Created.
*/
KDNODE *NewNode;
NewNode = (KDNODE *) Emalloc (sizeof (KDNODE));
NewNode->Key = Key;
NewNode->Data = Data;
NewNode->BranchPoint = Key[Index];
NewNode->LeftBranch = KeyDesc[Index].Min;
NewNode->RightBranch = KeyDesc[Index].Max;
NewNode->Left = NULL;
NewNode->Right = NULL;
return (NewNode);
} /* MakeKDNode */
/*---------------------------------------------------------------------------*/
void FreeKDNode(KDNODE *Node) {
/*
** Parameters:
** Node ptr to node data structure to be freed
** Globals:
** None
** Operation:
** This routine frees up the memory allocated to Node.
** Return:
** None
** Exceptions:
** None
** History:
** 3/13/89, DSJ, Created.
*/
memfree ((char *) Node);
} /* FreeKDNode */
/*---------------------------------------------------------------------------*/
void Search(int Level, KDNODE *SubTree) {
/*
** Parameters:
** Level level in tree of sub-tree to be searched
** SubTree sub-tree to be searched
** Globals:
** NumberOfNeighbors # of neighbors found so far
** N # of features in each key
** KeyDesc description of key dimensions
** QueryPoint point in D-space to find neighbors of
** MaxNeighbors maximum # of neighbors to find
** Radius current distance of furthest neighbor
** Furthest index of furthest neighbor
** Neighbor buffer of current neighbors
** Distance buffer of neighbor distances
** SBMin lower extent of small search region
** SBMax upper extent of small search region
** LBMin lower extent of large search region
** LBMax upper extent of large search region
** QuickExit quick exit from recursive search
** Operation:
** This routine searches SubTree for those entries which are
** possibly among the MaxNeighbors nearest neighbors of the
** QueryPoint and places their data in the Neighbor buffer and
** their distances from QueryPoint in the Distance buffer.
** Return: none
** Exceptions: none
** History:
** 3/11/89, DSJ, Created.
** 7/13/89, DSJ, Save node contents, not node, in neighbor buffer
*/
FLOAT32 d;
FLOAT32 OldSBoxEdge;
FLOAT32 OldLBoxEdge;
if (Level >= N)
Level = 0;
d = ComputeDistance (N, KeyDesc, QueryPoint, SubTree->Key);
if (d < Radius) {
if (NumberOfNeighbors < MaxNeighbors) {
Neighbor[NumberOfNeighbors] = SubTree->Data;
Distance[NumberOfNeighbors] = d;
NumberOfNeighbors++;
if (NumberOfNeighbors == MaxNeighbors)
FindMaxDistance();
}
else {
Neighbor[Furthest] = SubTree->Data;
Distance[Furthest] = d;
FindMaxDistance();
}
}
if (QueryPoint[Level] < SubTree->BranchPoint) {
OldSBoxEdge = SBMax[Level];
SBMax[Level] = SubTree->LeftBranch;
OldLBoxEdge = LBMax[Level];
LBMax[Level] = SubTree->RightBranch;
if (SubTree->Left != NULL)
Search (NextLevel(Level), SubTree->Left);
SBMax[Level] = OldSBoxEdge;
LBMax[Level] = OldLBoxEdge;
OldSBoxEdge = SBMin[Level];
SBMin[Level] = SubTree->RightBranch;
OldLBoxEdge = LBMin[Level];
LBMin[Level] = SubTree->LeftBranch;
if ((SubTree->Right != NULL) && QueryIntersectsSearch ())
Search (NextLevel(Level), SubTree->Right);
SBMin[Level] = OldSBoxEdge;
LBMin[Level] = OldLBoxEdge;
}
else {
OldSBoxEdge = SBMin[Level];
SBMin[Level] = SubTree->RightBranch;
OldLBoxEdge = LBMin[Level];
LBMin[Level] = SubTree->LeftBranch;
if (SubTree->Right != NULL)
Search (NextLevel(Level), SubTree->Right);
SBMin[Level] = OldSBoxEdge;
LBMin[Level] = OldLBoxEdge;
OldSBoxEdge = SBMax[Level];
SBMax[Level] = SubTree->LeftBranch;
OldLBoxEdge = LBMax[Level];
LBMax[Level] = SubTree->RightBranch;
if ((SubTree->Left != NULL) && QueryIntersectsSearch ())
Search (NextLevel(Level), SubTree->Left);
SBMax[Level] = OldSBoxEdge;
LBMax[Level] = OldLBoxEdge;
}
if (QueryInSearch ())
longjmp (QuickExit, 1);
} /* Search */
/*---------------------------------------------------------------------------*/
FLOAT32
ComputeDistance (register int N,
register PARAM_DESC Dim[],
register FLOAT32 p1[], register FLOAT32 p2[]) {
/*
** Parameters:
** N number of dimensions in K-D space
** Dim descriptions of each dimension
** p1,p2 two different points in K-D space
** Globals:
** None
** Operation:
** This routine computes the euclidian distance
** between p1 and p2 in K-D space (an N dimensional space).
** Return:
** Distance between p1 and p2.
** Exceptions:
** None
** History:
** 3/11/89, DSJ, Created.
*/
register FLOAT32 TotalDistance;
register FLOAT32 DimensionDistance;
FLOAT32 WrapDistance;
TotalDistance = 0;
for (; N > 0; N--, p1++, p2++, Dim++) {
if (Dim->NonEssential)
continue;
DimensionDistance = *p1 - *p2;
/* if this dimension is circular - check wraparound distance */
if (Dim->Circular) {
DimensionDistance = Magnitude (DimensionDistance);
WrapDistance = Dim->Max - Dim->Min - DimensionDistance;
DimensionDistance = MIN (DimensionDistance, WrapDistance);
}
TotalDistance += DimensionDistance * DimensionDistance;
}
return ((FLOAT32) sqrt ((FLOAT64) TotalDistance));
} /* ComputeDistance */
/*---------------------------------------------------------------------------*/
void FindMaxDistance() {
/*
** Parameters:
** None
** Globals:
** MaxNeighbors maximum # of neighbors to find
** Radius current distance of furthest neighbor
** Furthest index of furthest neighbor
** Distance buffer of neighbor distances
** Operation:
** This routine searches the Distance buffer for the maximum
** distance, places this distance in Radius, and places the
** index of this distance in Furthest.
** Return:
** None
** Exceptions:
** None
** History:
** 3/11/89, DSJ, Created.
*/
int i;
Radius = Distance[Furthest];
for (i = 0; i < MaxNeighbors; i++) {
if (Distance[i] > Radius) {
Radius = Distance[i];
Furthest = i;
}
}
} /* FindMaxDistance */
/*---------------------------------------------------------------------------*/
int QueryIntersectsSearch() {
/*
** Parameters:
** None
** Globals:
** N # of features in each key
** KeyDesc descriptions of each dimension
** QueryPoint point in D-space to find neighbors of
** Radius current distance of furthest neighbor
** SBMin lower extent of small search region
** SBMax upper extent of small search region
** Operation:
** This routine returns TRUE if the query region intersects
** the current smallest search region. The query region is
** the circle of radius Radius centered at QueryPoint.
** The smallest search region is the box (in N dimensions)
** whose edges in each dimension are specified by SBMin and SBMax.
** In the case of circular dimensions, we must also check the
** point which is one wrap-distance away from the query to
** see if it would intersect the search region.
** Return:
** TRUE if query region intersects search region, else FALSE
** Exceptions:
** None
** History:
** 3/11/89, DSJ, Created.
*/
register int i;
register FLOAT32 *Query;
register FLOAT32 *Lower;
register FLOAT32 *Upper;
register FLOAT64 TotalDistance;
register FLOAT32 DimensionDistance;
register FLOAT64 RadiusSquared;
register PARAM_DESC *Dim;
register FLOAT32 WrapDistance;
RadiusSquared = Radius * Radius;
Query = QueryPoint;
Lower = SBMin;
Upper = SBMax;
TotalDistance = 0.0;
Dim = KeyDesc;
for (i = N; i > 0; i--, Dim++, Query++, Lower++, Upper++) {
if (Dim->NonEssential)
continue;
if (*Query < *Lower)
DimensionDistance = *Lower - *Query;
else if (*Query > *Upper)
DimensionDistance = *Query - *Upper;
else
DimensionDistance = 0;
/* if this dimension is circular - check wraparound distance */
if (Dim->Circular) {
if (*Query < *Lower)
WrapDistance = *Query + Dim->Max - Dim->Min - *Upper;
else if (*Query > *Upper)
WrapDistance = *Lower - (*Query - (Dim->Max - Dim->Min));
else
WrapDistance = MAX_FLOAT32;
DimensionDistance = MIN (DimensionDistance, WrapDistance);
}
TotalDistance += DimensionDistance * DimensionDistance;
if (TotalDistance >= RadiusSquared)
return (FALSE);
}
return (TRUE);
} /* QueryIntersectsSearch */
/*---------------------------------------------------------------------------*/
int QueryInSearch() {
/*
** Parameters:
** None
** Globals:
** N # of features in each key
** KeyDesc descriptions of each dimension
** QueryPoint point in D-space to find neighbors of
** Radius current distance of furthest neighbor
** LBMin lower extent of large search region
** LBMax upper extent of large search region
** Operation:
** This routine returns TRUE if the current query region is
** totally contained in the current largest search region.
** The query region is the circle of
** radius Radius centered at QueryPoint. The search region is
** the box (in N dimensions) whose edges in each
** dimension are specified by LBMin and LBMax.
** Return:
** TRUE if query region is inside search region, else FALSE
** Exceptions:
** None
** History:
** 3/11/89, DSJ, Created.
*/
register int i;
register FLOAT32 *Query;
register FLOAT32 *Lower;
register FLOAT32 *Upper;
register PARAM_DESC *Dim;
Query = QueryPoint;
Lower = LBMin;
Upper = LBMax;
Dim = KeyDesc;
for (i = N - 1; i >= 0; i--, Dim++, Query++, Lower++, Upper++) {
if (Dim->NonEssential)
continue;
if ((*Query < *Lower + Radius) || (*Query > *Upper - Radius))
return (FALSE);
}
return (TRUE);
} /* QueryInSearch */
/*---------------------------------------------------------------------------*/
void Walk(KDNODE *SubTree, inT32 Level) {
/*
** Parameters:
** SubTree ptr to root of subtree to be walked
** Level current level in the tree for this node
** Globals:
** WalkAction action to be performed at every node
** Operation:
** This routine walks thru the specified SubTree and invokes
** WalkAction at each node. WalkAction is invoked with three
** arguments as follows:
** WalkAction( NodeData, Order, Level )
** Data is the data contents of the node being visited,
** Order is either preorder,
** postorder, endorder, or leaf depending on whether this is
** the 1st, 2nd, or 3rd time a node has been visited, or
** whether the node is a leaf. Level is the level of the node in
** the tree with the root being level 0.
** Return: none
** Exceptions: none
** History:
** 3/13/89, DSJ, Created.
** 7/13/89, DSJ, Pass node contents, not node, to WalkAction().
*/
if ((SubTree->Left == NULL) && (SubTree->Right == NULL))
(*WalkAction) (SubTree->Data, leaf, Level);
else {
(*WalkAction) (SubTree->Data, preorder, Level);
if (SubTree->Left != NULL)
Walk (SubTree->Left, NextLevel(Level));
(*WalkAction) (SubTree->Data, postorder, Level);
if (SubTree->Right != NULL)
Walk (SubTree->Right, NextLevel(Level));
(*WalkAction) (SubTree->Data, endorder, Level);
}
} /* Walk */
/*---------------------------------------------------------------------------*/
void FreeSubTree(KDNODE *SubTree) {
/*
** Parameters:
** SubTree ptr to root node of sub-tree to be freed
** Globals: none
** Operation:
** This routine recursively frees the memory allocated to
** to the specified subtree.
** Return: none
** Exceptions: none
** History: 7/13/89, DSJ, Created.
*/
if (SubTree != NULL) {
FreeSubTree (SubTree->Left);
FreeSubTree (SubTree->Right);
memfree(SubTree);
}
} /* FreeSubTree */