rtree implement code


空间树rtree原理见: rtree原理

rtree的原始论文下载:R-trees a dynamic index structure for spatial searching


rtree的代码根据the GRASS Development Team的原始代码整理, 原来的多个文件合并成了现在的两个文件,

向先行者致敬!


rtree.h

/****************************************************************************
* MODULE:       R-Tree library 
*              
* AUTHOR(S):    Antonin Guttman - original code
*               Daniel Green (green@superliminal.com) - major clean-up
*                               and implementation of bounding spheres
*               
* PURPOSE:      Multidimensional index
*
* COPYRIGHT:    (C) 2001 by the GRASS Development Team
*
*               This program is free software under the GNU General Public
*               License (>=v2). Read the file COPYING that comes with GRASS
*               for details.
*
* LAST MODIFICATION: Hyforthy 2013
*****************************************************************************/
#ifndef __RTREE_H__
#define __RTREE_H__

#define NUMDIMS	3		/* number of dimensions */
#define NUMSIDES 2*NUMDIMS

/* typedef float RectReal; */
typedef double RectReal;

struct Rect
{
    RectReal boundary[NUMSIDES];	/* xmin,ymin,...,xmax,ymax,... */
};

struct Node;

typedef int (*SearchHitCallback) (int id, void *arg);



struct Node *RTreeNewIndex(void);

int RTreeSearch(struct Node *, struct Rect *, SearchHitCallback, void *);

int RTreeInsertRect(struct Rect *, int, struct Node **, int depth);

int RTreeDeleteRect(struct Rect *, int, struct Node **);

void RTreeDestroyNode(struct Node *);

#endif

rtree.c

/****************************************************************************
* MODULE:       R-Tree library 
*              
* AUTHOR(S):    Antonin Guttman - original code
*               Daniel Green (green@superliminal.com) - major clean-up
*                               and implementation of bounding spheres
*               
* PURPOSE:      Multidimensional index
*
* COPYRIGHT:    (C) 2001 by the GRASS Development Team
*
*               This program is free software under the GNU General Public
*               License (>=v2). Read the file COPYING that comes with GRASS
*               for details.
*
* LAST MODIFICATION: Hyforthy 2013
*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "assert.h"
#include "rtree.h"

/*-----------------------------------------------------------------------------
| Definitions and global variables.
-----------------------------------------------------------------------------*/

#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif

#define METHODS 1
#define BIG_NUM (FLT_MAX/4.0)


#define Undefined(x) ((x)->boundary[0] > (x)->boundary[NUMDIMS])
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))


/* PGSIZE is normally the natural page size of the machine */
#define PGSIZE	512

struct Branch
{
    struct Rect rect;
    struct Node *child;
};

/* max branching factor of a node */
#define MAXCARD (int)((PGSIZE-(2*sizeof(int))) / sizeof(struct Branch))

struct Node
{
    int count;
    int level;			/* 0 is leaf, others positive */
    struct Branch branch[MAXCARD];
};

struct ListNode
{
    struct ListNode *next;
    struct Node *node;
};

// splitnode
struct PartitionVars {
    int partition[MAXCARD + 1];       /// partition[i]表示id为i的branch被分配到的group id
    int total, minfill;               /// total表示待分配的branch总数,minfill表示结点所需的最少孩子数
    int taken[MAXCARD + 1];           /// taken[i]表示id为i的branch分配与否
    int count[2];                     /// count[i]表示id为i的group已包含的branch数
    struct Rect cover[2];             /// cover[i]表示id为i的group的矩形空间
    RectReal area[2];                 /// area[i]表示id为i的group的矩形空间大小
};

int NODECARD = MAXCARD;
int LEAFCARD = MAXCARD;

/* balance criteria for node splitting */
/* NOTE: can be changed if needed. */
#define MinNodeFill (NODECARD / 2)
#define MinLeafFill (LEAFCARD / 2)

#define MAXKIDS(n) ((n)->level > 0 ? NODECARD : LEAFCARD)
#define MINFILL(n) ((n)->level > 0 ? MinNodeFill : MinLeafFill)

struct Branch BranchBuf[MAXCARD + 1];
int BranchCount;
struct Rect CoverSplit;
RectReal CoverSplitArea;

/* variables for finding a partition */
struct PartitionVars Partitions[METHODS];


static int set_max(int *which, int new_max)
{
    if (2 > new_max || new_max > MAXCARD)
	return 0;
    *which = new_max;
    return 1;
}

static int RTreeSetNodeMax(int new_max)
{
    return set_max(&NODECARD, new_max);
}
static int RTreeSetLeafMax(int new_max)
{
    return set_max(&LEAFCARD, new_max);
}
static int RTreeGetNodeMax(void)
{
    return NODECARD;
}
static int RTreeGetLeafMax(void)
{
    return LEAFCARD;
}


/*-----------------------------------------------------------------------------
| Initialize a rectangle to have all 0 coordinates.
-----------------------------------------------------------------------------*/
static void RTreeInitRect(struct Rect *R)
{
    register struct Rect *r = R;
    register int i;

    for (i = 0; i < NUMSIDES; i++)
		r->boundary[i] = (RectReal) 0;
}


/*-----------------------------------------------------------------------------
| Return a rect whose first low side is higher than its opposite side -
| interpreted as an undefined rect.
-----------------------------------------------------------------------------*/
static struct Rect RTreeNullRect(void)
{
    struct Rect r;
    register int i;

