Как 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
"Я делаю это в C/C++." -> Опубликуйте код, который вы сделали до сих пор. Пока это выглядит как математическая проблема, а не кодировка. Какие типы используются, какие угловые единицы? – chux
@chux Все работы, которые я делал, были задействованы atan2(), которые использовали источник для вычисления угла, а угловые единицы могут быть любыми - радиан или градусы. –
Преобразуйте CA в вектор и возьмите atan2(). Сделайте то же самое с CB. Вычитание. –