Обновление: оставив комментарий ниже для потомков
Я сейчас использую код, представленный здесь: https://www.redblobgames.com/grids/hexagons/
Действительно важным примечанием является то, что ваш шестиугольникСетка ДОЛЖНА начинаться с середины первых шестиугольников в (0, 0) - если этого не произойдет, вы получите чрезвычайно странные результаты, которые на первый взгляд выглядят как ошибки округления (даже после учета ожидаемого смещения).Для меня не имело значения, где был расположен первый шестиугольник, поэтому я просто установил его на (0, 0), и он отлично работал.
Старое решение
Я все еще надеюсь на оптимальное решение, но в итоге я выбрал свой собственный, который должен проверять только 6 шестиугольников на точку, с дополнительными затратами (приблизительно sqrt(m)
), необходимыми дополнительно.
При приблизительно 3000 точках и 768 шестиугольниках (из которых 310 были заполнены), он правильно назначил точку шестиугольнику в 100% случаев (при проверке методом грубой силы) и занял 29 миллисекунд по сравнениюдо ~ 840 с грубой силой.
Для начала я храню шестиугольники на карте, где ключом является "${column},${row}"
.Столбцы технически перекрываются, поэтому для 0-й строки 0-й столбец начинается с -0.5 * hexWidth
, а для строки 1 0-й столбец начинается с 0px
.
Далее я начинаю с позиции верхнего левого шестиугольника, позиция "0,0"
, которая также должна быть в позиции 0, и увеличиваю y
либо на высоту шестиугольника, либо на длину краяшестиугольник соответственно.Когда y
это> точки y
, я нашел вероятную строку, затем я проверяю строку выше и ниже.
Для столбца в строке я беру оба значения Math.floor
и Math.ceil
из x / hexWidth
.
В результате получается 6 шестиугольников для проверки, с этого момента решениеидентично решению в вопросе.
Теоретически, это можно использовать, чтобы просто найти правильный шестиугольник, используя позицию x / y.Однако на практике это не сработало для меня примерно в 5% случаев с ошибками off на 1, вероятно, это проблема округления.
Некоторые другие вещи, на которые я смотрел:
Как подсказывает @ jason-aller, https://www.redblobgames.com/grids/hexagons/#rounding. К сожалению, это, кажется, предполагает некоторую форму преобразования нашестнадцатеричная сетка (повороты), и за ней нелегко следить - постоянно ссылаясь на функции, которые еще предстоит определить.
QuadTree (различные реализации), к сожалению, это вернуло примерно 100 «потенциальных совпадений» для каждой точки - поэтому улучшение производительности было не очень хорошим.Я знаю, что порядок вставки меняет полезность QuadTree, я пробовал естественный порядок, отсортированный по расстоянию сверху, слева и в случайном порядке, все они одинаково плохо работали.Вполне вероятно, что оптимальное решение с QuadTree предполагает заполнение дерева элементом, ближайшим к средней точке, а затем элементами 1/2 от средней точки до каждого угла, рекурсивно.Слишком похоже на тяжелую работу для меня!