Попадание луча между двумя другими лучами
От: 777777w Россия  
Дата: 19.12.13 06:23
Оценка:
Дан угол, под которым луч выходит из начала координат (от -180 до 180) и угол на который он поворачивается (от -360 до 360). Требуется определить, пересечет ли он третий луч, угол которого также задан.

Есть ли какой-то простой алгоритм? Или нужно писать кучу if-ов учитывая пересечение первым лучом нуля, 180 или -180 градусов?
Re: Попадание луча между двумя другими лучами
От: Dorofey Россия  
Дата: 19.12.13 06:28
Оценка:
Здравствуйте, 777777w, Вы писали:

7>Дан угол, под которым луч выходит из начала координат (от -180 до 180) и угол на который он поворачивается (от -360 до 360). Требуется определить, пересечет ли он третий луч, угол которого также задан.


Третий? А где второй?

7>Есть ли какой-то простой алгоритм? Или нужно писать кучу if-ов учитывая пересечение первым лучом нуля, 180 или -180 градусов?


Бррр, какие кучу if-ов? Ты хочешь написать 360 if-ов? Вау, индиан стайл солюшн
Re[2]: Попадание луча между двумя другими лучами
От: 777777w Россия  
Дата: 19.12.13 06:38
Оценка:
Здравствуйте, Dorofey, Вы писали:

7>>Дан угол, под которым луч выходит из начала координат (от -180 до 180) и угол на который он поворачивается (от -360 до 360). Требуется определить, пересечет ли он третий луч, угол которого также задан.


D>Третий? А где второй?


Второй это положение первого после поворота.

7>>Есть ли какой-то простой алгоритм? Или нужно писать кучу if-ов учитывая пересечение первым лучом нуля, 180 или -180 градусов?


D>Бррр, какие кучу if-ов? Ты хочешь написать 360 if-ов? Вау, индиан стайл солюшн


Чтобы было понятно — конкретный пример. Первый луч +10 градусов, поворачивается на -340 градусов. Пересечет ли он луч -20 градусов? +170? +20? Напиши выражение возвращающее bool.
Re: Попадание луча между двумя другими лучами
От: Cyberax Марс  
Дата: 19.12.13 06:41
Оценка:
Здравствуйте, 777777w, Вы писали:

7>Есть ли какой-то простой алгоритм? Или нужно писать кучу if-ов учитывая пересечение первым лучом нуля, 180 или -180 градусов?

Строим уравнения прямых, на которых лежат лучи. Ищем точку пересечения и проверяем, что она лежит в границах луча.

Если луч 1 повёрнут на угол alpha радиан, то уравнение его прямой будет:
-x*sin(alpha) + y*cos(alpha) = 0

Уравнение второго луча считается как обычно.
Sapienti sat!
Re[2]: Попадание луча между двумя другими лучами
От: 777777w Россия  
Дата: 19.12.13 06:45
Оценка:
Здравствуйте, Cyberax, Вы писали:

7>>Есть ли какой-то простой алгоритм? Или нужно писать кучу if-ов учитывая пересечение первым лучом нуля, 180 или -180 градусов?

C>Строим уравнения прямых, на которых лежат лучи. Ищем точку пересечения и проверяем, что она лежит в границах луча.

Точка пересечения лучей всегда будет в начале координат независимо от углов.
Re[3]: Попадание луча между двумя другими лучами
От: Dorofey Россия  
Дата: 19.12.13 07:01
Оценка:
Здравствуйте, 777777w, Вы писали:

7>Чтобы было понятно — конкретный пример. Первый луч +10 градусов, поворачивается на -340 градусов. Пересечет ли он луч -20 градусов? +170? +20? Напиши выражение возвращающее bool.


if (testAngle > startAngle &&
testAngle < (startAngle+rotateAngle))

не?
Re[3]: Попадание луча между двумя другими лучами
От: Cyberax Марс  
Дата: 19.12.13 07:09
Оценка:
Здравствуйте, 777777w, Вы писали:

7>>>Есть ли какой-то простой алгоритм? Или нужно писать кучу if-ов учитывая пересечение первым лучом нуля, 180 или -180 градусов?

