Надеюсь, я правильно понимаю ваш вопрос, как стремление к острому углу, а не тупому углу пересечения двух линий. Я прав?
Острый и тупой углы пересечения дополняют друг друга на 180 градусов. т.е.
acute + obtuse = PI.
http://www.mathworks.com/access/helpdesk/help/techdoc/ref/atan.html
показывает, что атан асимптотичен при +/- пи / 2.
Следовательно, максимальная разница между двумя результатами atan равна pi или 180 градусов, независимо от того, используете ли вы запись +/-
или положительную запись 0 to pi
градиента.
Рассмотрим следующий псевдокод:
acuteAngle(m1, m2){
a = atan(m1) - atan(m2);
// if obtuse get the complementary acute angle:
if (a>PI/2)
a = PI - a;
return a;
}
Функция acuteAngle
математически иллюстрирует, что вам нужно сделать.
Однако его нельзя использовать для значений углов в окрестности PI / 2, поскольку бинарное сравнение углов с результатами в этой окрестности вызывает сомнение, представлен ли тупой или острый угол.
Следовательно, нам нужно сравнить координаты точек двух прямых.
Мы выясняем, является ли 3-я линия, образованная из [(x2,y2)(x3,y3)]
, короче, равна или длиннее гипотетической гипотенузы.
В силу теоремы Пифагора,
Гипотенуза формируется, если угол точно равен PI / 2 или 90 град. Назовем его гипотетическую линию гипотенузы L3Hypo.
По геометрической визуализации в вашем уме
- Если 3-я строка длиннее
L3Hypo, угол тупой.
- Если короче, то угол острый.
- В противном случае идеально 90.
Таким образом,
L1.lengthSquared = sq(x2-x1) + sq(y2-y1)
L2.lengthSquared = sq(x3-x1) + sq(y3-y1)
L3Hypo.lengthSquared = L1.lengthSquared + L2.lengthSquared
L3.lengthSquared = sq(x3-x2) + sq(y3-y2)
Следовательно, следующий псевдокод,
struct Point{
double x, y;
}
// no need to struct, for clarity only
struct Line{
double lengthSquared;
}
#define sq(n) (n*n)
int isObtuse(Point P1, P2, P3){
Line L1, L2, L3, L3Hypo;
L1.lengthSquared = sq(P2.x-P1.x) + sq(P2.y-P1.y);
L2.lengthSquared = sq(P3.x-P1.x) + sq(P3.y-P1.y);
L3Hypo.lengthSquared = L1.lengthSquared + L2.lengthSquared;
L3.lengthSquared = sq(P3.x-P2.x) + sq(P3.y-P2.y);
if (L3>L3Hypo) return 1; //obtuse
else if (L3<L3Hypo) return -1; //acute
else return 0;
}
Если у вас уже есть функция
getGradient (точка P, Q):
double m1m2 = getGradient(P1,P2);
double m1m3 = getGradient(P1,P3);
double a = Abs(atan(m1m2) - atan(m1m3));
if (isObtuse(P1, P2, P3)>0)
a = PI - a;
Возможно, я допустил некоторые опечатки в псевдокоде (надеюсь, что нет), но я продемонстрировал суть концепции. Если так, кто-то может быть так любезен, чтобы отредактировать опечатки.
Далее
Однако, обдумав это, я обнаружил, что борьба за точность сводится к самому слабому звену благодаря директиве
#define PI 3.14159blah..blah..blah.
Итак, мы могли бы также спасти все проблемы и просто сделать это:
double m1m2 = getGradient(P1,P2);
double m1m3 = getGradient(P1,P3);
double a = Abs(atan(m1m2) - atan(m1m3));
double b = PI - a;
return min(a, b);//the smaller of the two is the acute