⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtree.cxx

📁 完全免费的邮件发送程序。delphi 6.0
💻 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 + -