    r.boundary[0] = (RectReal) 1;
    r.boundary[NUMDIMS] = (RectReal) - 1;
    for (i = 1; i < NUMDIMS; i++)
	r.boundary[i] = r.boundary[i + NUMDIMS] = (RectReal) 0;
    return r;
}


#if 0

/*-----------------------------------------------------------------------------
| Fills in random coordinates in a rectangle.
| The low side is guaranteed to be less than the high side.
-----------------------------------------------------------------------------*/
static void RTreeRandomRect(struct Rect *R)
{
    register struct Rect *r = R;
    register int i;
    register RectReal width;

    for (i = 0; i < NUMDIMS; i++) {
	/* width from 1 to 1000 / 4, more small ones
	 */
	width = drand48() * (1000 / 4) + 1;

	/* sprinkle a given size evenly but so they stay in [0,100]
	 */
	r->boundary[i] = drand48() * (1000 - width);	/* low side */
	r->boundary[i + NUMDIMS] = r->boundary[i] + width;	/* high side */
    }
}


/*-----------------------------------------------------------------------------
| Fill in the boundaries for a random search rectangle.
| Pass in a pointer to a rect that contains all the data,
| and a pointer to the rect to be filled in.
| Generated rect is centered randomly anywhere in the data area,
| and has size from 0 to the size of the data area in each dimension,
| i.e. search rect can stick out beyond data area.
-----------------------------------------------------------------------------*/
static void RTreeSearchRect(struct Rect *Search, struct Rect *Data)
{
    register struct Rect *search = Search, *data = Data;
    register int i, j;
    register RectReal size, center;

    assert(search);
    assert(data);

    for (i = 0; i < NUMDIMS; i++) {
	j = i + NUMDIMS;	/* index for high side boundary */
	if (data->boundary[i] > -BIG_NUM && data->boundary[j] < BIG_NUM) {
	    size = (drand48() * (data->boundary[j] -
				 data->boundary[i] + 1)) / 2;
	    center = data->boundary[i] + drand48() *
		(data->boundary[j] - data->boundary[i] + 1);
	    search->boundary[i] = center - size / 2;
	    search->boundary[j] = center + size / 2;
	}
	else {			/* some open boundary, search entire dimension */

	    search->boundary[i] = -BIG_NUM;
	    search->boundary[j] = BIG_NUM;
	}
    }
}

#endif

static void RTreeTabIn(int depth)
{
    int i;

    for (i = 0; i < depth; i++)
	putchar('\t');
}

/*-----------------------------------------------------------------------------
| Print out the data for a rectangle.
-----------------------------------------------------------------------------*/
static void RTreePrintRect(struct Rect *R, int depth)
{
    register struct Rect *r = R;
    register int i;

    assert(r);

    RTreeTabIn(depth);
    fprintf(stdout, "rect:\n");
    for (i = 0; i < NUMDIMS; i++) {
	RTreeTabIn(depth + 1);
	fprintf(stdout, "%f\t%f\n", r->boundary[i], r->boundary[i + NUMDIMS]);
    }
}

/*-----------------------------------------------------------------------------
| Calculate the n-dimensional volume of a rectangle
-----------------------------------------------------------------------------*/
static RectReal RTreeRectVolume(struct Rect *R)
{
    register struct Rect *r = R;
    register int i;
    register RectReal volume = (RectReal) 1;

    assert(r);
    if (Undefined(r))
	return (RectReal) 0;

    for (i = 0; i < NUMDIMS; i++)
	volume *= r->boundary[i + NUMDIMS] - r->boundary[i];
    assert(volume >= 0.0);
    return volume;
}


/*-----------------------------------------------------------------------------
| Define the NUMDIMS-dimensional volume the unit sphere in that dimension into
| the symbol "UnitSphereVolume"
| Note that if the gamma function is available in the math library and if the
| compiler supports static initialization using functions, this is
| easily computed for any dimension. If not, the value can be precomputed and
| taken from a table. The following code can do it either way.
-----------------------------------------------------------------------------*/

#ifdef gamma

/* computes the volume of an N-dimensional sphere. */
/* derived from formule in "Regular Polytopes" by H.S.M Coxeter */
static double sphere_volume(double dimension)
{
    double log_gamma, log_volume;

    log_gamma = gamma(dimension / 2.0 + 1);
    log_volume = dimension / 2.0 * log(M_PI) - log_gamma;
    return exp(log_volume);
}
static const double UnitSphereVolume = sphere_volume(NUMDIMS);

#else

/* Precomputed volumes of the unit spheres for the first few dimensions */
static const double UnitSphereVolumes[] = {
    0.000000,			/* dimension   0 */
    2.000000,			/* dimension   1 */
    3.141593,			/* dimension   2 */
    4.188790,			/* dimension   3 */
    4.934802,			/* dimension   4 */
    5.263789,			/* dimension   5 */
    5.167713,			/* dimension   6 */
    4.724766,			/* dimension   7 */
    4.058712,			/* dimension   8 */
    3.298509,			/* dimension   9 */
    2.550164,			/* dimension  10 */
    1.884104,			/* dimension  11 */
    1.335263,			/* dimension  12 */
    0.910629,			/* dimension  13 */
    0.599265,			/* dimension  14 */
    0.381443,			/* dimension  15 */
    0.235331,			/* dimension  16 */
    0.140981,			/* dimension  17 */
    0.082146,			/* dimension  18 */
    0.046622,			/* dimension  19 */
    0.025807,			/* dimension  20 */
};

#if NUMDIMS > 20
#	error "not enough precomputed sphere volumes"
#endif
#define UnitSphereVolume UnitSphereVolumes[NUMDIMS]

