📄 rtree.cxx
字号:
//-< RTREE.CXX >-----------------------------------------------------*--------*
// POST++ Version 1.0 (c) 1998 GARRET * ? *
// (Persistent Object Storage) * /\| *
// * / \ *
// Created: 15-Mar-98 K.A. Knizhnik * / [] \ *
// Last update: 15-Mar-98 K.A. Knizhnik * GARRET *
//-------------------------------------------------------------------*--------*
// R-tree class implementation
//-------------------------------------------------------------------*--------*
#include "rtree.h"
void R_tree::insert(rectangle const& r, object* obj)
{
if (root == NULL) {
root = new_in(*get_storage(), R_page)(r, obj);
height = 1;
} else {
R_page* p = root->insert(r, obj, height);
if (p != NULL) {
// root splitted
root = new_in(*get_storage(), R_page)(root, p);
height += 1;
}
}
n_records += 1;
}
bool R_tree::remove(rectangle const& r, object* obj)
{
if (height != 0) {
R_page::reinsert_list rlist;
if (root->remove(r, obj, height, rlist)) {
R_page* pg = rlist.chain;
int level = rlist.level;
while (pg != NULL) {
for (int i = 0, n = pg->n; i < n; i++) {
R_page* p = root->insert(pg->b[i].rect,
pg->b[i].p, height-level);
if (p != NULL) {
// root splitted
root = new_in(*get_storage(), R_page)(root, p);
height += 1;
}
}
level -= 1;
R_page* next = pg->next_reinsert_page();
delete pg;
pg = next;
}
if (root->n == 1 && height > 1) {
R_page* new_root = root->b[0].p;
delete root;
root = new_root;
height -= 1;
}
n_records -= 1;
return true;
}
}
return false;
}
int R_tree::search(rectangle const& r, callback& cb) const
{
return (n_records != 0) ? root->search(r, cb, height) : 0;
}
int R_tree::search(rectangle const& r, search_buffer& sb) const
{
return (n_records != 0) ? root->search(r, sb, height) : 0;
}
void R_tree::purge(bool delete_leaves)
{
if (root != NULL) {
root->purge(height, delete_leaves);
root = NULL;
n_records = 0;
}
}
REGISTER(R_tree);
//-------------------------------------------------------------------------
// R-tree page methods
//-------------------------------------------------------------------------
//
// Search for objects overlapped with specified rectangle and call
// callback method for all such objects.
//
int R_page::search(rectangle const& r, callback& cb, int level) const
{
assert(level >= 0);
int hit_count = 0;
if (--level != 0) { /* this is an internal node in the tree */
for (int i=0; i < n; i++) {
if ((r & b[i].rect) != 0) {
R_page* child = b[i].p;
hit_count += child->search(r, cb, level);
}
}
} else { /* this is a leaf node */
for (int i=0; i < n; i++) {
if ((r & b[i].rect) != 0) {
cb.apply(b[i].p);
hit_count += 1;
}
}
}
return hit_count;
}
//
// Search for objects overlapped with specified rectangle and place
// all such objects in search buffer.
//
int R_page::search(rectangle const& r, search_buffer& sb, int level) const
{
assert(level >= 0);
int hit_count = 0;
if (--level != 0) { /* this is an internal node in the tree */
for (int i=0; i < n; i++) {
if ((r & b[i].rect) != 0) {
R_page* child = b[i].p;
hit_count += child->search(r, sb, level);
}
}
} else { /* this is a leaf node */
for (int i=0; i < n; i++) {
if ((r & b[i].rect) != 0) {
sb.push(b[i].p);
hit_count += 1;
}
}
}
return hit_count;
}
//
// Create root page
//
R_page::R_page(rectangle const& r, object* obj)
{
n = 1;
b[0].rect = r;
b[0].p = (R_page*)obj;
}
//
// Create new root page (root splitting)
//
R_page::R_page(R_page* old_root, R_page* new_page)
{
n = 2;
b[0].rect = old_root->cover();
b[0].p = old_root;
b[1].rect = new_page->cover();
b[1].p = new_page;
}
//
// Calculate cover of all rectangles at page
//
rectangle R_page::cover() const
{
rectangle r = b[0].rect;
for (int i = 1; i < n; i++) {
r += b[i].rect;
}
return r;
}
R_page* R_page::split_page(branch const& br)
{
int i, j, seed[2];
int rect_area[card+1], waste, worst_waste = INT_MIN;
//
// As the seeds for the two groups, find two rectangles which waste
// the most area if covered by a single rectangle.
//
rect_area[0] = area(br.rect);
for (i = 0; i < card; i++) {
rect_area[i+1] = area(b[i].rect);
}
branch const* bp = &br;
for (i = 0; i < card; i++) {
for (j = i+1; j <= card; j++) {
waste = area(bp->rect + b[j-1].rect) - rect_area[i] - rect_area[j];
if (waste > worst_waste) {
worst_waste = waste;
seed[0] = i;
seed[1] = j;
}
}
bp = &b[i];
}
char taken[card];
rectangle group[2];
int group_area[2];
int group_card[2];
R_page* p;
memset(taken, 0, sizeof taken);
taken[seed[1]-1] = 2;
group[1] = b[seed[1]-1].rect;
if (seed[0] == 0) {
group[0] = br.rect;
p = new_in(*get_storage(), R_page)(br.rect, br.p);
} else {
group[0] = b[seed[0]-1].rect;
p = new_in(*get_storage(), R_page)(group[0], b[seed[0]-1].p);
b[seed[0]-1] = br;
}
group_card[0] = group_card[1] = 1;
group_area[0] = rect_area[seed[0]];
group_area[1] = rect_area[seed[1]];
//
// Split remaining rectangles between 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.
//
while (group_card[0] + group_card[1] < card + 1
&& group_card[0] < card + 1 - min_fill
&& group_card[1] < card + 1 - min_fill)
{
int better_group = -1, chosen = -1, biggest_diff = -1;
for (i = 0; i < card; i++) {
if (!taken[i]) {
int diff = (area(group[0] + b[i].rect) - group_area[0])
- (area(group[1] + b[i].rect) - group_area[1]);
if (diff > biggest_diff || -diff > biggest_diff) {
chosen = i;
if (diff < 0) {
better_group = 0;
biggest_diff = -diff;
} else {
better_group = 1;
biggest_diff = diff;
}
}
}
}
assert(chosen >= 0);
group_card[better_group] += 1;
group[better_group] += b[chosen].rect;
group_area[better_group] = area(group[better_group]);
taken[chosen] = better_group+1;
if (better_group == 0) {
p->b[group_card[0]-1] = b[chosen];
}
}
//
// If one group gets too full, then remaining rectangle are
// split between two groups in such way to balance cards of two groups.
//
if (group_card[0] + group_card[1] < card + 1) {
for (i = 0; i < card; i++) {
if (!taken[i]) {
if (group_card[0] >= group_card[1]) {
taken[i] = 2;
group_card[1] += 1;
} else {
taken[i] = 1;
p->b[group_card[0]++] = b[i];
}
}
}
}
p->n = group_card[0];
n = group_card[1];
for (i = 0, j = 0; i < n; j++) {
if (taken[j] == 2) {
b[i++] = b[j];
}
}
while (i < card) {
b[i++].p = NULL;
}
return p;
}
void R_page::remove_branch(int i)
{
n -= 1;
memcpy(&b[i], &b[i+1], (n-i)*sizeof(branch));
}
R_page* R_page::insert(rectangle const& r, object* obj, int level)
{
branch br;
if (--level != 0) {
// not leaf page
int i, mini = 0;
size_t min_incr = INT_MAX;
size_t r_area = area(r);
for (i = 0; i < n; i++) {
size_t incr = area(b[i].rect + r) - r_area;
if (incr < min_incr) {
min_incr = incr;
mini = i;
}
}
R_page* p = b[mini].p;
R_page* q = p->insert(r, obj, level);
if (q == NULL) {
// child was not split
b[mini].rect += r;
return NULL;
} else {
// child was split
b[mini].rect = p->cover();
br.p = q;
br.rect = q->cover();
return add_branch(br);
}
} else {
br.p = (R_page*)obj;
br.rect = r;
return add_branch(br);
}
}
bool R_page::remove(rectangle const& r, object* obj,
int level, reinsert_list& rlist)
{
if (--level != 0) {
for (int i = 0; i < n; i++) {
if (b[i].rect & r) {
R_page* p = b[i].p;
if (p->remove(r, obj, level, rlist)) {
if (p->n >= min_fill) {
b[i].rect = p->cover();
} else {
// not enough entries in child
p->b[card-1].p = rlist.chain;
rlist.chain = p;
rlist.level = level - 1;
remove_branch(i);
}
return true;
}
}
}
} else {
for (int i = 0; i < n; i++) {
if (b[i].p == obj) {
remove_branch(i);
return true;
}
}
}
return false;
}
void R_page::purge(int level, bool remove_leaves)
{
if (--level != 0) { /* this is an internal node in the tree */
for (int i=0; i < n; i++) {
b[i].p->purge(level, remove_leaves);
}
} else { /* this is a leaf node */
if (remove_leaves) {
for (int i=0; i < n; i++) {
delete b[i].p;
}
}
}
delete this;
}
REGISTER(R_page);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -