Как я могу определить, движется ли объект CW или CCW по соединенному пути?

19

Допустим, мы имеем зубчатую форму:

shape0

И два существа движутся по его контуру.

Затем мы полностью сглаживаем форму, вытягивая углы.

Мы получаем это:

гладкий; плавный

Теперь легко увидеть, что Orange двигается CW, а зеленый CCW. Как я могу сказать, в каком направлении они движутся, не сглаживая форму?

Новое изображение

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

wolfdawn
источник
Вот мои 2 цента: i.imgur.com/zrBdw.png
Кендалл Фрей,

Ответы:

27

Нарисуйте линию до бесконечности и посчитайте, сколько раз вы пересекаете фигуру (четную или нечетную), не считая отрезок, в котором находится существо. Затем проверьте, идет ли существо влево или вправо от этой линии.

пример

В этом примере мы дважды (так ровно) пересекаем форму и идем налево. Результат немедленно из этой таблицы:

   # Crosses | even  | odd
  Direction  |       |
-------------+-------+------
    left     | CCW   |  CW
    right    |  CW   | CCW

В псевдокоде:

x, y = position of creature
vx, vy = direction of creature movement
crossings = 0
for each x1, y1, x2, y2 in shape segments:
    if (x1 < x and x <= x2) or (x2 < x and x <= x1):
        if y - y1 > (x - x1) * (y2 - y1) / (x2 - x1):
            ++crossings
if (crossings & 1) == (vx < 0):
    return CW
else
    return CCW
Сэм Хоцевар
источник
Вы включаете линейное существо, которое движется дальше?
Ali1S232
@Gajoo: нет, следовательно> вместо> = в строке 6. Я добавлю примечание об этом. Но обратите внимание, что вы можете включить строку и просто перевернуть содержимое таблицы.
Сам Хочевар
1
Я пытался найти ответ, основанный на этом методе, и ответ, который я дал. Я рад, что здесь представлены оба подхода. Этот концептуально проще и очень элегантен, но требует выполнения тестов пересечения отрезков, которые сложно сделать надежными.
Тревор Пауэлл
@TrevorPowell Правда. Поиск самого дальнего края может сбить с толку. Сначала я проверил, основываясь на самой удаленной вершине ребра, а затем нарисовал линию от центра фигуры и через центры двух ребер (два, которые разделяют вершину) и проверил, пересекает ли одна из линий другой край на пути к бесконечность после пересечения одного из этих ребер. Это сработало хорошо
wolfdawn
5

Это зависит от того, какую информацию вы имеете в своей структуре данных формы, но существо, движущееся CW вдоль контура фигуры, всегда будет иметь внутреннюю часть фигуры справа, а существо, движущееся CCW, будет иметь внутреннюю часть фигуры на его слева.

Джефф
источник
Гораздо более простое решение, а также моя первая мысль.
Amplify91
как узнать, какое направление находится внутри фигуры? Я имею в виду перемещение по краю внутри фигуры либо слева, либо справа. откуда ты знаешь, как это?
Ali1S232
Очень элегантное решение, но в целом не соответствует действительности. Вообразите пончик, сплющенный на столе, чтобы сделать двухмерную форму. Вы можете идти по краю этой фигуры, держать внутреннюю часть фигуры слева и делать круг по часовой стрелке или против часовой стрелки в зависимости от того, с чего вы начали.
Марки Томас
4
  1. Рассчитайте центральную точку вашей фигуры.
  2. Выберите самый отдаленный край вашей фигуры от центра.
    • (Выбор наиболее удаленного края гарантирует, что вы не начнете с перевернутой вогнутой части фигуры, что приведет к получению определения по часовой стрелке / против часовой стрелки назад для всей фигуры)
  3. Определите, какое направление вдоль этого края по часовой стрелке
    • (Простая реализация этого будет включать сравнение углов от центра фигуры до каждого конца выбранного ребра. Знак различия между углами скажет ваше по часовой стрелке против часовой стрелки)
  4. Переберите все ребра фигуры, начиная с ребра, выбранного на шаге 2, и составьте список ребер. Для каждого ребра сохраните две его вершины по часовой стрелке.
    • (Если ваша форма не меняется со временем, вы можете сохранить этот список краев для последующего использования, поэтому вам не нужно делать первые четыре шага каждый кадр)
    • (Возможно, у вас уже есть список ребер. Если это так, вы можете сохранить этот порядок вершин по часовой стрелке в этом же списке.)
  5. Чтобы определить, движется ли объект по часовой стрелке или против часовой стрелки:
    • Определите, по какому краю движется объект.
    • Произведите точечное произведение направления движения сущности против вектора из вершин этого края по часовой стрелке, которые вы определили в шаге 4.
    • Если результатом точечного произведения является значение больше нуля, объект движется по часовой стрелке. Меньше нуля означает против часовой стрелки.