#endif


/*-----------------------------------------------------------------------------
| Calculate the n-dimensional volume of the bounding sphere of a rectangle
-----------------------------------------------------------------------------*/

#if 0
/*
 * A fast approximation to the volume of the bounding sphere for the
 * given Rect. By Paul B.
 */
static RectReal RTreeRectSphericalVolume(struct Rect *R)
{
    register struct Rect *r = R;
    register int i;
    RectReal maxsize = (RectReal) 0, c_size;

    assert(r);
    if (Undefined(r))
	return (RectReal) 0;
    for (i = 0; i < NUMDIMS; i++) {
	c_size = r->boundary[i + NUMDIMS] - r->boundary[i];
	if (c_size > maxsize)
	    maxsize = c_size;
    }
    return (RectReal) (pow(maxsize / 2, NUMDIMS) * UnitSphereVolume);
}
#endif

/*
 * The exact volume of the bounding sphere for the given Rect.
 */
static RectReal RTreeRectSphericalVolume(struct Rect * R)
{
    register struct Rect *r = R;
    register int i;
    register double sum_of_squares = 0, radius;

    assert(r);
    if (Undefined(r))
		return (RectReal) 0;
    for (i = 0; i < NUMDIMS; i++) {
		double half_extent = (r->boundary[i + NUMDIMS] - r->boundary[i]) / 2;

		sum_of_squares += half_extent * half_extent;
    }
    radius = sqrt(sum_of_squares);
    return (RectReal) (pow(radius, NUMDIMS) * UnitSphereVolume);
}


/*-----------------------------------------------------------------------------
| Calculate the n-dimensional surface area of a rectangle
-----------------------------------------------------------------------------*/
static RectReal RTreeRectSurfaceArea(struct Rect * R)
{
    register struct Rect *r = R;
    register int i, j;
    register RectReal sum = (RectReal) 0;

    assert(r);
    if (Undefined(r))
	return (RectReal) 0;

    for (i = 0; i < NUMDIMS; i++) {
	RectReal face_area = (RectReal) 1;

	for (j = 0; j < NUMDIMS; j++)
	    /* exclude i extent from product in this dimension */
	    if (i != j) {
		RectReal j_extent = r->boundary[j + NUMDIMS] - r->boundary[j];

		face_area *= j_extent;
	    }
	sum += face_area;
    }
    return 2 * sum;
}



/*-----------------------------------------------------------------------------
| Combine two rectangles, make one that includes both.
-----------------------------------------------------------------------------*/
static struct Rect RTreeCombineRect(struct Rect *R, struct Rect *Rr)
{
    register struct Rect *r = R, *rr = Rr;
    register int i, j;
    struct Rect new_rect;

    assert(r && rr);

    if (Undefined(r))
		return *rr;

    if (Undefined(rr))
		return *r;

    for (i = 0; i < NUMDIMS; i++) {
		new_rect.boundary[i] = MIN(r->boundary[i], rr->boundary[i]);
		j = i + NUMDIMS;
		new_rect.boundary[j] = MAX(r->boundary[j], rr->boundary[j]);
    }
    return new_rect;
}


/*-----------------------------------------------------------------------------
| Decide whether two rectangles overlap.
-----------------------------------------------------------------------------*/
static int RTreeOverlap(struct Rect *R, struct Rect *S)
{
    register struct Rect *r = R, *s = S;
    register int i, j;

    assert(r && s);

    for (i = 0; i < NUMDIMS; i++) {
		j = i + NUMDIMS;	/* index for high sides */
		if (r->boundary[i] > s->boundary[j] ||
			s->boundary[i] > r->boundary[j]) {
			return FALSE;
		}
    }
    return TRUE;
}


/*-----------------------------------------------------------------------------
| Decide whether rectangle r is contained in rectangle s.
-----------------------------------------------------------------------------*/
static int RTreeContained(struct Rect *R, struct Rect *S)
{
    register struct Rect *r = R, *s = S;
    register int i, j, result;

    assert(r && s); /* same as in RTreeOverlap() */

    /* undefined rect is contained in any other */
    if (Undefined(r))
	return TRUE;

    /* no rect (except an undefined one) is contained in an undef rect */
    if (Undefined(s))
	return FALSE;

    result = TRUE;
    for (i = 0; i < NUMDIMS; i++) {
	j = i + NUMDIMS;	/* index for high sides */
	result = result && r->boundary[i] >= s->boundary[i]
	    && r->boundary[j] <= s->boundary[j];
    }
    return result;
}


/* Initialize one branch cell in a node. */
static void RTreeInitBranch(struct Branch *b)
{
    RTreeInitRect(&(b->rect));
    b->child = NULL;
}

/* Initialize a Node structure. */
static void RTreeInitNode(struct Node *N)
{
    register struct Node *n = N;
    register int i;

    n->count = 0;
    n->level = -1;
    for (i = 0; i < MAXCARD; i++)
		RTreeInitBranch(&(n->branch[i]));
}

/* Make a new node and initialize to have all branch cells empty. */
static struct Node *RTreeNewNode(void)
{
    register struct Node *n;

    /* n = new Node; */
    n = (struct Node *)malloc(sizeof(struct Node));
    assert(n);
    RTreeInitNode(n);
    return n;
}

static void RTreeFreeNode(struct Node *p)
{
    assert(p);
    /* delete p; */
    free(p);
}

static void RTreePrintNode(struct Node *n, int depth);
static void RTreePrintBranch(struct Branch *b, int depth)
{
    RTreePrintRect(&(b->rect), depth);
    RTreePrintNode(b->child, depth);
}

