2017-01-07 2 views
0

У меня есть две точки A (X, Y) и B (P, Q) в первом квадранте. Есть еще одна точка C (L, M). Как найти угол между CA и CB по часовой стрелке?Найти угол по часовой стрелке между двумя точками относительно произвольного начала

Я искал много, и все решение, используемое atan2(), но находит угол от начала координат относительно оси x.

C and A can be assumed fixed. And B is can be anywhere in the first quadrant

С и А можно считать фиксированной. И B может быть где угодно в первом квадранте. Угол должен быть по часовой стрелке и в пределах диапазона 0-360 (от 0 до 360-1).

Я делаю это в C/C++.

Редактировать: добавление кода для запроса. Это немного отличается, потому что я застрял в концепции и нуждался в разъяснении относительно этого. Эта функция должна возвращаться, если точка x, y лежит между 50, 50 и P. P - угол относительно CA.

bool isInsideAngle(long double x,long double y, long double p) 
{ 
    if((atan2(y,x) >= atan2(50,100)) && (atan2(y,x) <= (p * PI/50))) 
    { 
     // cout<<"YES!"; 
     // cout<<" atan2(y,x) = " <<atan2(y,x)*180/PI<<endl; 
     // cout<<" atan2(50,50) = " <<atan2(50,100)*180/PI<<endl; 
     // cout<<" (p * PI/50) = "<<(p * PI/50)*180/PI<<endl; 
     return true; 
    } 

    else 
     return false; 

} 
+1

"Я делаю это в C/C++." -> Опубликуйте код, который вы сделали до сих пор. Пока это выглядит как математическая проблема, а не кодировка. Какие типы используются, какие угловые единицы? – chux

+0

@chux Все работы, которые я делал, были задействованы atan2(), которые использовали источник для вычисления угла, а угловые единицы могут быть любыми - радиан или градусы. –

+0

Преобразуйте CA в вектор и возьмите atan2(). Сделайте то же самое с CB. Вычитание. –

ответ

2

Как найти угол между СА и СВ в направлении по часовой стрелке?

// The atan2 functions return arctan y/x in the interval [−π , +π] radians 
double Dir_C_to_A = atan2(Ay - Cy, Ax - Cx); 
double Dir_C_to_B = atan2(By - Cy, Bx - Cx); 
double Angle_ACB = Dir_C_to_A - Dir_C_to_B; 

// Handle wrap around 
const double Pi = acos(-1); // or use some π constant 
if (Angle_ACB > Pi) Angle_ACB -= 2*Pi; 
else if (Angle_ACB < -Pi) Angle_ACB += 2*Pi; 

// Answer is in the range of [-pi...pi] 
return Angle_ACB; 
+1

Спасибо! Это именно то, что мне нужно. Теперь мне просто нужно преобразовать углы в углы в диапазоне [0,360]. (Приведенный выше код также дает отрицательные углы). –

+0

@SaurabhShrivastava Лучше масштабировать на 180/пи, затем добавить 360 для отрицательных значений, чем добавлять и масштабировать. Первый метод численно более стабилен. – chux

+0

Точно то, что я собираюсь делать. –

0

Как chux уже ответил на ваш вопрос, и вы приняли его ответ, вот альтернативный способ тоже смотреть на нее как с точки зрения программирования математики &. Это может быть применено к любым трем отличительным относительным точкам.


Math - Это будет сделано в 2D пространстве, но может быть применен к любой размерности пространства.

  • Очки будут пожертвованы строчным регистром, где векторы будут заглавными.
  • Dot Product будет обозначен *
  • Длина вектора такая же, как и его величина.
  • Очки будут показаны с их компонентами оси (х, у)
  • векторов будут показаны с их компонентами вектора (I, J)
  • Тета будет угол между двумя векторами & Фи будет внешним углом

Абстракции - Правила & уравнения векторов
Мы имеем THRE е точки a(x,y), b(x,y) & c(x,y)
Из них мы можем построить два вектора A<i,j> & B<i,j>

A = ca и B = cb
A = <ax - cx, ay - cy>
B = <bx - cx, by - cy>