C>>Строим уравнения прямых, на которых лежат лучи. Ищем точку пересечения и проверяем, что она лежит в границах луча.
7>Точка пересечения лучей всегда будет в начале координат независимо от углов.
Можно детально задачу с рисунком?
Sapienti sat!
Re[4]: Попадание луча между двумя другими лучами
От: 777777w Россия  
Дата: 19.12.13 07:29
Оценка:
Здравствуйте, Dorofey, Вы писали:

D>Здравствуйте, 777777w, Вы писали:


7>>Чтобы было понятно — конкретный пример. Первый луч +10 градусов, поворачивается на -340 градусов. Пересечет ли он луч -20 градусов? +170? +20? Напиши выражение возвращающее bool.


D>if (testAngle > startAngle &&

D> testAngle < (startAngle+rotateAngle))

D>не?


Не. Вышеприведенный пример не прокатывает если testAngle = -170

В том-то и проблема, что это углы, а не расстояния. С углами всегда проблемы.
Re[4]: Попадание луча между двумя другими лучами
От: 777777w Россия  
Дата: 19.12.13 07:38
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Можно детально задачу с рисунком?




Известен угол луча 1 и угол, на который он поворачивается рисуя дугу. (В данном случае — примерно 10 градусов и поворот на -340 градусов.)

Требуется узнать, попадают ли в эту дугу лучи 2 и 3, углы которых также известны.
Re: Попадание луча между двумя другими лучами
От: MBo  
Дата: 19.12.13 07:48
Оценка: 1 (1)
Здравствуйте, 777777w, Вы писали:

7>Дан угол, под которым луч выходит из начала координат (от -180 до 180) и угол на который он поворачивается (от -360 до 360). Требуется определить, пересечет ли он третий луч, угол которого также задан.


7>Есть ли какой-то простой алгоритм? Или нужно писать кучу if-ов учитывая пересечение первым лучом нуля, 180 или -180 градусов?


Луч заметает некий интервал углов на окружности. Приводим этот интервал к полностью неотрицательному, добавляя при необходимости 2Pi или 4Pi так, чтобы левая точка интервала (неважно, начало это, или конец) стала неотрицательной, и лежала в диапазоне [0, 2Pi). Потом третью точку тоже делаем неотрицательной, и проверяем, что или она (X) или (X+2Pi) лежит внутри интервала
Re[2]: Попадание луча между двумя другими лучами
От: Stanislav V. Zudin Россия  
Дата: 19.12.13 08:08
Оценка:
Здравствуйте, MBo, Вы писали:

MBo>Луч заметает некий интервал углов на окружности. Приводим этот интервал к полностью неотрицательному, добавляя при необходимости 2Pi или 4Pi так, чтобы левая точка интервала (неважно, начало это, или конец) стала неотрицательной, и лежала в диапазоне [0, 2Pi). Потом третью точку тоже делаем неотрицательной, и проверяем, что или она (X) или (X+2Pi) лежит внутри интервала


Добавлю, стоит еще разворачивать дугу, чтобы направление всегда было CW или CCW (смотря что выбрано за положительное направление).
Тогда пасьянс сходится.
_____________________
С уважением,
Stanislav V. Zudin
Re[3]: Попадание луча между двумя другими лучами
От: MBo  
Дата: 19.12.13 08:13
Оценка:
Здравствуйте, Stanislav V. Zudin, Вы писали:

SVZ>Добавлю, стоит еще разворачивать дугу, чтобы направление всегда было CW или CCW (смотря что выбрано за положительное направление).


Собственно, интервал (отрезок) ненаправленный, поэтому ориентация уже волновать не будет.
Re[4]: Попадание луча между двумя другими лучами
От: Stanislav V. Zudin Россия  
Дата: 19.12.13 08:35
Оценка:
Здравствуйте, MBo, Вы писали:

MBo>Здравствуйте, Stanislav V. Zudin, Вы писали:


SVZ>>Добавлю, стоит еще разворачивать дугу, чтобы направление всегда было CW или CCW (смотря что выбрано за положительное направление).


MBo>Собственно, интервал (отрезок) ненаправленный, поэтому ориентация уже волновать не будет.


Нашел контрпример, когда алгоритм не сработает.

Поискал у себя в закромах.
В общем достаточно посчитать векторное произведение векторов SD и SE.
D — точка пересечения луча и окружности,
S — начало дуги, E — конец дуги.