/* Print out the data in a node. */
static void RTreePrintNode(struct Node *n, int depth)
{
    int i;

    assert(n);

    RTreeTabIn(depth);
    fprintf(stdout, "node");
    if (n->level == 0)
	fprintf(stdout, " LEAF");
    else if (n->level > 0)
	fprintf(stdout, " NONLEAF");
    else
	fprintf(stdout, " TYPE=?");
    fprintf(stdout, "  level=%d  count=%d  address=%o\n", n->level, n->count,
	    (unsigned)n);

    for (i = 0; i < n->count; i++) {
	if (n->level == 0) {
	    /* RTreeTabIn(depth); */
	    /* fprintf (stdout, "\t%d: data = %d\n", i, n->branch[i].child); */
	}
	else {
	    RTreeTabIn(depth);
	    fprintf(stdout, "branch %d\n", i);
	    RTreePrintBranch(&n->branch[i], depth + 1);
	}
    }
}

/*
 * Find the smallest rectangle that includes all rectangles in
 * branches of a node.
 */
static struct Rect RTreeNodeCover(struct Node *N)
{
    register struct Node *n = N;
    register int i, first_time = 1;
    struct Rect r;

    assert(n);

    RTreeInitRect(&r);
    for (i = 0; i < MAXKIDS(n); i++)
	if (n->branch[i].child) {
	    if (first_time) {
		r = n->branch[i].rect;
		first_time = 0;
	    }
	    else
		r = RTreeCombineRect(&r, &(n->branch[i].rect));
	}
    return r;
}

/*
 * Pick a branch.  Pick the one that will need the smallest increase
 * in area to accomodate the new rectangle.  This will result in the
 * least total area for the covering rectangles in the current node.
 * In case of a tie, pick the one which was smaller before, to get
 * the best resolution when searching.
 */
static int RTreePickBranch(struct Rect *R, struct Node *N)
{
    register struct Rect *r = R;
    register struct Node *n = N;
    register struct Rect *rr;
    register int i, first_time = 1;
    RectReal increase, bestIncr = (RectReal) - 1, area, bestArea = 0;
    int best = 0;
    struct Rect tmp_rect;

    assert(r && n);

	// best是这样的孩子:添加矩形R后其矩形空间增加值最少
    for (i = 0; i < MAXKIDS(n); i++) {
		if (n->branch[i].child) {
			rr = &n->branch[i].rect;
			area = RTreeRectSphericalVolume(rr);
			tmp_rect = RTreeCombineRect(r, rr);
			increase = RTreeRectSphericalVolume(&tmp_rect) - area;
			if (increase < bestIncr || first_time) {
				best = i;
				bestArea = area;
				bestIncr = increase;
				first_time = 0;
			}
			else if (increase == bestIncr && area < bestArea) {
				best = i;
				bestArea = area;
				bestIncr = increase;
			}
		}
    }
    return best;
}

/*-----------------------------------------------------------------------------
| Load branch buffer with branches from full node plus the extra branch.
-----------------------------------------------------------------------------*/
static void RTreeGetBranches(struct Node *n, struct Branch *b)
{
    int i;

    assert(n);
    assert(b);

    /* load the branch buffer */
    for (i = 0; i < MAXKIDS(n); i++) {
		assert(n->branch[i].child);	/* n should have every entry full */
		BranchBuf[i] = n->branch[i];
    }
    BranchBuf[MAXKIDS(n)] = *b;
    BranchCount = MAXKIDS(n) + 1;

    /* calculate rect containing all in the set */
    CoverSplit = BranchBuf[0].rect;
    for (i = 1; i < MAXKIDS(n) + 1; i++) {
		CoverSplit = RTreeCombineRect(&CoverSplit, &BranchBuf[i].rect);
    }
    CoverSplitArea = RTreeRectSphericalVolume(&CoverSplit);

    RTreeInitNode(n);
}

/*-----------------------------------------------------------------------------
| Put a branch in one of the groups.
-----------------------------------------------------------------------------*/
static void RTreeClassify(int i, int group, struct PartitionVars *p)
{
    assert(p);
    assert(!p->taken[i]);

    p->partition[i] = group;
    p->taken[i] = TRUE;

    if (p->count[group] == 0)
		p->cover[group] = BranchBuf[i].rect;
    else
		p->cover[group] =
			RTreeCombineRect(&BranchBuf[i].rect, &p->cover[group]);
    p->area[group] = RTreeRectSphericalVolume(&p->cover[group]);
    p->count[group]++;
}




/*-----------------------------------------------------------------------------
| Pick two rects from set to be the first elements of the two groups.
| Pick the two that waste the most area if covered by a single rectangle.
-----------------------------------------------------------------------------*/
static void RTreePickSeeds(struct PartitionVars *p)
{
    int i, j, seed0 = 0, seed1 = 0;
    RectReal worst, waste, area[MAXCARD + 1];

    for (i = 0; i < p->total; i++)
	area[i] = RTreeRectSphericalVolume(&BranchBuf[i].rect);

    worst = -CoverSplitArea - 1;
    for (i = 0; i < p->total - 1; i++) {
		for (j = i + 1; j < p->total; j++) {
			struct Rect one_rect;
	
			one_rect = RTreeCombineRect(&BranchBuf[i].rect,
						&BranchBuf[j].rect);
			waste = RTreeRectSphericalVolume(&one_rect) - area[i] - area[j];
			if (waste > worst) {
				worst = waste;
				seed0 = i;
				seed1 = j;
			}
		}
    }
    RTreeClassify(seed0, 0, p);
    RTreeClassify(seed1, 1, p);
}


