#include <algorithm>
#include "kdtree.h"
void Container::addShape(Shape* aShape)
{
shapes.push_back(aShape);
if (shapes.size() == 0) {
/* initialize bounding box */
bbox = aShape->get_bbox();
} else {
/* adjust bounding box */
BBox shapebb = aShape->get_bbox();
if (shapebb.L.x < bbox.L.x) bbox.L.x = shapebb.L.x;
if (shapebb.L.y < bbox.L.y) bbox.L.y = shapebb.L.y;
if (shapebb.L.z < bbox.L.z) bbox.L.z = shapebb.L.z;
if (shapebb.R.x > bbox.R.x) bbox.R.x = shapebb.R.x;
if (shapebb.R.y > bbox.R.y) bbox.R.y = shapebb.R.y;
if (shapebb.R.z > bbox.R.z) bbox.R.z = shapebb.R.z;
}
};
void KdNode::subdivide(BBox bbox, int depth, int count)
{
int axis;
float pos;
//if (stopcriterionmet()) return
// choose split axis
axis = 0;
if (bbox.R.y - bbox.L.y > bbox.R.x - bbox.L.x)
axis = 1;
if (bbox.R.z - bbox.L.z > bbox.R.y - bbox.L.y)
axis = 2;
// *** find optimal split position
SortableShapeList sslist(shapes, axis);
sort(sslist.begin(), sslist.end());
SplitList splitlist = SplitList();
SortableShapeList::iterator sh;
for (sh = sslist.begin(); sh != sslist.end(); sh++)
{
splitlist.push_back(SplitPos(sh->bbox.L.cell[axis]));
splitlist.push_back(SplitPos(sh->bbox.R.cell[axis]));
}
sort(splitlist.begin(), splitlist.end());
// find all posible splits
SplitList::iterator split;
int rest;
for (split = splitlist.begin(); split != splitlist.end(); split++)
{
for (sh = sslist.begin(), rest = sslist.size(); sh != sslist.end(); sh++, rest--)
{
if (sh->hasMark())
continue;
// if shape is on left side of split plane
if (sh->bbox.R.cell[axis] <= split->pos)
{
sh->setMark();
split->lnum++;
}
// if shape is completely contained in split plane
if (sh->bbox.L.cell[axis] == sh->bbox.R.cell[axis] == split->pos)
{
if (split->pos - bbox.L.cell[axis] < bbox.R.cell[axis] - split->pos)
{
// left subcell is smaller -> if not empty, put shape here
if (split->lnum)
split->lnum++;
else
split->rnum++;
} else {
// right subcell is smaller
if (split->rnum)
split->rnum++;
else
split->lnum++;
}
}
// if shape is on right side of split plane
if (sh->bbox.L.cell[axis] >= split->pos)
{
split->rnum += rest;
break;
}
// if shape occupies both sides of split plane
if (sh->bbox.L.cell[axis] < split->pos && sh->bbox.R.cell[axis] > split->pos)
{
split->lnum++;
split->rnum++;
}
}
}
// choose best split pos
// ... //
KdNode *children = new KdNode[2];
ShapeList::iterator shape;
for (shape = shapes.begin(); shape != shapes.end(); shape++)
{
if (((Triangle*)*shape)->A.cell[axis-1] < pos
|| ((Triangle*)*shape)->B.cell[axis-1] < pos
|| ((Triangle*)*shape)->C.cell[axis-1] < pos)
children[0].addShape(*shape);
if (((Triangle*)*shape)->A.cell[axis-1] >= pos
|| ((Triangle*)*shape)->B.cell[axis-1] >= pos
|| ((Triangle*)*shape)->C.cell[axis-1] >= pos)
children[1].addShape(*shape);
}
bbox.R[axis-1] = pos;
children[0].subdivide(bbox, depth+1, children[0].shapes.size());
bbox.L[axis-1] = pos;
children[1].subdivide(bbox, depth+1, children[1].shapes.size());
}
void KdTree::build()
{
root = new KdNode();
root->shapes = shapes;
root->subdivide(bbox, 0, shapes.size());
}