mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-17 03:08:26 +00:00
svn -> git Migration
This commit is contained in:
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
|
||||
Father Nitwit's Fear Pathing File Maker Thing
|
||||
Copyright (C) 2005 Father Nitwit (eqemu@8ass.com)
|
||||
|
||||
I'll release thisunder the GPL, even though I hate the GPL.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
This is a modified quadtree that stores a list of all
|
||||
nodes reachable within a defined distance from the bounds
|
||||
of that quadtree node. Therefor this distance should be
|
||||
the maximum distance used to search for a node.
|
||||
|
||||
In case this distance is not big enough, we also store a
|
||||
complete list of reachable nodes at each quadtree level, so
|
||||
the root has all nodes for sure. This makes it possible to
|
||||
garuntee that we can find A node which is closest.
|
||||
|
||||
*/
|
||||
|
||||
#include "quadtree.h"
|
||||
#include "apathing.h"
|
||||
#include "../zone/map.h"
|
||||
|
||||
//#define SPLIT_DEBUG
|
||||
|
||||
QTNode::QTNode(Map *_map, float dist2, float Tminx, float Tmaxx, float Tminy, float Tmaxy) {
|
||||
node1 = NULL;
|
||||
node2 = NULL;
|
||||
node3 = NULL;
|
||||
node4 = NULL;
|
||||
minx = Tminx;
|
||||
maxx = Tmaxx;
|
||||
miny = Tminy;
|
||||
maxy = Tmaxy;
|
||||
map = _map;
|
||||
search_dist2 = dist2; //this is a distance-squared
|
||||
final = false;
|
||||
buildVertexes();
|
||||
|
||||
}
|
||||
|
||||
QTNode::~QTNode() {
|
||||
clearNodes();
|
||||
}
|
||||
|
||||
void QTNode::clearNodes() {
|
||||
if(node1 != NULL)
|
||||
delete node1;
|
||||
if(node2 != NULL)
|
||||
delete node2;
|
||||
if(node3 != NULL)
|
||||
delete node3;
|
||||
if(node4 != NULL)
|
||||
delete node4;
|
||||
node1 = NULL;
|
||||
node2 = NULL;
|
||||
node3 = NULL;
|
||||
node4 = NULL;
|
||||
}
|
||||
|
||||
|
||||
//assumes that both supplied arrays are big enough per countQTNodes/Facelists
|
||||
void QTNode::fillBlocks(PathTree_Struct *heads, PathPointRef *flist, unsigned long &hindex, unsigned long &findex) {
|
||||
PathTree_Struct *head = &heads[hindex];
|
||||
hindex++;
|
||||
|
||||
head->minx = minx;
|
||||
head->maxx = maxx;
|
||||
head->miny = miny;
|
||||
head->maxy = maxy;
|
||||
head->flags = 0;
|
||||
//printf("Node %u: (%.2f -> %.2f, %.2f -> %.2f)\n", hindex-1, head->minx, head->maxx, head->miny, head->maxy);
|
||||
|
||||
//rearranged to give all QT nodes a node list
|
||||
head->nodelist.count = nodes.size();
|
||||
head->nodelist.offset = findex;
|
||||
//printf(" Final node with %u nodes, list offset %lu.\n", head->nodes.count, head->nodes.offset);
|
||||
list<PathNode *>::iterator curs,end;
|
||||
curs = nodes.begin();
|
||||
end = nodes.end();
|
||||
for(; curs != end; curs++) {
|
||||
//printf("Got to node index %d (0x%x)\n", findex, *curs);
|
||||
PathNode *cur = *curs;
|
||||
flist[findex] = cur->node_id;
|
||||
findex++;
|
||||
}
|
||||
// findex += head->nodes.count;
|
||||
|
||||
|
||||
if(final) {
|
||||
head->flags |= pathNodeFinal;
|
||||
} else {
|
||||
head->flags = 0;
|
||||
//branch node.
|
||||
|
||||
if(node1 != NULL) {
|
||||
head->nodes[0] = hindex;
|
||||
node1->fillBlocks(heads, flist, hindex, findex);
|
||||
} else {
|
||||
head->nodes[0] = PATH_NODE_NONE;
|
||||
}
|
||||
if(node2 != NULL) {
|
||||
head->nodes[1] = hindex;
|
||||
node2->fillBlocks(heads, flist, hindex, findex);
|
||||
} else {
|
||||
head->nodes[1] = PATH_NODE_NONE;
|
||||
}
|
||||
if(node3 != NULL) {
|
||||
head->nodes[2] = hindex;
|
||||
node3->fillBlocks(heads, flist, hindex, findex);
|
||||
} else {
|
||||
head->nodes[2] = PATH_NODE_NONE;
|
||||
}
|
||||
if(node4 != NULL) {
|
||||
head->nodes[3] = hindex;
|
||||
node4->fillBlocks(heads, flist, hindex, findex);
|
||||
} else {
|
||||
head->nodes[3] = PATH_NODE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long QTNode::countQTNodes() const {
|
||||
unsigned long c = 1;
|
||||
if(node1 != NULL)
|
||||
c += node1->countQTNodes();
|
||||
if(node2 != NULL)
|
||||
c += node2->countQTNodes();
|
||||
if(node3 != NULL)
|
||||
c += node3->countQTNodes();
|
||||
if(node4 != NULL)
|
||||
c += node4->countQTNodes();
|
||||
return(c);
|
||||
}
|
||||
|
||||
/*unsigned long QTNode::countNodes() const {
|
||||
unsigned long c = nodes.size();
|
||||
if(node1 != NULL)
|
||||
c += node1->countNodes();
|
||||
if(node2 != NULL)
|
||||
c += node2->countNodes();
|
||||
if(node3 != NULL)
|
||||
c += node3->countNodes();
|
||||
if(node4 != NULL)
|
||||
c += node4->countNodes();
|
||||
return(c);
|
||||
}*/
|
||||
|
||||
unsigned long QTNode::countPathNodes() const {
|
||||
// unsigned long c = final? nodes.size() : 0;
|
||||
unsigned long c = nodes.size();
|
||||
if(node1 != NULL)
|
||||
c += node1->countPathNodes();
|
||||
if(node2 != NULL)
|
||||
c += node2->countPathNodes();
|
||||
if(node3 != NULL)
|
||||
c += node3->countPathNodes();
|
||||
if(node4 != NULL)
|
||||
c += node4->countPathNodes();
|
||||
return(c);
|
||||
}
|
||||
|
||||
void QTNode::divideYourself(int depth) {
|
||||
// printf("Dividing in box (%.2f -> %.2f, %.2f -> %.2f) at depth %d with %d nodes.\n",
|
||||
// minx, maxx, miny, maxy, depth, nodes.size());
|
||||
|
||||
unsigned long cc;
|
||||
cc = nodes.size();
|
||||
#ifdef MAX_QUADRENT_NODES
|
||||
if(cc <= MAX_QUADRENT_NODES) {
|
||||
#ifdef SPLIT_DEBUG
|
||||
printf("Stopping (nodecount) on box (%.2f -> %.2f, %.2f -> %.2f) at depth %d with %d nodes.\n",
|
||||
minx, maxx, miny, maxy, depth, cc);
|
||||
#endif
|
||||
final = true;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MIN_QUADRENT_SIZE
|
||||
if((maxx - minx) < MIN_QUADRENT_SIZE || (maxy - miny) < MIN_QUADRENT_SIZE) {
|
||||
#ifdef SPLIT_DEBUG
|
||||
printf("Stopping on box (size) (%.2f -> %.2f, %.2f -> %.2f) at depth %d with %d nodes.\n",
|
||||
minx, maxx, miny, maxy, depth, cc);
|
||||
#endif
|
||||
final = true;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
doSplit();
|
||||
|
||||
//get counts on our split
|
||||
float c1, c2, c3, c4;
|
||||
c1 = node1? node1->nodes.size() : 0;
|
||||
c2 = node2? node2->nodes.size() : 0;
|
||||
c3 = node3? node3->nodes.size() : 0;
|
||||
c4 = node4? node4->nodes.size() : 0;
|
||||
|
||||
#ifdef MIN_QUADRENT_GAIN
|
||||
int miss = 0;
|
||||
float gain1 = 1.0 - c1 / cc;
|
||||
float gain2 = 1.0 - c2 / cc;
|
||||
float gain3 = 1.0 - c3 / cc;
|
||||
float gain4 = 1.0 - c4 / cc;
|
||||
|
||||
//see how many missed the gain mark
|
||||
if(gain1 < MIN_QUADRENT_GAIN)
|
||||
miss++;
|
||||
if(gain2 < MIN_QUADRENT_GAIN)
|
||||
miss++;
|
||||
if(gain3 < MIN_QUADRENT_GAIN)
|
||||
miss++;
|
||||
if(gain4 < MIN_QUADRENT_GAIN)
|
||||
miss++;
|
||||
|
||||
if(miss > MAX_QUADRENT_MISSES) {
|
||||
#ifdef SPLIT_DEBUG
|
||||
printf("Stopping (gain) on box (%.2f -> %.2f, %.2f -> %.2f) at depth %d with %d nodes.\n",
|
||||
minx, maxx, miny, maxy, depth, cc);
|
||||
#endif
|
||||
final = true;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//if all nodes pass through all quadrents, then we are done
|
||||
//partially obsoleted by gain test.
|
||||
if(c1 == c2 && c1 == c3 && c1 == c4) {
|
||||
#ifdef SPLIT_DEBUG
|
||||
printf("Stopping (empty) on box (%.2f -> %.2f, %.2f -> %.2f) at depth %d with %d nodes.\n",
|
||||
minx, maxx, miny, maxy, depth, cc);
|
||||
printf("Our counts: %.3f, %.3f, %.3f, %.3f\n", c1, c2, c3, c4);
|
||||
#endif
|
||||
final = true;
|
||||
return;
|
||||
}
|
||||
|
||||
//there are prolly some more intelligent stopping criteria...
|
||||
|
||||
depth++;
|
||||
|
||||
if(node1 != NULL)
|
||||
node1->divideYourself(depth);
|
||||
if(node2 != NULL)
|
||||
node2->divideYourself(depth);
|
||||
if(node3 != NULL)
|
||||
node3->divideYourself(depth);
|
||||
if(node4 != NULL)
|
||||
node4->divideYourself(depth);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void QTNode::buildVertexes() {
|
||||
|
||||
v[0].x = v[1].x = v[2].x = v[3].x = minx;
|
||||
v[4].x = v[5].x = v[6].x = v[7].x = maxx;
|
||||
|
||||
v[0].y = v[1].y = v[4].y = v[5].y = miny;
|
||||
v[2].y = v[3].y = v[6].y = v[7].y = maxy;
|
||||
|
||||
v[0].z = v[3].z = v[4].z = v[7].z = -999999;
|
||||
v[1].z = v[2].z = v[5].z = v[6].z = 9999999;
|
||||
}
|
||||
|
||||
bool QTNode::IsInNode(const QTNode *n, const PathNode *o) {
|
||||
//printf("IIN: (%.3f,%.3f) in (%.3f -> %.3f, %.3f -> %.3f)\n", o->x, o->y, n->minx, n->maxx, n->miny, n->maxy);
|
||||
if( o->x >= n->minx && o->x < n->maxx
|
||||
&& o->y >= n->miny && o->y < n->maxy )
|
||||
return(true);
|
||||
|
||||
//well its not inside the node, so see if it is reachable from it
|
||||
|
||||
//4 points of this node
|
||||
GPoint pt1(n->minx, n->miny, 0),
|
||||
pt2(n->minx, n->maxy, 0),
|
||||
pt3(n->maxx, n->miny, 0),
|
||||
pt4(n->maxx, n->maxy, 0);
|
||||
if( o->Dist2(&pt1) < search_dist2
|
||||
|| o->Dist2(&pt2) < search_dist2
|
||||
|| o->Dist2(&pt3) < search_dist2
|
||||
|| o->Dist2(&pt4) < search_dist2)
|
||||
return(true);
|
||||
|
||||
//not inside, and not reachable...
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
void QTNode::doSplit() {
|
||||
|
||||
|
||||
//find midpoints...
|
||||
float midx = minx + (maxx - minx) / 2.0;
|
||||
float midy = miny + (maxy - miny) / 2.0;
|
||||
|
||||
//ordering following definitions in map.h
|
||||
node1 = new QTNode(map, search_dist2, midx, maxx, midy, maxy);
|
||||
node2 = new QTNode(map, search_dist2, minx, midx, midy, maxy);
|
||||
node3 = new QTNode(map, search_dist2, minx, midx, miny, midy);
|
||||
node4 = new QTNode(map, search_dist2, midx, maxx, miny, midy);
|
||||
if(node1 == NULL || node2 == NULL || node3 == NULL || node4 == NULL) {
|
||||
printf("Error: unable to allocate new QTNode, giving up.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// unsigned long l;
|
||||
// l = faces.size();
|
||||
// for(r = 0; r < l; r++) {
|
||||
// PathNode *cur = faces[r];
|
||||
list<PathNode *>::iterator curs,end;
|
||||
curs = nodes.begin();
|
||||
end = nodes.end();
|
||||
for(; curs != end; curs++) {
|
||||
PathNode *cur = *curs;
|
||||
if(IsInNode(node1, cur))
|
||||
node1->nodes.push_back(cur);
|
||||
if(IsInNode(node2, cur))
|
||||
node2->nodes.push_back(cur);
|
||||
if(IsInNode(node3, cur))
|
||||
node3->nodes.push_back(cur);
|
||||
if(IsInNode(node4, cur))
|
||||
node4->nodes.push_back(cur);
|
||||
}
|
||||
|
||||
//clean up empty sets.
|
||||
if(node1->nodes.size() == 0) {
|
||||
delete node1;
|
||||
node1 = NULL;
|
||||
}
|
||||
if(node2->nodes.size() == 0) {
|
||||
delete node2;
|
||||
node2 = NULL;
|
||||
}
|
||||
if(node3->nodes.size() == 0) {
|
||||
delete node3;
|
||||
node3 = NULL;
|
||||
}
|
||||
if(node4->nodes.size() == 0) {
|
||||
delete node4;
|
||||
node4 = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user