Знак произведения показывает, попадает луч в дугу или нет.
В этом случае направление дуги не важно.
_____________________
С уважением,
Stanislav V. Zudin
Re[5]: Попадание луча между двумя другими лучами
От: 777777w Россия  
Дата: 19.12.13 10:38
Оценка:
Здравствуйте, Stanislav V. Zudin, Вы писали:

SVZ>Нашел контрпример, когда алгоритм не сработает.


А я пока не нашел...

SVZ>Поискал у себя в закромах.

SVZ>В общем достаточно посчитать векторное произведение векторов SD и SE.
SVZ>
SVZ>Знак произведения показывает, попадает луч в дугу или нет.
SVZ>В этом случае направление дуги не важно.

То есть как не важно? А если дуга рисуется от S к E против часовой стрелки? Тогда произведение останется прежним, но точка D попадает на дугу!
Re[5]: Попадание луча между двумя другими лучами
От: Кодт Россия  
Дата: 19.12.13 11:08
Оценка: +1
Здравствуйте, 777777w, Вы писали:

7>


Одна картинка стоит тысячи слов.

Задача выглядит так: попадает ли угловая координата НаправлениеЛуча2 в интервал [НачалоЛуча1, НачалоЛуча1 + ПоворотЛуча1].

Поскольку у нас есть зацикливание, то
— либо придётся распознать, что интервал вышел за область значений [-180,+180] — и тогда рассмотреть уже два интервала [-180,конец] и [начало,+180]
— либо размножить проверяемую точку — и проверить вхождение луч2, луч2-360, луч2+360 в интервал [начало,конец]
— либо размножить интервал — и проверить вхождение луч2 в [начало,конец], [начало-360,конец-360], [начало+360,конец+360]
Понятно, что проверять надо не три, а только два варианта — в зависимости от того, куда сместился оригинальный интервал.

Ну а если коротко, то
bool belongs(int a, int b, int c) // a <- [b,b+c]
{
  assert(a >= -180 && a <= 180);
  assert(b >= -180 && b <= 180);
  assert(c >= -360 && c <= 360);

  // быстрые проверки
  if(c == 0) return a==b;
  if(c == -360 || c == 360) return true;

  int x, y; // [b,b+c] = [x,y]
  if(c < 0) { x=b+c; y=b; } else { x=b; y=b+c; } // упорядочиваем границы интервала

  if(a < x) a += 360; // даём шанс - перемещаем точку вправо на полный цикл
  return a>=x && a<=y;
}
Перекуём баги на фичи!
Re: Попадание луча между двумя другими лучами
От: watchmaker  
Дата: 19.12.13 14:06
Оценка: 9 (2)
Здравствуйте, 777777w, Вы писали:

7>Дан угол, под которым луч выходит из начала координат (от -180 до 180) и угол на который он поворачивается (от -360 до 360).

7>Есть ли какой-то простой алгоритм? Или нужно писать кучу if-ов учитывая пересечение первым лучом нуля, 180 или -180 градусов?

Если тебе важно не писать много условий, то можно обойтись одним:
угол t находится внутри сектора [s; s + a] только если cos(s – t + a/2) ≥ cos(a/2).
Очевидно, все случаи с периодичностью тут уже учтены внутри косинуса. Разумеется двукратное вычисление косинуса и является главным недостатком такого решения.
Re: Попадание луча между двумя другими лучами
От: AleksandrN Россия  
Дата: 19.12.13 14:14
Оценка:
Здравствуйте, 777777w, Вы писали:

7>Дан угол, под которым луч выходит из начала координат (от -180 до 180) и угол на который он поворачивается (от -360 до 360). Требуется определить, пересечет ли он третий луч, угол которого также задан.


7>Есть ли какой-то простой алгоритм? Или нужно писать кучу if-ов учитывая пересечение первым лучом нуля, 180 или -180 градусов?


Вычислить угол между 1-м и 3-м лучём в направлении вращения 1-го луча.
Сравнить вычисленный угол с углом поворота.
Re[3]: Попадание луча между двумя другими лучами
От: Pzz Россия https://github.com/alexpevzner
Дата: 19.12.13 14:35
Оценка:
Здравствуйте, 777777w, Вы писали:

7>Чтобы было понятно — конкретный пример. Первый луч +10 градусов, поворачивается на -340 градусов. Пересечет ли он луч -20 градусов? +170? +20? Напиши выражение возвращающее bool.


