Итак, я реализую свое первое дерево BSP, и я думаю, что обнаружил недостаток в своей логике. Я довольно потерян относительно того, как я мог бы реально реорганизовать это правильно, чтобы работать так, как должно.Двоичное пространственное разделение - ошибка в логике разбиения пространства
Вот конструктор (объяснение следует):
BSPTree::BSPTree(const polygonList_t& list)
: mRoot(nullptr)
{
polygonList_t front, back;
auto eol = list.end();
Polygon* rootSplitter = list[ 0 ];
vec3 rootSplitPos;
rootSplitter->GetPosition(rootSplitPos);
for(auto iPoly = list.begin() + 1; iPoly != eol; ++iPoly)
{
vec3 resolvePos;
(*iPoly)->GetPosition(resolvePos);
switch(ResolvePosition(rootSplitPos, resolvePos))
{
case POSITION_FRONT:
front.push_back(*iPoly);
break;
case POSITION_BACK:
back.push_back(*iPoly);
break;
case POSITION_SPLIT:
{
Polygon* toSplit = *iPoly;
list.erase(iPoly);
Polygon* outFront = new Polygon;
Polygon* outBack = new Polygon;
SplitPolygon(resolvePos, toSplit, outFront, outBack);
front.push_back(outFront);
back.push_back(outBack);
// finally we kill this one off
delete toSplit;
toSplit = nullptr;
}
break;
}
}
mRoot = BSP_MakeNode();
mRoot->splitter = rootSplitter;
SplitSpace(mRoot, front);
SplitSpace(mRoot, back);
}
В двух словах, мы получаем typedeffed std::vector< Polygon* >
с произвольным числом кучных распределёнными объектов Polygon. Затем мы хотим разделить их на две категории: те, которые находятся перед определенным элементом центра, и те, что стоят. Естественно, мы объявляем два списка одного и того же typedef и называем их front
и back
соответственно.
Сначала мы выбираем Polygon (в конце концов, я бы хотел найти многоугольник, который наилучшим образом подходит для плоскости разбиения корня), а затем мы перебираем исходный список, проверяя один из 3-х случаев:
(Примечание - для краткости, я просто хочу, чтобы перезаписать наш корневой раздел многоугольник, как корень)
POSITION_FRONT
: Мы знаем, что наш текущий полигон в списке находится перед корень, поэтому мы естественно добавляем этот многоугольник в наш передний список.POSITION_BACK
: То же, что и положение, с той лишь разницей, что этот многоугольник находится за корень.POSITION_SPLIT
: Мы не можем определить, является ли этот полигон находится в передней части корня или позади него, поэтому мы разделили его на две части и вставьте передние и заднюю ее части в соответствующие списки.
Наконец, когда мы разделили наши многоугольники в их передних и задних списков, мы также подразделяют наше пространство, используя корень в качестве основы для первоначального расчленения.
void BSPTree::SplitSpace(bspNode_t* node, polygonList_t& polygons)
{
if (polygons.size() == 0) return;
// grab the first polygon within the list,
// and then subtract it from the list itself.
Polygon* next = polygons[ 0 ];
polygons.pop_back();
vec3 splitPos;
node->splitter->GetPosition(splitPos);
vec3 toResolve;
next->GetPosition(toResolve);
switch(ResolvePosition(splitPos, toResolve))
{
case POSITION_FRONT:
node->front = BSP_MakeNode();
node->front->splitter = next;
SplitSpace(node->front, polygons);
break;
case POSITION_BACK:
node->back = BSP_MakeNode();
node->back->splitter = next;
SplitSpace(node->back, polygons);
break;
case POSITION_SPLIT:
{
Polygon* outFront = new Polygon;
Polygon* outBack = new Polygon;
SplitPolygon(toResolve, next, outFront, outBack);
node->front = BSP_MakeNode();
node->back = BSP_MakeNode();
node->front->splitter = outFront;
node->back->splitter = outBack;
SplitSpace(node->front, polygons);
SplitSpace(node->back, polygons);
}
break;
}
}
Теперь мы выполняем очень похожую последовательность операций, основное различие в том, что мы дополнительно подразделяя уже разделенное пространство, пока каждый полигон не имеет заданную позицию в дереве узлов, который является либо перед или за его родительским узлом. Конечно, мы делаем это рекурсивно.
Проблема я в настоящее время видим, лежит в оценке в POSITION_SPLIT
случае в заявлении выключателя выше:
case POSITION_SPLIT:
{
Polygon* outFront = new Polygon;
Polygon* outBack = new Polygon;
SplitPolygon(toResolve, next, outFront, outBack);
node->front = BSP_MakeNode();
node->back = BSP_MakeNode();
node->front->splitter = outFront;
node->back->splitter = outBack;
SplitSpace(node->front, polygons); // here
SplitSpace(node->back, polygons); // and here
}
В сочетании с двумя другими факторами:
Для каждого многоугольника, полученного из заданный ссылочный параметр
polygons
, мы укажем указатель, который содержит этот многоугольник в списке после присвоения его временному.Взаимодействие с вышеупомянутым, каждый вызов
SplitSpace(...)
дает чек, чтобы узнать, пуст ли его принятый список. Если это так, ничего не делается, и для этого списка завершено рекурсивное подразделение.
Из-за этих двух факторов, я не могу не думать, что, в случае оценки по POSITION_SPLIT
, второй вызов SplitSpace(...)
бесполезно: список будет исчерпан до второго вызова (для размещения для назад часть раскола).
Вопрос
Итак, что решение этой проблемы, которая, по крайней мере, получить меня возглавили назад на правильном пути?
пожалуйста сделайте [SSCCE] (http://sscce.org/) – TemplateRex
извините, я не верю SSCCE актуально здесь: вопрос, который я m сталкивается с понятиями и алгоритмом в частности, а также ошибкой в моей собственной логике с реализацией. Разумеется, если вы можете объяснить, почему SSCCE поможет, я с удовольствием создам его. – zeboidlund
Некоторые люди любят сначала компилировать и запускать, задавать вопросы позже. Когда я устал, я склонен пропускать вопросы, которые не компилируются. Это только мой собственный недостаток, конечно ... –