/*-----------------------------------------------------------------------------
| Initialize a PartitionVars structure.
-----------------------------------------------------------------------------*/
static void RTreeInitPVars(struct PartitionVars *p, int maxrects, int minfill)
{
    int i;

    assert(p);

    p->count[0] = p->count[1] = 0;
    p->cover[0] = p->cover[1] = RTreeNullRect();
    p->area[0] = p->area[1] = (RectReal) 0;
    p->total = maxrects;
    p->minfill = minfill;
    for (i = 0; i < maxrects; i++) {
		p->taken[i] = FALSE;
		p->partition[i] = -1;
    }
}

/*-----------------------------------------------------------------------------
| Print out data for a partition from PartitionVars struct.
-----------------------------------------------------------------------------*/
static void RTreePrintPVars(struct PartitionVars *p)
{
    int i;

    assert(p);

    fprintf(stdout, "\npartition:\n");
    for (i = 0; i < p->total; i++) {
	fprintf(stdout, "%3d\t", i);
    }
    fprintf(stdout, "\n");
    for (i = 0; i < p->total; i++) {
	if (p->taken[i])
	    fprintf(stdout, "  t\t");
	else
	    fprintf(stdout, "\t");
    }
    fprintf(stdout, "\n");
    for (i = 0; i < p->total; i++) {
	fprintf(stdout, "%3d\t", p->partition[i]);
    }
    fprintf(stdout, "\n");

    fprintf(stdout, "count[0] = %d  area = %f\n", p->count[0], p->area[0]);
    fprintf(stdout, "count[1] = %d  area = %f\n", p->count[1], p->area[1]);
    if (p->area[0] + p->area[1] > 0) {
	fprintf(stdout, "total area = %f  effectiveness = %3.2f\n",
		p->area[0] + p->area[1],
		(float)CoverSplitArea / (p->area[0] + p->area[1]));
    }
    fprintf(stdout, "cover[0]:\n");
    RTreePrintRect(&p->cover[0], 0);

    fprintf(stdout, "cover[1]:\n");
    RTreePrintRect(&p->cover[1], 0);
}


/*-----------------------------------------------------------------------------
| Method #0 for choosing a partition:
| As the seeds for the two groups, pick the two rects that would waste the
| most area if covered by a single rectangle, i.e. evidently the worst pair
| to have in the same group.
| Of the remaining, one at a time is chosen to be put in one of the two groups.
| The one chosen is the one with the greatest difference in area expansion
| depending on which group - the rect most strongly attracted to one group
| and repelled from the other.
| If one group gets too full (more would force other group to violate min
| fill requirement) then other group gets the rest.
| These last are the ones that can go in either group most easily.
-----------------------------------------------------------------------------*/
static void RTreeMethodZero(struct PartitionVars *p, int minfill)
{
    int i;
    RectReal biggestDiff;
    int group, chosen = 0, betterGroup = 0;

    assert(p);

    RTreeInitPVars(p, BranchCount, minfill);
    RTreePickSeeds(p);

    while (p->count[0] + p->count[1] < p->total
	   && p->count[0] < p->total - p->minfill
	   && p->count[1] < p->total - p->minfill) {
		biggestDiff = (RectReal) - 1.;
		for (i = 0; i < p->total; i++) {
			if (!p->taken[i]) {
				struct Rect *r, rect_0, rect_1;
				RectReal growth0, growth1, diff;
		
				r = &BranchBuf[i].rect;
				rect_0 = RTreeCombineRect(r, &p->cover[0]);
				rect_1 = RTreeCombineRect(r, &p->cover[1]);
				growth0 = RTreeRectSphericalVolume(&rect_0) - p->area[0];
				growth1 = RTreeRectSphericalVolume(&rect_1) - p->area[1];
				diff = growth1 - growth0;
				if (diff >= 0)
					group = 0;
				else {
					group = 1;
					diff = -diff;
				}
		
				if (diff > biggestDiff) {
					biggestDiff = diff;
					chosen = i;
					betterGroup = group;
				}
				else if (diff == biggestDiff &&
					p->count[group] < p->count[betterGroup]) {
					chosen = i;
					betterGroup = group;
				}
			}
		}
		RTreeClassify(chosen, betterGroup, p);
    }

    /* if one group too full, put remaining rects in the other */
    if (p->count[0] + p->count[1] < p->total) {
		if (p->count[0] >= p->total - p->minfill)
			group = 1;
		else
			group = 0;
		for (i = 0; i < p->total; i++) {
			if (!p->taken[i])
				RTreeClassify(i, group, p);
		}
    }

    assert(p->count[0] + p->count[1] == p->total);
    assert(p->count[0] >= p->minfill && p->count[1] >= p->minfill);
}

static void RTreeSplitNode(struct Node *n, struct Branch *b, struct Node **nn);
/*
 * Add a branch to a node.  Split the node if necessary.
 * Returns 0 if node not split.  Old node updated.
 * Returns 1 if node split, sets *new_node to address of new node.
 * Old node updated, becomes one of two.
 */
