Я сейчас пользуюсь Irrlicht Engine
реализовать QuickHull
Алгоритм в 3D. Пользователь сможет пошагово проходить алгоритм по нажатию клавиш, переходя через каждый отдельный шаг.
Я хотел бы сделать это независимо от основного цикла рендеринга, чтобы не останавливать всю симуляцию в ожидании пользовательского ввода; пользователь должен иметь возможность перемещать камеру и видеть, что происходит.
У меня сейчас есть QuickHull
контейнерный класс со всеми точками и отрезками и методом для алгоритма. Как заставить этот метод приостанавливать работу по требованию и ждать ввода пользователя, не останавливая цикл рендеринга или случайно не прерывая рекурсию по мере продвижения цикла рендеринга?
Следующее не является лучшим решением в отношении памяти, но может работать:
Когда пользователь запускает QuickHull, фактически запускается все решение. ОДНАКО, сохраняйте промежуточные состояния на ходу. В худшем случае, QHull требуется O (n) памяти, если все точки лежат на выпуклой оболочке (то есть выпуклом многоугольнике) и работают в O (n2), поэтому, если вы генерируете промежуточные состояния, вам нужно хранить векторы размером 1, 2, 3, …, n, чтобы представлять оболочку на каждом этапе, что может привести к общей дополнительной памяти O ( N3).
По мере постепенного создания корпуса создайте для каждой итерации новый набор точек, представляющих, как выглядит корпус в данный момент времени. Чтобы представить созданную выпуклую оболочку, добавьте узлы сферической сцены для каждой точки корпуса по мере продвижения.
Вы можете добавить сферу к сцене с помощью irr::scene::ISceneManager::addSphereSceneNode(radius)
функция, которая возвращает IMeshSceneNode*
что вы можете вставить в вектор, представляющий выпуклую оболочку в этом состоянии.
Чтобы показать ребра между этими точками, вам нужно нарисовать линии между вашими сферами. Таким образом, для каждой точки в текущем корпусе проведите линию между ними (также линию между последней и первой)
Вы можете нарисовать линию с draw3DLine
команда в irr::video::IVideoDriver
вроде такой:
irr::video::SMaterial lineMaterial;
lineMaterial.Lighting = false;
lineMaterial.Thickness = 2.0f;
lineMaterial.FrontfaceCulling = false;
lineMaterial.BackfaceCulling = false;
lineMaterial.MaterialType = irr::video::EMT_SOLID;
_driver->setMaterial(lineMaterial);
_driver->setTransform(irr::video::ETS_WORLD,
irr::core::IdentityMatrix);
//draw a line
irr::core::vector3df lineStart,lineEnd; //set these equal to 2 adjacent vertices on your hull
_driver->draw3DLine(lineStart,lineEnd,irr::video::SColor(0.0,0.0,0.0,205)); //blue line
Изначально все IMeshSceneNode*
что вы добавили на сцену должно быть невидимым. Используйте команду void irr::scene::ISceneNode::setVisible(bool isVisible)
на каждой сфере в ваших векторах, когда вы их создаете.
Теперь, после запуска алгоритма QHull, вы можете создать индекс для вашего вектора состояний (где каждое состояние представляет оболочку на временном шаге, который сам по себе является вектором).
При увеличении индекса вы можете установить все сферы в текущем состоянии (до увеличения) в невидимые, а затем сделать все сферы в следующем состоянии видимыми.
Ваш основной цикл рендеринга также должен вызывать некоторую функцию, которая рендерит ребра в текущем состоянии ConvexHull.
Хорошая вещь в этой модели заключается в том, что теперь пользователь может идти вперед и назад, чтобы увидеть, как продвигается алгоритм. Если вы только идете вперед, то вместо того, чтобы сделать предыдущие узлы, представляющие корпус, невидимыми, вы можете полностью удалить их со сцены.
Также с этой моделью нам не нужно пытаться приостановить алгоритм QHull в середине выполнения, используя некоторую странную многопоточную модель, и нам не нужно сильно изменять сам алгоритм, чтобы он мог приостанавливать и возобновлять работу. Вы просто визуализируете текущее состояние корпуса в каждом кадре, позволяя перемещать камеру и смотреть на нее, как вы хотите, а затем просто обновлять корпус нажатием кнопки, используя свой собственный EventReceiver
учебный класс.
Других решений пока нет …