Теперь, когда мы определили два вектора A & B Lets найти Theta. Чтобы найти cos(angle) между ними, мы должны знать как величины A & B и Dot Product между ними.

Magnitude или Length вектора является sqrt((i^2) + (j^2))
Dot Product является A*B = (Ai x Bi) + (Aj x Bj)
Cos(Angle) = (A*B)/(magA * magB)
Theta = acos(Cos(Angle))
Phi = 360 - Theta


Доказательство - пример с точки будучи a(5,7), b(3,5) & c(5,3)

A = < 5-5, 7-3 > = < 0, 4 >
B = < 3-5, 5-3 > = < -2, 2 >

magA = sqrt(0^2 + 4^2) = 4
magB = sqrt((-2)^2 + 2^2) = 2sqrt(2)

cosAngle = A*B/(magA * magB)
cosAngle = (0*-2 + 4*2) = 8/(4 x 2sqrt(2)) = 0.7071067812

Theta = acos(cosAngle) = 45 degrees
Phi = 360 - 45 = 315

Phi является clockwise angle, что вы просили в первой диаграмме на левой
где Theta угол между любыми двумя векторами.


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

Примечание - Это только обнаружит угол между двумя векторами и вычитает Theta от 360, чтобы найти Phi даст вам внешний угол вокруг этих двух векторов. Это не включает и не подразумевает какого-либо направления вращения самих углов. Это не различает по часовой стрелке или против часовой стрелки. Пользователь должен был бы рассчитать это для себя. Это просто использует основные свойства и операции над 3 точками или 2 векторами, чтобы найти угол между ними, который является всего лишь одним шагом полной проблемы. Если вы ссылаетесь на доказательство выше, где внутренний угол составляет 45 градусов, а внешний угол равен 315; если вы измените точку b на (7,5) вместо того, где точка b отразится над вектором A, тогда выход будет точно такими же: 45 градусов для угла между двумя векторами и 315 для внешнего угла. Это не знает, в каком направлении вы вращаетесь; если только вы не считали использование и нести знак функции косинуса, если это - или +, то это может иметь значение, но помните, что из Trig cosine есть + и - в разных квадрантах.


Программирование - C++

main.cpp

#include <iostream> 
#include "Vector2.h" 

int main() { 
    // We can assume that points and vectors are similar except that points 
    // Don't have a direction where vectors do. 
    Vector2 pointA(5, 7); 
    Vector2 pointB(3, 5); 
    Vector2 pointC(5, 3); 

    Vector2 vec1 = pointA - pointC; 
    Vector2 vec2 = pointB - pointC; 

    // This is the actual angle 
    float ThetaA = vec1.getAngle(vec2, false, false);  

    // Other Option 
    float ThetaB = vec1.getCosAngle(vec2, false); 
    ThetaB = acos(ThetaB); 
    ThetaB = Math::radian2Degree(ThetaB); 

    // Same as other option above which this is already being done in getAngle() 
    float ThetaC = Math::radian2Degree(acos(vec1.getCosAngle(vec2, false))); 

    std::cout << "ThetaA = " << ThetaA << std::endl; 
    std::cout << "ThetaB = " << ThetaB << std::endl; 
    std::cout << "ThetaC = " << ThetaC << std::endl; 

    float Phi = 360.0f - ThetaA; 
    std::cout << "Phi = " << Phi << std::endl; 

    return 0; 
} 

Выход

ThetaA = 45 
ThetaB = 45 
ThetaC = 45 
Phi = 315 

Короткая версия главного

#include <iostream> 
#include "Vector2.h" 

int main() { 
    Vector2 pointA(5, 7); 
    Vector2 pointB(3, 5); 
    Vector2 pointC(5, 3); 

    Vector2 vec1 = pointA - pointC; 
    Vector2 vec2 = pointB - pointC; 

    float angle = vec1.getAngle(vec2, false, false); 
    float clockwiseAngle = 360 - angle; 

    std::cout << "Theta " << angle << std::endl; 
    std::cout << "Phi " << clockwiwseAngle << std::endl; 

    return 0; 
} 

Выход

Theta = 45 
Phi = 315 

Это, как вы можете найти угол по часовой стрелке от 3-х точек в е диаграммы слева слева. Что касается диаграммы справа, просто найдите угол, не вычитая его из 360. Используемые классы ниже.


Vector2.h

#ifndef VECTOR2_H 
#define VECTOR2_H 

#include "GeneralMath.h" 

class Vector2 { 

public: 
    union { 
     float m_f2[2]; 
     struct { 
      float m_fX; 
      float m_fY; 
     }; 
    }; 

    // Constructors 
    inline Vector2(); 
    inline Vector2(float x, float y); 
    inline Vector2(float *pfv); 

    // Destructor 
    ~Vector2(){} 

    // Operators 
    inline Vector2 operator+(const Vector2 &v2) const; 
    inline Vector2 operator+() const; 
    inline Vector2& operator+=(const Vector2 &v2); 
    inline Vector2 operator-(const Vector2 &v2) const; 
    inline Vector2 operator-() const; 
    inline Vector2& operator-=(const Vector2 &v2); 
    inline Vector2 operator*(const float &fValue) const; 
    inline Vector2& operator*=(const float &fValue); 
    inline Vector2 operator/(const float &fValue) const; 
    inline Vector2& operator/=(const float &fValue); 

    // Functions 
    inline void  normalize(); 
    inline void  zero(); 
    inline bool  isZero() const; 
    inline float dot(const Vector2 v2) const; 
    inline float length2() const; 
    inline float length() const; 
    inline float getCosAngle(const Vector2 &v2, const bool bNormalized = false); 
    inline float getAngle(const Vector2 &v2, const bool bNormalized = false, bool bRadians = true); 

    // Pre Multiple Vector By A Scalar 
    inline friend Vector2 Vector2::operator*(const float &fValue, const Vector2 v2) {   
     return Vector2(fValue*v2.m_fX, fValue*v2.m_fY);  
    } // operator* 

    // Pre Divide Vector By A Scalar 
    inline friend Vector2 Vector2::operator/(const float &fValue, const Vector2 v2) { 
     Vector2 vec2; 
     if (Math::isZero(v2.m_fX)) { 
      vec2.m_fX = 0.0f; 
     } else { 
      vec2.m_fX = fValue/v2.m_fX; 
     } 

     if (Math::isZero(v2.m_fY)) { 
      vec2.m_fY = 0.0f; 
     } else { 
      vec2.m_fY = fValue/v2.m_fY; 
     } 

     return vec2;  
    } // operator/ 

}; // Vector2 

inline Vector2::Vector2() : m_fX(0.0f), m_fY(0.0f) { 
} // Vector2 

inline Vector2::Vector2(float x, float y) : m_fX(x), m_fY(y) { 
} // Vector2 

inline Vector2::Vector2(float *pfv) { 
    m_fX = pfv[0]; 
    m_fY = pfv[1]; 
} // Vector2 

// Unary + Operator 
inline Vector2 Vector2::operator+() const { 
    return *this; 
} // operator+ 

// Binary + Take This Vector And Add Another Vector To It 
inline Vector2 Vector2::operator+(const Vector2 &v2) const { 
    return Vector2(m_fX + v2.m_fX, m_fY + v2.m_fY); 
} // operator+ 

// Add Two Vectors Together 
inline Vector2 &Vector2::operator+=(const Vector2 &v2) { 
    m_fX += v2.m_fX; 
    m_fY += v2.m_fY; 
    return *this; 
} // operator+= 

// Unary - Operator: Negate Each Value 
inline Vector2 Vector2::operator-() const { 
    return Vector2(-m_fX, -m_fY); 
} // operator- 

// Unary - Take This Vector And Subtract Another Vector From It 
inline Vector2 Vector2::operator-(const Vector2 &v2) const { 
    return Vector2(m_fX - v2.m_fX, m_fY - v2.m_fY); 
} // operator- 

// Subtract Two Vectors From Each Other 
inline Vector2 &Vector2::operator-=(const Vector2 &v2) { 
    m_fX -= v2.m_fX; 
    m_fY -= v2.m_fY; 
    return *this; 
} // operator-= 