static int RTreeAddBranch(struct Branch *B, struct Node *N, struct Node **New_node)
{
    register struct Branch *b = B;
    register struct Node *n = N;
    register struct Node **new_node = New_node;
    register int i;

    assert(b);
    assert(n);

    if (n->count < MAXKIDS(n)) {	/* split won't be necessary */
		for (i = 0; i < MAXKIDS(n); i++) {	/* find empty branch */
			if (n->branch[i].child == NULL) {
			n->branch[i] = *b;
			n->count++;
			break;
			}
		}
		return 0;
    }
    else {
		assert(new_node);
		RTreeSplitNode(n, b, new_node);
		return 1;
    }
}

/*-----------------------------------------------------------------------------
| Copy branches from the buffer into two nodes according to the partition.
-----------------------------------------------------------------------------*/
static void RTreeLoadNodes(struct Node *n, struct Node *q,
			   struct PartitionVars *p)
{
    int i;

    assert(n);
    assert(q);
    assert(p);

    for (i = 0; i < p->total; i++) {
		assert(p->partition[i] == 0 || p->partition[i] == 1);
		if (p->partition[i] == 0)
			RTreeAddBranch(&BranchBuf[i], n, NULL);
		else if (p->partition[i] == 1)
			RTreeAddBranch(&BranchBuf[i], q, NULL);
    }
}

/*-----------------------------------------------------------------------------
| Split a node.
| Divides the nodes branches and the extra one between two nodes.
| Old node is one of the new ones, and one really new one is created.
| Tries more than one method for choosing a partition, uses best result.
-----------------------------------------------------------------------------*/
static void RTreeSplitNode(struct Node *n, struct Branch *b, struct Node **nn)
{
    struct PartitionVars *p;
    int level;

    assert(n);
    assert(b);

    /* load all the branches into a buffer, initialize old node */
    level = n->level;
    RTreeGetBranches(n, b);

    /* find partition */
    p = &Partitions[0];
    /* Note: can't use MINFILL(n) below since n was cleared by GetBranches() */
    RTreeMethodZero(p, level > 0 ? MinNodeFill : MinLeafFill);

    /*
     * put branches from buffer into 2 nodes
     * according to chosen partition
     */
    *nn = RTreeNewNode();
    (*nn)->level = n->level = level;
    RTreeLoadNodes(n, *nn, p);
    assert(n->count + (*nn)->count == p->total);
}

/* Disconnect a dependent node. */
static void RTreeDisconnectBranch(struct Node *n, int i)
{
    assert(n && i >= 0 && i < MAXKIDS(n));
    assert(n->branch[i].child);

    RTreeInitBranch(&(n->branch[i]));
    n->count--;
}

/* Destroy (free) node recursively. */
void RTreeDestroyNode(struct Node *n)
{
    int i;
	
	if (!n)
		return;
    if (n->level > 0) {		/* it is not leaf -> destroy childs */
		for (i = 0; i < NODECARD; i++) {
			if (n->branch[i].child) {
				RTreeDestroyNode(n->branch[i].child);
			}
		}
    }

    /* Free this node */
    RTreeFreeNode(n);
}


/* Make a new index, empty.  Consists of a single node. */
struct Node *RTreeNewIndex(void)
{
    struct Node *x;

    x = RTreeNewNode();
    x->level = 0;		/* leaf */
    return x;
}

/*
 * Search in an index tree or subtree for all data retangles that
 * overlap the argument rectangle.
 * Return the number of qualifying data rects.
 */
int RTreeSearch(struct Node *N, struct Rect *R, SearchHitCallback shcb,
		void *cbarg)
{
    register struct Node *n = N;
    register struct Rect *r = R;	/* NOTE: Suspected bug was R sent in as Node* and cast to Rect* here. */

    /* Fix not yet tested. */
    register int hitCount = 0;
    register int i;

    assert(n);
    assert(n->level >= 0);
    assert(r);

    if (n->level > 0) {		/* this is an internal node in the tree */
		for (i = 0; i < NODECARD; i++)
			if (n->branch[i].child && RTreeOverlap(r, &n->branch[i].rect)) {
				hitCount += RTreeSearch(n->branch[i].child, r, shcb, cbarg);
			}
    }
    else {			/* this is a leaf node */

		for (i = 0; i < LEAFCARD; i++)
			if (n->branch[i].child && RTreeOverlap(r, &n->branch[i].rect)) {
				hitCount++;
				if (shcb)	/* call the user-provided callback */
					if (!shcb((int)n->branch[i].child, cbarg))
						return hitCount;	/* callback wants to terminate search early */
			}
    }
    return hitCount;
}

/*
 * Inserts a new data rectangle into the index structure.
 * Recursively descends tree, propagates splits back up.
 * Returns 0 if node was not split.  Old node updated.
 * If node was split, returns 1 and sets the pointer pointed to by
 * new_node to point to the new node.  Old node updated to become one of two.
 * The level argument specifies the number of steps up from the leaf
 * level to insert; e.g. a data rectangle goes in at level = 0.
 */
static int RTreeInsertRect2(struct Rect *r,
			    struct Node *child, struct Node *n, struct Node **new_node,
			    int level)
{
    /*
       register struct Rect *r = R;
       register int tid = Tid;
       register struct Node *n = N, **new_node = New_node;
       register int level = Level;
     */

    register int i;
    struct Branch b;
    struct Node *n2;

    assert(r && n && new_node);
    assert(level >= 0 && level <= n->level);

    /* Still above level for insertion, go down tree recursively */
    if (n->level > level) {
		i = RTreePickBranch(r, n);
		if (!RTreeInsertRect2(r, child, n->branch[i].child, &n2, level)) {
			/* child was not split */
			n->branch[i].rect = RTreeCombineRect(r, &(n->branch[i].rect));
			return 0;
		}
		else {			/* child was split */
	
			n->branch[i].rect = RTreeNodeCover(n->branch[i].child);
			b.child = n2;
			b.rect = RTreeNodeCover(n2);
			return RTreeAddBranch(&b, n, new_node);
		}
    }

    /* Have reached level for insertion. Add rect, split if necessary */
    else if (n->level == level) {
		b.rect = *r;
		b.child = child;
		/* child field of leaves contains tid(the id of tuple) of data record */
		return RTreeAddBranch(&b, n, new_node);
    }
    else {
		/* Not supposed to happen */
		assert(FALSE);
		return 0;
    }
}