Тревор Пауэлл
источник
Очень умный ответ
волчий рассвет
У меня есть маленький вопрос? предполагая, что вершины в его форме нумеруются, начиная с самой левой точки CWW, основываясь на вашем ответе, как я могу определить, движется ли движение от 6-> 7 или 9-> 10 (на основе нуля) по часовой стрелке?
Ali1S232
Вы начинаете с самого дальнего края и выясняете, какой путь идет по часовой стрелке на этом краю. Допустим, ребро A находится по часовой стрелке от вершины «a» до «b». Затем, если мы переместимся к ребру B (у которого есть вершины 'b' и 'c'), мы знаем, что B по часовой стрелке от 'b' до 'c'. Точно так же край C будет по часовой стрелке от 'c' до 'd'. Как только мы узнаем правильное направление по часовой стрелке от одного края (шаги 1-3), продолжая в этом направлении по часовой стрелке вокруг краев фигуры, мы можем определить правильное направление «по часовой стрелке» для каждого ребра, фактически не глядя на то, где расположены его ребра, так вогнутость в порядке.
Тревор Пауэлл
Как вы можете определить, находится ли ребро A по часовой стрелке от «a» до «b» или по часовой стрелке от «b» до «a»? Я думаю, что вы пропустили эту часть.
Ali1S232
@Gajoo Это точка в скобках на шаге 3. Вероятно, не следует заключать в скобки, так как это действительно важный шаг всего процесса.
Тревор Пауэлл
2

Вы должны знать, какой путь вокруг многоугольника определен, каким образом вершины обходят его.

Если вы этого не знаете, вы можете решить это, вычислив площадь многоугольника:

float Polygon::area() {
    float result = 0.0f;

    for(int a = 0; a < vertexCount; a ++) {
        int b = (a+1) % vertexCount;
        result += vertices[a].x * vertices[b].y;
        result -= vertices[a].y * vertices[b].x;
    }

    return result * .5f;
}

Знак результата (положительного или отрицательного) скажет вам , является ли она по часовой стрелке или против часовой стрелки. Вы должны попробовать это, чтобы увидеть, какой путь вам нужен, потому что это зависит от вашей системы координат.

Если форма по часовой стрелке:

  • Существо, идущее вперед по фигуре, идет по часовой стрелке , и
  • Существо, идущее назад по фигуре, идет против часовой стрелки .

Если форма против часовой стрелки:

  • Существо, идущее вперед по форме, идет против часовой стрелки , и
  • Существо, идущее назад по форме, идет по часовой стрелке .
Крис Бёрт-Браун
источник
0

Кажется, Тревор уже рассмотрел этот вопрос, но вот мое решение:

  1. вычислить область, которую покрывает ваша форма, то есть

    area = 0
    foreach (edge in shape)
        area += edge.begin.x * edge.end.y - edge.begin.y * edge.end.x
  2. используя площадь, вычисленную как указано выше, вы можете легко определить, является ли сама форма по часовой стрелке или нет. это по часовой стрелке, только если область ниже нуля.

  3. проверьте, движутся ли объект (ы) так же, как вершины - это порядок или в противоположном направлении.

Ali1S232
источник
Связанный: stackoverflow.com/questions/1165647/…
Тревор Пауэлл