// Post Multiply Vector By A Scalar 
inline Vector2 Vector2::operator*(const float &fValue) const { 
    return Vector2(m_fX * fValue, m_fY * fValue); 
} // operator* 

// Multiply This Vector By A Scalar 
inline Vector2& Vector2::operator*=(const float &fValue) {  
    m_fX *= fValue; 
    m_fY *= fValue;  
    return *this;  
} // operator* 

// Post Divide Vector By A Scalar 
inline Vector2 Vector2::operator/(const float &fValue) const {  
    Vector2 vec2; 
    if (Math::isZero(fValue)) { 
     vec2.m_fX = 0.0f; 
     vec2.m_fY = 0.0f; 
    } else { 
     float fValue_Inv = 1/fValue; 
     vec2.m_fX = vec2.m_fX * fValue_Inv; 
     vec2.m_fY = vec2.m_fY * fValue_Inv; 
    }  
    return vec2; 
} // operator/ 

// Divide This Vector By A Scalar Value 
inline Vector2& Vector2::operator/=(const float &fValue) {  
    if (Math::isZero(fValue)) { 
     m_fX = 0.0f; 
     m_fY = 0.0f; 
    } else { 
     float fValue_Inv = 1/fValue; 
     m_fX *= fValue_Inv; 
     m_fY *= fValue_Inv; 
    }  
    return *this; 
} // operator/= 

// Make The Length Of This Vector Equal To One 
inline void Vector2::normalize() {  
    float fMag; 
    fMag = sqrt(m_fX * m_fX + m_fY * m_fY); 
    if (fMag <= Math::ZERO) { 
     m_fX = 0.0f; 
     m_fY = 0.0f; 
     return; 
    } 

    fMag = 1/fMag; 
    m_fX *= fMag; 
    m_fY *= fMag;  
} // normalize 

// Return True if Vector Is (0, 0) 
inline bool Vector2::isZero() const { 
    if (Math::isZero(m_fX) && Math::isZero(m_fY)) { 
     return true; 
    } else { 
     return false; 
    } 
} // isZero 

// Set Vector To (0, 0) 
inline void Vector2::zero() { 
    m_fX = 0.0f; 
    m_fY = 0.0f; 
} // zero 

// Return The Length Of This Vector 
inline float Vector2::length() const { 
    return sqrtf(m_fX * m_fX + m_fY * m_fY); 
} // length 

// Return The Length Of This Vector 
inline float Vector2::length2() const { 
    return (m_fX * m_fX + m_fY * m_fY); 
} // length2 

// Return The Dot Product Between THIS Vector And Another Vector 
inline float Vector2::dot(const Vector2 v2) const { 
    return (m_fX * v2.m_fX + m_fY * v2.m_fY); 
} // dot 

// Returns The cos(Angle) Value Between THIS Vector And Vector v2. 
// This Is Less Expensive Than Using GetAngle() 
inline float Vector2::getCosAngle(const Vector2 &v2, const bool bNormalized) {  
    // A . B = |A||B|cos(angle) 
    // -> cos-1((A.B)/(|A||B|)) 

    float fMagA = length(); 
    if (fMagA <= Math::ZERO) { 
     // This (A) Is An Invalid Vector 
     return 0; 
    } 

    float fValue = 0.0f; 

    if (bNormalized) { 
     // v2 Already Normalized 
     fValue = dot(v2)/fMagA; 
    } else { 
     // v2 Not Normalized 
     float fMagB = v2.length(); 
     if (fMagB <= Math::ZERO) { 
      // B Is An Invalid Vector 
      return 0; 
     } 
     fValue = dot(v2)/(fMagA * fMagB); 
    } 

    // Correct Value Due To Rounding Problems 
    Math::constrain(-1.0f, 1.0f, fValue); 

    return fValue; 

} // getCosAngle 

// Returns The Angle Between THIS Vector And Vector v2 In RADIANS 
inline float Vector2::getAngle(const Vector2 &v2, const bool bNormalized, bool bRadians) {  
    // A . B = |A||B|cos(angle) 
    // -> cos-1((A.B)/(|A||B|)) 

    if (bRadians) { 
     return acos(getCosAngle(v2, bNormalized)); 
    } else { 
     // Convert To Degrees 
     return Math::radian2Degree(acos(getCosAngle(v2, bNormalized))); 
    }  
} // GetAngle 