static int RTreeInsertRect1(struct Rect *R, struct Node *Child, struct Node **Root, int Level)
{
    register struct Rect *r = R;
    register struct Node *child = Child;
    register struct Node **root = Root;
    register int level = Level;
    register int i;
    register struct Node *newroot;
    struct Node *newnode;
    struct Branch b;
    int result;

    assert(r && root);
    assert(level >= 0 && level <= (*root)->level);
    for (i = 0; i < NUMDIMS; i++) {
		assert(r->boundary[i] <= r->boundary[NUMDIMS + i]);
    }

    if (RTreeInsertRect2(r, child, *root, &newnode, level)) {	/* root split */
		newroot = RTreeNewNode();	/* grow a new root, & tree taller */
		newroot->level = (*root)->level + 1;
		b.rect = RTreeNodeCover(*root);
		b.child = *root;
		RTreeAddBranch(&b, newroot, NULL);
		b.rect = RTreeNodeCover(newnode);
		b.child = newnode;
		RTreeAddBranch(&b, newroot, NULL);
		*root = newroot;
		result = 1;
    }
    else
		result = 0;

    return result;
}

/* 
 * Insert a data rectangle into an index structure.
 * RTreeInsertRect provides for splitting the root;
 * returns 1 if root was split, 0 if it was not.
 * The level argument specifies the number of steps up from the leaf
 * level to insert; e.g. a data rectangle goes in at level = 0.
 * RTreeInsertRect2 does the recursion.
 */
int RTreeInsertRect(struct Rect *R, int Tid, struct Node **Root, int Level)
{
    assert(Level == 0);
    return RTreeInsertRect1(R, (struct Node *) Tid, Root, Level);
}

/*
 * Allocate space for a node in the list used in DeletRect to
 * store Nodes that are too empty.
 */
static struct ListNode *RTreeNewListNode(void)
{
    return (struct ListNode *)malloc(sizeof(struct ListNode));
    /* return new ListNode; */
}

static void RTreeFreeListNode(struct ListNode *p)
{
    free(p);
    /* delete(p); */
}

/* 
 * Add a node to the reinsertion list.  All its branches will later
 * be reinserted into the index structure.
 */
static void RTreeReInsert(struct Node *n, struct ListNode **ee)
{
    register struct ListNode *l;

    l = RTreeNewListNode();
    l->node = n;
    l->next = *ee;
    *ee = l;
}

/*
 * Delete a rectangle from non-root part of an index structure.
 * Called by RTreeDeleteRect.  Descends tree recursively,
 * merges branches on the way back up.
 * Returns 1 if record not found, 0 if success.
 */
static int
RTreeDeleteRect2(struct Rect *R, struct Node *Child, struct Node *N,
		 struct ListNode **Ee)
{
    register struct Rect *r = R;
    register struct Node *child = Child;
    register struct Node *n = N;
    register struct ListNode **ee = Ee;
    register int i;

    assert(r && n && ee);
    assert(child);
    assert(n->level >= 0);

    if (n->level > 0) {		/* not a leaf node */
		for (i = 0; i < NODECARD; i++) {
			if (n->branch[i].child && RTreeOverlap(r, &(n->branch[i].rect))) {
				if (!RTreeDeleteRect2(r, child, n->branch[i].child, ee)) {
					if (n->branch[i].child->count >= MinNodeFill) {
						n->branch[i].rect =
							RTreeNodeCover(n->branch[i].child);
					}
					else {
						/* not enough entries in child, eliminate child node */
						RTreeReInsert(n->branch[i].child, ee);
						RTreeDisconnectBranch(n, i);
					}
					return 0;
				}
			}
		}
		return 1;
    }
    else {			/* a leaf node */

		for (i = 0; i < LEAFCARD; i++) {
			if (n->branch[i].child &&
				n->branch[i].child == child) {
				RTreeDisconnectBranch(n, i);
				return 0;
			}
		}
		return 1;
    }
}

static int RTreeDeleteRect1(struct Rect *R, struct Node *Child, struct Node **Nn)
{
    register struct Rect *r = R;
    register struct Node *child = Child;
    register struct Node **nn = Nn;
    register int i;
    struct Node *tmp_nptr = NULL;
    struct ListNode *reInsertList = NULL;
    register struct ListNode *e;

    assert(r && nn);
    assert(*nn);
    assert(child);

    if (!RTreeDeleteRect2(r, child, *nn, &reInsertList)) {
		/* found and deleted a data item */
	
		/* reinsert any branches from eliminated nodes */
		while (reInsertList) {
			tmp_nptr = reInsertList->node;
			for (i = 0; i < MAXKIDS(tmp_nptr); i++) {
				if (tmp_nptr->branch[i].child) {
					RTreeInsertRect1(&(tmp_nptr->branch[i].rect),
							tmp_nptr->branch[i].child,
							nn, tmp_nptr->level);
				}
			}
			e = reInsertList;
			reInsertList = reInsertList->next;
			RTreeFreeNode(e->node);
			RTreeFreeListNode(e);
		}
	
		/* check for redundant root (not leaf, 1 child) and eliminate */
		if ((*nn)->count == 1 && (*nn)->level > 0) {
			for (i = 0; i < NODECARD; i++) {
				tmp_nptr = (*nn)->branch[i].child;
				if (tmp_nptr)
					break;
			}
			assert(tmp_nptr);
			RTreeFreeNode(*nn);
			*nn = tmp_nptr;
		}
		return 0;
    }
    else {
		return 1;
    }
}