Что значит пересечет? Если все лучи исходят из начала координат, казалось бы, все они в начале координат и пересекаются между собой. Поэтому выражение будет состоять из одного слова, true
Re[5]: Попадание луча между двумя другими лучами
От: Pzz Россия https://github.com/alexpevzner
Дата: 19.12.13 14:36
Оценка:
Здравствуйте, 777777w, Вы писали:

7>В том-то и проблема, что это углы, а не расстояния. С углами всегда проблемы.


Приведите их все к диапазону 0...360, если в градусах.
Re[2]: Попадание луча между двумя другими лучами
От: watchmaker  
Дата: 19.12.13 15:09
Оценка:
W>угол t находится внутри сектора [s; s + a] только если cos(s – t + a/2) ≥ cos(a/2).
W>Разумеется двукратное вычисление косинуса и является главным недостатком такого решения.
Впрочем, от косинуса требуется лишь сравнение на больше–меньше, а не точное значение. Так что можно его заменить на похожую функцию, скажем на модуль и остаток от деления:
|180° – (|s – t + a/2| mod 360°)| ≥ 180° – |a/2|
Не то чтобы запись получилась короче, но зато никакой тригонометрии.
Re[3]: Попадание луча между двумя другими лучами
От: sz36 Россия  
Дата: 19.12.13 22:30
Оценка:
Здравствуйте, 777777w, Вы писали:

7> Напиши выражение возвращающее bool.


Пожалуйста

  bool res=(rotateAngle > 0) ? (testAngle>startAngle && testAngle<(startAngle+rotateAngle)) 
                             : (testAngle<startAngle && testAngle>(startAngle+rotateAngle));
Re[4]: Попадание луча между двумя другими лучами
От: 777777w Россия  
Дата: 20.12.13 04:01
Оценка:
Здравствуйте, sz36, Вы писали:

S>
S>  bool res=(rotateAngle > 0) ? (testAngle>startAngle && testAngle<(startAngle+rotateAngle)) 
S>                             : (testAngle<startAngle && testAngle>(startAngle+rotateAngle));
S>


Если бы все было так просто, я бы не задавал таких вопросов. Простейший тестовый пример:

startAngle = 170
rotateAngle = 20
testAngle = -179

не выдерживает проверки этой формулой
Re[2]: Попадание луча между двумя другими лучами
От: 777777w Россия  
Дата: 20.12.13 04:04
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Здравствуйте, 777777w, Вы писали:


7>>Дан угол, под которым луч выходит из начала координат (от -180 до 180) и угол на который он поворачивается (от -360 до 360).

7>>Есть ли какой-то простой алгоритм? Или нужно писать кучу if-ов учитывая пересечение первым лучом нуля, 180 или -180 градусов?

W>Если тебе важно не писать много условий, то можно обойтись одним:

W>угол t находится внутри сектора [s; s + a] только если cos(s – t + a/2) ≥ cos(a/2).
W>Очевидно, все случаи с периодичностью тут уже учтены внутри косинуса.

Мне это совершенно не очевидно. Нельзя ли привести математическое доказательство?

W>Разумеется двукратное вычисление косинуса и является главным недостатком такого решения.


На дворе 21 век, поэтому вычисление косинуса не является препятствием. Гораздо более серьезным недостатком является то, что ни один придуманный мной тестовый пример не подтверждает работоспособность этого алгоритма.
Re: Попадание луча между двумя другими лучами
От: Буравчик Россия  
Дата: 20.12.13 06:44
Оценка:
Здравствуйте, 777777w, Вы писали:

7>Дан угол, под которым луч выходит из начала координат (от -180 до 180) и угол на который он поворачивается (от -360 до 360). Требуется определить, пересечет ли он третий луч, угол которого также задан.


7>Есть ли какой-то простой алгоритм? Или нужно писать кучу if-ов учитывая пересечение первым лучом нуля, 180 или -180 градусов?


Протестированное решение

a — угол первого луча
delta — угол поворота первого луча
b — угол луча, для которого требуется определить пересечет ли его первый луч при повороте

Алгоритм работает для любых a, delta, b (не только в диапазоне из задачи)

Решение: Изменяем систему координат таким образом, чтобы первый луч был равен нулю, а второй луч задан положительным углом (т.е. по часовой стрелке). Далее нам останется рассмотреть два варианта — либо угол поворота также положительный (по часовой стрелке), либо отрицательный (против часовой)