#endif // VECTOR2_H 

GeneralMath.h

#ifndef GENERALMATH_H 
#define GENERALMATH_H 

#include <math.h> 

class Math { 
public: 

    static const float PI; 
    static const float PI_HALVES; 
    static const float PI_THIRDS; 
    static const float PI_FOURTHS; 
    static const float PI_SIXTHS; 
    static const float PI_2; 
    static const float PI_INVx180; 
    static const float PI_DIV180; 
    static const float PI_INV; 
    static const float ZERO; 

    Math(); 

    inline static bool isZero(float fValue); 
    inline static float sign(float fValue); 

    inline static int randomRange(int iMin, int iMax); 
    inline static float randomRange(float fMin, float fMax); 

    inline static float degree2Radian(float fDegrees); 
    inline static float radian2Degree(float fRadians); 
    inline static float correctAngle(float fAngle, bool bDegrees, float fAngleStart = 0.0f); 
    inline static float mapValue(float fMinY, float fMaxY, float fMinX, float fMaxX, float fValueX); 

    template<class T> 
    inline static void constrain(T min, T max, T &value); 

    template<class T> 
    inline static void swap(T &value1, T &value2); 

}; // Math 

// Convert Angle In Degrees To Radians 
inline float Math::degree2Radian(float fDegrees) { 
    return fDegrees * PI_DIV180; 
} // degree2Radian 

// Convert Angle In Radians To Degrees 
inline float Math::radian2Degree(float fRadians) { 
    return fRadians * PI_INVx180; 
} // radian2Degree 

// Returns An Angle Value That Is Alway Between fAngleStart And fAngleStart + 360 
// If Radians Are Used, Then Range Is fAngleStart To fAngleStart + 2PI 
inline float Math::correctAngle(float fAngle, bool bDegrees, float fAngleStart) {  
    if (bDegrees) { 
     // Using Degrees 
     if (fAngle < fAngleStart) { 
      while (fAngle < fAngleStart) { 
       fAngle += 360.0f; 
      } 
     } else if (fAngle >= (fAngleStart + 360.0f)) { 
      while (fAngle >= (fAngleStart + 360.0f)) { 
       fAngle -= 360.0f; 
      } 
     } 
     return fAngle; 
    } else { 
     // Using Radians 
     if (fAngle < fAngleStart) { 
      while (fAngle < fAngleStart) { 
       fAngle += Math::PI_2; 
      } 
     } else if (fAngle >= (fAngleStart + Math::PI_2)) { 
      while (fAngle >= (fAngleStart + Math::PI_2)) { 
       fAngle -= Math::PI_2; 
      } 
     } 
     return fAngle; 
    }  
} // correctAngle 

// Tests If Input Value Is Close To Zero 
inline bool Math::isZero(float fValue) { 
    if ((fValue > -ZERO) && (fValue < ZERO)) { 
     return true; 
    } 
    return false; 
} // isZero 

// Returns 1 If Value Is Positive, -1 If Value Is Negative Or 0 Otherwise 
inline float Math::Sign(float fValue) {  
    if (fValue > 0) { 
     return 1.0f; 
    } else if (fValue < 0) { 
     return -1.0f; 
    } 
    return 0; 
} // sign 

// Return A Random Number Between iMin And iMax Where iMin < iMax 
inline int Math::randomRange(int iMin, int iMax) {  
    if (iMax < iMin) { 
     swap(iMax, iMin); 
    }  
    return (iMin + ((iMax - iMin +1) * rand())/(RAND_MAX+1)); 

} // randomRange 

// Return A Random Number Between fMin And fMax Where fMin < fMax 
inline float Math::randomRange(float fMin, float fMax) { 
    if (fMax < fMin) { 
     swap(fMax, fMin); 
    }  
    return (fMin + (rand()/(float)RAND_MAX)*(fMax-fMin));  
} // randomRange 