/*
 * Delete a data rectangle from an index structure.
 * Pass in a pointer to a Rect, the tid of the record, ptr to ptr to root node.
 * Returns 1 if record not found, 0 if success.
 * RTreeDeleteRect provides for eliminating the root.
 */
int RTreeDeleteRect(struct Rect *R, int Tid, struct Node **Nn)
{
    /* wrapper not really needed, but restricts compile warnings to rtree lib */
    /* this way it's easier to fix if necessary? */
    return RTreeDeleteRect1(R, (struct Node *) Tid, Nn);
}



test.c

/****************************************************************************
* MODULE:       R-Tree library 
*              
* AUTHOR(S):    Antonin Guttman - original code
*               Daniel Green (green@superliminal.com) - major clean-up
*                               and implementation of bounding spheres
*               
* PURPOSE:      Multidimensional index
*
* COPYRIGHT:    (C) 2001 by the GRASS Development Team
*
*               This program is free software under the GNU General Public
*               License (>=v2). Read the file COPYING that comes with GRASS
*               for details.
*
* LAST MODIFICATION: Hyforthy 2013
*****************************************************************************/

#include <stdio.h>
#include "rtree.h"

struct Rect rects[] = {
    {{0, 0, 0, 2, 2, 0}},	/* xmin, ymin, zmin, xmax, ymax, zmax (for 3 dimensional RTree) */
    {{5, 5, 0, 7, 7, 0}},
    {{8, 5, 0, 9, 6, 0}},
    {{7, 1, 0, 9, 2, 0}},
	{{1, 1, 0, 9, 2, 0}},
	{{2, 1, 0, 9, 2, 0}},
	{{3, 1, 0, 9, 2, 0}},
	{{4, 1, 0, 9, 2, 0}},
	{{6, 1, 0, 9, 2, 0}},
	{{8, 1, 0, 9, 2, 0}},
	{{9, 1, 0, 9, 2, 0}},
	{{1, 1, 0, 9, 2, 0}},
	{{2, 2, 0, 9, 2, 0}},
	{{3, 3, 0, 9, 20, 0}},
	{{4, 5, 0, 9, 20, 0}},
	{{6, 7, 0, 9, 20, 0}},
	{{8, 10, 0, 9, 20, 0}},
	{{9, 11, 0, 9, 20, 0}},
	{{1, 1, 1, 9, 2, 10}},
	{{2, 2, 2, 9, 2, 10}},
	{{3, 3, 3, 9, 12, 10}},
	{{4, 5, 4, 9, 12, 10}},
	{{6, 7, 5, 9, 12, 10}},
	{{8, 10, 6, 9, 12, 10}},
	{{9, 11, 7, 9, 12, 10}},
	{{1, 1, 1, 1, 2, 4}},
	{{2, 2, 2, 9, 2, 7}},
	{{3, 3, 3, 4, 4, 4}},
	{{4, 5, 4, 10, 10, 10}},
	{{6, 7, 5, 20, 20, 10}},
	{{8, 10, 6, 15, 11, 10}},
	{{9, 11, 7, 10, 12, 18}},
	{{3, 5, 0, 19, 6, 1}},
	{{3, 5, 0, 9, 6, 1}},
	{{3, 1, 0, 8, 10, 1}},
	{{3, 5, 0, 9, 6, 1}}
	
};


int nrects = sizeof(rects) / sizeof(rects[0]);
struct Rect search_rect = {
    {6, 4, 0, 10, 6, 0}		/* search will find above rects that this one overlaps */
};

int MySearchCallback(int id, void *arg)
{
    /* Note: -1 to make up for the +1 when data was inserted */
    fprintf(stdout, "Hit data rect %d\n", id - 1);
    return 1;			/* keep going */
}

int main()
{
    struct Node *root = RTreeNewIndex();
    int i, nhits;

    fprintf(stdout, "nrects = %d\n", nrects);
    /*
     * Insert all the data rects.
     * Notes about the arguments:
     * parameter 1 is the rect being inserted,
     * parameter 2 is its ID. NOTE: *** ID MUST NEVER BE ZERO ***, hence the +1,
     * parameter 3 is the root of the tree. Note: its address is passed
     * because it can change as a result of this call, therefore no other parts
     * of this code should stash its address since it could change undernieth.
     * parameter 4 is always zero which means to add from the root.
     */
    for (i = 0; i < nrects; i++)
	RTreeInsertRect(&rects[i], i + 1, &root, 0);	/* i+1 is rect ID. Note: root can change */
    nhits = RTreeSearch(root, &search_rect, MySearchCallback, 0);
    fprintf(stdout, "Search resulted in %d hits\n", nhits);
	
	fprintf(stdout, "------------------- delete -------------------\n");
	RTreeDeleteRect(&rects[34], 35, &root);
	nhits = RTreeSearch(root, &search_rect, MySearchCallback, 0);
    fprintf(stdout, "Search resulted in %d hits\n", nhits);
	RTreeDestroyNode(root);

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值