2014-10-24 3 views
0

Я работаю над алгоритмом, определяющим направление ребра BC относительно ребра AB.Алгоритм определения направления смещений Влево и вправо

Я реализовал определение ArcCos. Это почти работает. Он правильно определяет форвард и правильно определяет, когда нужен поворот. Но неправильно определяет, является ли это правильным или левым поворотом.

private Direction DetermineDirectionOfV2(Vertex v1, Vertex v2, Vertex v3) 
{ 
    if (v1 == null || v2 == null || v3 == null) 
     return Direction.Forward; 

    double p12 = v1.distance2D(v2); 
    double p13 = v1.distance2D(v3); 
    double p23 = v2.distance2D(v3); 

    double p12S = p12 * p12; 
    double p13S = p13 * p13; 
    double p23S = p23 * p23; 

    double a = p12S + p13S - p23S; 
    double b = 2 * p12 * p13; 

    if(b == 0.0) 
     return Direction.Forward; 

    double angle = Math.Acos(a/b); 

    double thresh = 0.1; 
    if(angle >= -thresh && angle <= thresh) 
    { 
     return Direction.Forward; 
    } 
    else if (angle > 0 && angle < Math.PI) 
    { 
     return Direction.Right; 
    } 
    else 
    { 
     return Direction.Left; 
    } 

} 

Я не уверен, что проблема есть, но я думаю, что это может быть, что это скажет мне угол ABC вместо угла BC относительно AB.

В ситуации с левым поворотом я получаю около 1,1 радиан для угла, который является неправильным. Он должен быть не менее> 3,14 радиан или -1,1 радианов.

Что может быть неправильным?

Эти 3: вершин,

//x,y,z (z is unused) 
      v1 = new Vertex(0.0f, 0.0f, 0.0f,""); 
      v2 = new Vertex(0.0f, -10.0f, 0.0f, ""); 
      v3 = new Vertex(5.0f, -10.0f, 0.0f, ""); 

дают угол 0,46 радиан, когда на самом деле это должно быть 4,71238898 рад, потому что с точки зрения AB, BC образует угол 270 градусов.

Благодаря

Пример

Если есть моменты, которые выглядят следующим образом:

A 


B  C 

Это должно дать 270 градусов или 4.7rad, потому что если мы ходим от А к В, мы превратим слева, чтобы добраться до C.

+0

Я не уверен, как использовать Атана в этом случае, не могли бы вы привести мне пример? – jmasterx

+0

вам нужно использовать atan2, а не atan – Seb

+0

@Seb Я не уверен, какие параметры Y и X будут в этом случае. Это были бы переменные a и b? – jmasterx

ответ

2

Во-первых, у вас есть признаки вашего числителя неправильно. Косинус Правило

c² = a² + b² - 2*a*b*cos(alpha) 

Следовательно,

cos(alpha) = (c² - a² - b²)/(2 * a * b) 

, который в своей номенклатуре означает:

angle = Math.Acos(p13S - p12S - p23S/(2 * p12 * p13)); 

К сожалению, это не решает проблему.

Косайное правило дает наименьший угол между двумя катетами. Вы работаете только по длине, поэтому теряете информацию о направлении. Функция acos возвращает углы в диапазоне от 0 до π, но вам нужен весь круг от -π до π.

Ваш вопрос не делает этого ясным, но я предполагаю, что у вас есть двумерные векторы в плоскости x, y. (Без опорной плоскости, направление, как слева и справа, не имеет смысла.)

Если это так, вы можете определить, повернуть ли вы влево или вправо путем вычисления декартово произведения АВ и ВС. Затем проверьте знак компонента Z:

private Direction dir(Vertex v1, Vertex v2, Vertex v3) 
{ 
    double ax = v2.x - v1.x; 
    double ay = v2.y - v1.y; 
    double bx = v3.x - v2.x; 
    double by = v3.y - v2.y; 

    double z = ax*by - ay*bx; 

    if (z > 0.0) return Direction.Left; 
    if (z < 0.0) return Direction.Right; 
    return Direction.Forward; 
} 

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

|a x b| = |a| * |b| * sin(angle) 

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

ax*bx + ay*by 

положительно (вперед) или отрицательный (назад).

+0

Это прекрасно работает, спасибо большое :) – jmasterx