// Returns The fValueY That Corresponds To A Point On The Line Going From Min To Max 
inline float Math::mapValue(float fMinY, float fMaxY, float fMinX, float fMaxX, float fValueX) {  
    if (fValueX >= fMaxX) { 
     return fMaxY; 
    } else if (fValueX <= fMinX) { 
     return fMinY; 
    } else { 
     float fM = (fMaxY - fMinY)/(fMaxX - fMinX); 
     float fB = fMaxY - fM * fMaxX; 

     return (fM*fValueX + fB); 
    }  
} // mapValue 

// Constrain a Value To Be Between T min & T max 
template<class T> 
inline void Math::constrain(T min, T max, T &value) {  
    if (value < min) { 
     value = min; 
     return; 
    } 

    if (value > max) { 
     value = max; 
    }  
} // constrain 

// Swap Two Values 
template<class T> 
inline void Math::Swap(T &value1, T &value2) {  
    T temp; 

    temp = value1; 
    value1 = value2; 
    value2 = temp;  
} // swap 

#endif // GENERALMATH_H 

GeneralMath.cpp

#include "GeneralMath.h" 

const float Math::PI   = 4.0f * atan(1.0f); // tan(pi/4) = 1 or acos(-1) 
const float Math::PI_HALVES  = 0.50f * Math::PI; 
const float Math::PI_THIRDS  = Math::PI * 0.3333333333333f; 
const float Math::PI_FOURTHS = 0.25f * Math::PI; 
const float Math::PI_SIXTHS  = Math::PI * 0.6666666666667f; 
const float Math::PI_2   = 2.00f * Math::PI; 
const float Math::PI_DIV180  = Math::PI/180.0f; 
const float Math::PI_INVx180 = 180.0f/Math::PI; 
const float Math::PI_INV  = 1.0f/Math::PI; 
const float Math::ZERO   = (float)1e-7; 

Math::Math() { 
} // Math 
+0

Вместо 'sqrtf (m_fX * m_fX + m_fY * m_fY);', ваш компилятор разрешает 'hypotf (m_fX, m_fY);'? «Функции' hypot' вычисляют квадратный корень из суммы квадратов x и y без излишнего потока над потоком или под потоком » – chux

+0

Получаете ли вы тот же результат с' Vector2' как 'pointB (3, 5)' или 'pointB (7, 1) '(180 градусов на другой стороне' C')? – chux

+0

@chux для вашего первого вопроса Я не уверен насчет 'hypotf (...)' и для вашего второго вопроса это базовый класс Vector2, который я использую в своих старых игровых машинах, прежде чем я начал использовать библиотеку GLM. Он имеет все необходимые функции, которые могут быть применены к векторам. Метод getAngle() 'всегда будет возвращать угол между двумя векторами. Последний параметр «true/false» предназначен для возврата либо радианов, либо градусов. Он не имеет никакого отношения к тому, какой угол поворачивается или ориентируется. Но, зная, где одно очко от другого, вы можете выяснить, нужно ли добавить или под 360. –

0

Это решение использует векторы чтобы решить вашу проблему. Она опирается на тот факт, что, учитывая два вектора у и v, косинус наименьшего угла между ними (уф/| у || v |), где уф является точечный продукт u и v. Чтобы определить, является ли смысл наименьшего угла от u до v положительным или отрицательным, то есть против часовой стрелки или по часовой стрелке, используется тройной продукт. Тройное произведение трех векторов U, об и ш является (Wu Х противов), и может быть интерпретировано как подписанный объем параллелепипеда, определяемого три векторов. Поскольку перекрестное произведение (и, следовательно, тройное произведение) определено только для векторов в R^3, используемые здесь векторы представляют собой 3-векторы с интересными точками, лежащими в плоскости XY. Третий вектор, образующий параллелепипед, лежит в положительном Z-направлении, так что положительный результат для тройного произведения показывает, что наименьший угол между u и v имеет против часовой стрелки.

Функция smallest_angle() возвращает наименьший угол между двумя векторами в радианах. Функция clockwise_angle() возвращает угол по часовой стрелке в радианах от первого вектора u ко второму вектору v. Функция angle_about_c() возвращает угол по часовой стрелке в радианах от отрезка линии CA до CB. Обратите внимание, что пункты A, B, и C взяты быть векторами.

