Как покрыть сектор (расширяющийся луч, конус и т.д.) равноудаленными точками (шаблон шахматных плиток)?

#javascript #java #c# #algorithm #geometry

#javascript #java #c# #алгоритм #геометрия

Вопрос:

Предположим, что есть исходная точка s = (x, y) и два угла a и b. Углы создают луч, световой конус из точки p. Я хотел бы получить список точек, которые находятся в пределах этой области и находятся на одинаковом расстоянии друг от друга по вертикали и горизонтали. Максимальное расстояние теоретически бесконечно (но ограничено чем-то другим, не рассматриваемым в этом алгоритме).

введите описание изображения здесь

Я пробовал рекурсивный метод, и он работал для более широких углов. Для острых углов количество соседних квадратов должно было увеличиться, чтобы не получилось. Я попытался следовать одной из линий, описанных углами, и подсчитывать все точки внутри углов, расположенных вертикально. Это не удалось из-за вертикальных линий и стало очень беспорядочным из-за разных квадрантов и т.д. Я попытался применить двойную for-петлю грубой силы, но это заканчивается из-за избытка глупых точек, когда я увеличил степень детализации.

Мне нужна помощь, чтобы переформулировать проблему таким образом, чтобы она была более доступной. Я кодирую решение на C #, но, очевидно, проблема не зависит от технологии, поэтому подойдет что угодно.

Комментарии:

1. Обрабатывайте каждый квадрант отдельно; объединяйте точки, если лучи находятся в разных квадрантах. Когда оба луча находятся в одном и том же квадранте, либо (i) они оба <= 45 градусов, (ii) оба > 45 градусов, либо (iii) один ниже, а другой выше 45 градусов. Для (i) переместите алгоритм Брезенхэма вправо вдоль оси x, чтобы найти для каждого x самую нижнюю и самую верхнюю точки y между двумя лучами. Для (ii) сделайте то же самое, но продолжайте вверх по оси y. Для (iii) нарисуйте третий луч c ровно под углом 45 градусов, решите подзадачи для пар лучей (a, c) и (b, c) и сформируйте объединение. (Могут быть более быстрые способы.)

Ответ №1:

Для углов A и B в диапазоне -Pi/2..Pi/2 и B>A рассмотрим следующий подход: пусть начальной точкой луча будет (x0, y0) .

Тогда вертикальная линия сетки с координатами x1 будет содержать точки сетки внутри сектора, которые имеют координаты y в диапазоне

   Ceil(y0   (x1-x0) * tg(A)) .. Floor(y0   (x1-x0) * tg(B))
  

Ceil округляется вверх, Floor округляется вниз (этот Y-диапазон может быть пустым)

Этот подход работает для углов в диапазоне Pi/2..3Pi/2 , если мы поменяемся углами. И для углов в разных полуплоскостях, если мы разделим сектор на x0 по вертикали на 2 части.
Другой способ — использовать горизонтальные линии развертки вместо вертикальных для некоторых ориентаций.

Комментарии:

1. Как насчет случаев, когда конус идет вертикально? Или если он попадает в два квадранта (скажем, между строками -1,1 и 1,1)? Довольно быстро все становится очень запутанным. Я чувствую, что должно быть простое решение, если я подхожу к проблеме под другим углом (угол, понял, хе-хе)…

2. Как я уже сказал, разделите такой конус вертикальной осью. (1,1)- (-1,1) должно дать (1,1)- (0,1) и (0,1)-(-1,1). Вы можете рассмотреть также горизонтальные линии развертки вместо вертикальных для такой ориентации конуса. Примечание — это довольно простое решение, оно дает целые диапазоны координат.

3. Теперь я понимаю, что вы имеете в виду. Довольно быстро все становится таким сомнительным, хе-хе. И, конечно, поскольку я имею дело с удвоениями, мне нужно будет это учитывать (вместо настила мне придется округлить его до определенного кратного чему-то). Я думаю, это просто неприятная проблема, поэтому потребуется неприятное решение. Спасибо, друг!

Ответ №2:

Идея состояла бы в том, чтобы сформулировать конус как линии, определяемые уравнениями:

строка 1: A1x B1y C1= 0

строка 2: A2x B2y C2= 0

Это означает, что любая точка, принадлежащая линии, удовлетворяет ее уравнению. И точки, расположенные выше, дают положительный результат, а расположенные ниже — отрицательный.

Точка, которую вы ищете, скажем, ниже line1 и выше line2… и на некоторой сетке.

Комментарии:

1. Что вы имеете в виду? Единственное дополнительное требование, чтобы линии не были параллельными для создания конуса. С этими двумя линиями вы фактически получили 4 конуса. Чтобы выбрать один из них, вы должны добавить ограничение для требуемого знака формулы линии.