def cover(a, delta, b):
  # Шаг первый - поворачиваем систему координат на угол a
  b -= a
  a -= a
  
  # Шаг второй - если необходимо переворачиваем (отражаем) систему координат
  if b < 0:
    b = -b
    delta = -delta

  # Привели систему к виду:
  assert a == 0  
  assert b >= 0
 
  # Корректируем b, если он очень большой
  b = b % 360

  # Сравниваем нашу delta c углом b (b > 0)
  if delta >= 0:  # delta и b идут в одном направлении (по часовой)
    return delta >= b
  else:           # delta < 0, т.е. против часовой
    return -delta >= 360 - b
Best regards, Буравчик
Re[2]: Попадание луча между двумя другими лучами
От: Буравчик Россия  
Дата: 20.12.13 08:26
Оценка:
Здравствуйте, Буравчик, Вы писали:
Б>
Б>  # Сравниваем нашу delta c углом b (b > 0)
Б>  if delta >= 0:  # delta и b идут в одном направлении (по часовой)
Б>    return delta >= b
Б>  else:           # delta < 0, т.е. против часовой
Б>    return -delta >= 360 - b
Б>


Перепутал здесь "по часовой" и "против часовой", но это только в комментариях. На код не влияет
Best regards, Буравчик
Re[3]: Попадание луча между двумя другими лучами
От: watchmaker  
Дата: 20.12.13 10:10
Оценка:
Здравствуйте, 777777w, Вы писали:

W>>угол t находится внутри сектора [s; s + a] только если cos(s – t + a/2) ≥ cos(a/2).

W>>Очевидно, все случаи с периодичностью тут уже учтены внутри косинуса.
7>Мне это совершенно не очевидно.
Косинус — функция периодическая.
7>Нельзя ли привести математическое доказательство?
Идея такая:
Проверим, что угол 0 лежит внутри сектора, заметаемый вектором с началом в угле s при повороте на угол a. Возьмём биссектрису этого сектора, у неё будет угол (s+a/2). Любое направление, что находится внутри сектора, имеет угол между ним и биссектрисой меньше |a/2|. Всё что находится вне сектора имеет угол с биссектрисой больше |a/2|.
Берёшь пару единичных векторов U(cos(s+a/2), sin(s+a/2)) и V(1, 0) — один из них соответствует биссектрисе, второй — цели проверки. Скалярное произведение U·V = |U|·|V|·cos(i) = cos(i), где i — это искомый угол. Если он больше |a/2|, то вхождения нет, если меньше — есть. Но в если записать скалярное произведение покоординатно, то U·V = cos(s+a/2). Таким образом нужно просто решить, что же больше: cos(s+a/2) или cos(a/2).
Случай с произвольной целью t сводится просто к повороту всей конструкции на угол (-t). В этом случае a, разумеется, не меняется, а начало сектора переходит в (s – t). То есть сравнивать на больше–меньше придётся cos(s – t + a/2) и cos(a/2).

W>>Разумеется двукратное вычисление косинуса и является главным недостатком такого решения.


7>На дворе 21 век, поэтому вычисление косинуса не является препятствием. Гораздо более серьезным недостатком является то, что ни один придуманный мной тестовый пример не подтверждает работоспособность этого алгоритма.

То есть? Ты придумал миллиард примеров и на них всех формула дала верный ответ, но тебе нужно более полное доказательство?

Или ты нашел пример, где формула даёт неверный ответ? В таком случае, возможно, ты зря говоришь о том, что «вычисление косинуса не является препятствием» — вдруг ты в своём калькуляторе радианы с градусами перепутал при вычислениях, например.
Re[4]: Попадание луча между двумя другими лучами
От: 777777w Россия  
Дата: 20.12.13 14:36
Оценка:
Здравствуйте, watchmaker, Вы писали:

7>>Нельзя ли привести математическое доказательство?

W>Идея такая:
W>Проверим, что угол 0 лежит внутри сектора, заметаемый вектором с началом в угле s при повороте на угол a. Возьмём биссектрису этого сектора, у неё будет угол (s+a/2). Любое направление, что находится внутри сектора, имеет угол между ним и биссектрисой меньше |a/2|. Всё что находится вне сектора имеет угол с биссектрисой больше |a/2|.

Кажется дошло... Действительно должно работать, сейчас попробую.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.