#include <stdio.h> 
#include <math.h> 

#ifndef M_PI 
#define M_PI 3.14159265358979323846 
#endif 

struct Vector { 
    double i; 
    double j; 
    double k; 
}; 

double magnitude(struct Vector u); 
struct Vector vect_diff(struct Vector u, struct Vector v); 
double dot_product(struct Vector u, struct Vector v); 
struct Vector cross_product(struct Vector u, struct Vector v); 
double triple_product(struct Vector u, struct Vector v, struct Vector w); 
double smallest_angle(struct Vector u, struct Vector v); 
double clockwise_angle(struct Vector u, struct Vector v); 
double angle_about_c(struct Vector a, struct Vector b, struct Vector c); 

int main(void) 
{ 
    struct Vector vect_a = { .i = 1, .j = 1 }; 
    struct Vector vect_b = { .i = 0, .j = 1 }; 

    printf("Smallest angle: %f rad\n", smallest_angle(vect_a, vect_b)); 
    printf("Clockwise angle: %f rad\n", clockwise_angle(vect_a, vect_b)); 

    struct Vector point_a = { .i = 3, .j = 3 }; 
    struct Vector point_b1 = { .i = 4, .j = 2 }; 
    struct Vector point_b2 = { .i = 2, .j = 2 }; 
    struct Vector point_c = { .i = 3, .j = 1 }; 

    printf("Clockwise angle from CA to CB1: %f rad\n", 
      angle_about_c(point_a, point_b1, point_c)); 
    printf("Clockwise angle from CA to CB2: %f rad\n", 
      angle_about_c(point_a, point_b2, point_c)); 

    return 0; 
} 

double magnitude(struct Vector u) 
{ 
    return sqrt(dot_product(u, u)); 
} 

struct Vector vect_diff(struct Vector u, struct Vector v) 
{ 
    return (struct Vector) { .i = u.i - v.i, 
          .j = u.j - v.j, 
          .k = u.k - v.k }; 
} 

double dot_product(struct Vector u, struct Vector v) 
{ 
    return (u.i * v.i) + (u.j * v.j) + (u.k * v.k); 
} 

struct Vector cross_product(struct Vector u, struct Vector v) 
{ 
    return (struct Vector) { .i = (u.j * v.k) - (u.k * v.j), 
          .j = (u.k * v.i) - (u.i * v.k), 
          .k = (u.i * v.j) - (u.j * v.i) }; 
} 

double triple_product(struct Vector u, struct Vector v, struct Vector w) 
{ 
    return dot_product(u, cross_product(v, w)); 
} 

double smallest_angle(struct Vector u, struct Vector v) 
{ 
    return acos(dot_product(u, v)/(magnitude(u) * magnitude(v))); 
} 

double clockwise_angle(struct Vector u, struct Vector v) 
{ 
    double angle_s = smallest_angle(u, v); 

    if (triple_product((struct Vector) { 0, 0, 1 }, u, v) > 0) { 
     angle_s = 2 * M_PI - angle_s; 
    } 

    return angle_s; 
} 

double angle_about_c(struct Vector a, struct Vector b, struct Vector c) 
{ 
    return clockwise_angle(vect_diff(a, c), vect_diff(b, c)); 
} 

выход программы:

Smallest angle: 0.785398 rad 
Clockwise angle: 5.497787 rad 
Clockwise angle from CA to CB1: 0.785398 rad 
Clockwise angle from CA to CB2: 5.497787 rad 
+1

Возможно, у downvoter будет любезность, чтобы объяснить, что не так с моим ответом? –

+0

Выглядит хорошо. Он сообщает о возможном диапазоне полного круга. – chux

+0

@ chux-- Спасибо. Я видел ваши комментарии по поводу диапазона в соответствии с вашим ответом; подумает об этом еще немного. Похоже, наш драйв-на-downvoter ударил ваш ответ! Мой ответ довольно многословный; моя цель - не эффективность, а скорее модель определенной геометрической точки зрения. Может быть, это было возражение? –

Смежные вопросы