Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Нахождение внутренних углов в многоугольнике (http://forum.oszone.net/showthread.php?t=108177)

mrcnn 31-05-2008 17:08 815239

Нахождение внутренних углов в многоугольнике
 
В декартовой системе координат, образованной окном Windows

Дано: точка 1 (x1, y1) точка 2 (x2, y2) точка 3 (x3, y3) ... точка n (xn, yn)

x1=xn
y1=yn

Замкнутый многоугольник

Найти: все углы многоугольника
Первый угол образован прямыми (x1, y1) - (x2, y2) и (x2, y2) - (x3, y3) .......

N угол образован прямыми (x(n-1), y(n-1)) - (xn, yn) и (xn, yn) - (x1, y1)


Решение:

Длину вектора найти очень просто.
Длина первого вектора
len1 = Math.Sqrt(Math.Abs((x2-x1) * (x2-x1)) + Math.Abs((y2-y1) * l(y2-y1)))
Длина второго вектора
len2 = Math.Sqrt(Math.Abs((x3-x2) * (x3-x2)) + Math.Abs((y3-y2) * l(y3-y2)))



Угол получаем по формуле
(скалярное произведение первого вектора на второй вектор ) / длина первого вектора * длину второго вектора

Скалярное произведение первого вектора на второй
это (x2-x1)*(x3-x2) + (y3-y2)*(y2-y1)

Косинус угла это ( (x2-x1)*(x3-x2) + (y3-y2)*(y2-y1)) / ( len1*len2)

Acos(cos)*180 получаем угол...

Что я не учел? В чем ошибка в рассуждениях и в коде?



Координаты точек хранятся в двух массивах.
XM - координаты x
YM - координата y
tm - длина массивов
Длина массивов одинакова, счетчик совпадает


Код

If tm > 1 Then
For cn = 0 To tm
ReDim Preserve ug(sug)

q1 = cn + 1
If q1 > tm Then
q1 = Math.Abs(tm - Math.Abs(tm - q1) - 1)
End If
q2 = cn + 2
If q2 > tm Then
q2 = Math.Abs(tm - Math.Abs(tm - q2) - 1)
End If

lx = Math.Abs(XM(q1) - XM(cn))
ly = Math.Abs(YM(q1) - YM(cn))
mx = Math.Abs(XM(q2) - XM(q1))
my = Math.Abs(YM(q2) - YM(q1))
z1 = Math.Sqrt(Math.Abs(lx * lx) + Math.Abs(ly * ly))
z2 = Math.Sqrt(Math.Abs(mx * mx) + Math.Abs(my * my))
ug(sug) = (Math.Acos((lx * mx + ly * my) / (z1 * z2))) * 180

MsgBox(CStr(ug(sug)))
sug = sug + 1
Next


для прямоугольного треугольника выдача: 115, 164, 280
280 вполне логичное значение т.к 360-280=90
115 и 164 как получены не понимаю значит где-то ошибка
Где я ошибся?

Altair86 31-05-2008 18:37 815300

Цитата:

Цитата mrcnn
ug(sug) = (Math.Acos((lx * mx + ly * my) / (z1 * z2))) * 180 »

Попробуй поделить на пи.
ug(sug) = (Math.Acos((lx * mx + ly * my) / (z1 * z2))) * 180/3,1415926
В код не очень врубился, торможу( Если других ошибок нет, программка должна вроде на невыпуклых многоугольниках подглючивать.

Coutty 31-05-2008 18:50 815306

Цитата:

Цитата mrcnn
280 вполне логичное значение т.к 360-280=90 »

Извините, конечно, но проверьте на калькуляторе :lol:

Цитата:

Цитата mrcnn
len1 = Math.Sqrt(Math.Abs((x2-x1) * (x2-x1)) + Math.Abs((y2-y1) * l(y2-y1))) »

Зачем брать абсолютное значение, если при возведении в квадрат всё равно положительное число получается? Непонятно также, что это за палочка перед второй скобкой с игреками. Наверное, опечатка?

А что, если для вычисления угла воспользоваться теоремой косинусов? Просто я не понял про скалярное произведение векторов, да и вообще...
cos (между b и c) = (b^2 + c^2 - a^2) / 2bc.
Правда тут ещё придётся длину a вычислять (по концам векторов b и с, разумеется).

mrcnn 31-05-2008 19:04 815317

Графически задача выглядит так:





Отредактировано:

Хм.. Деление на пи рулезно сработало. Объясните, почему пришлось еще делить на пи?

Admiral 31-05-2008 19:47 815346

mrcnn, а ведь если б по ссылке сходил из соседней темы
Цитата:

Цитата Admiral
mrcnn, MSDN нету?
...
Math.Acos Method »

то там бы нашёл бы рулёзную формулу
Цитата:

Цитата Math.Acos Method (System)
Remarks

Multiply the return value by 180/Math.PI to convert from radians to degrees. >>

Потому что Pi это 180 градусов, а 3.14... это в радиальной мере.
И выходит пропорция
Код:

Pi это 180 градусов  3.14... радиан
        Х градусов          Х радиан
Х градусов=180 градусов*Х Радиан/3.14... радиан (то есть Pi)


mrcnn 31-05-2008 20:05 815356

Цитата:

Multiply the return value by 180/Math.PI to convert from radians to degrees
По ссылке из соседней темы я сходил, увидел только то, что надо умножить на 180 как раз в той самой ремарке, которые вы откопировали
но я не увидел еще, что надо разделить на Math.PI

Сходил еще раз. Не увидел, потому что Math.PI было выделено ссылкой. Я прочитал все, что было до ссылки.

В школе, к сожалению, не научили переводить из радианов в градусы :( MSDN бы и не понадобился тогда.

Admiral 31-05-2008 20:10 815362

mrcnn, теперь на примере пропорции ясность есть?
Да ещё по коду, я бы сделал одну процедуру которая считает угол между отрезками, координаты точек которых известно, а потом бы вызвал эту процедуру n раз, на количество вершин многоугольника.

mrcnn 31-05-2008 20:23 815371

Цитата:

mrcnn, теперь на примере пропорции ясность есть?
Да. Спасибо.

Altair86 01-06-2008 14:51 815892

Еще возможен альтернативный способ:
Dim N As Integer 'число углов/сторон
Dim XM() As Single 'координаты Х вершин
Dim YM() As Single 'координаты Y вершин
Dim fi() As Single ' угол такой) объяснение ниже
Dim sinus As Single 'синус этого угла
Dim cosinus As Single ' косинус его же
Dim len As Single 'длины сторон многоугольника
Dim angle() As Single ' то, что нам надо-- углы многоугольника
Dim i As Byte 'переменная цикла, юзаем везде где надо
Private Sub <название>
'<...> здесь у нас ввод N
'после чего задаем длины массивов
ReDim XM(0 to N+1)
ReDim YM(0 to N+1)
ReDim fi(0 to N)
ReDim Angle(1 to N)
'<...> здесь у нас ввод кооординат вершин от 1-й до N-й
' внимание! вершины нумеруем по часовой стрелке
XM(0)=XM(N)
XM(N+1)=XM(1)
YM(0)=YM(N)
YM(N+1)=YM(1)
'0-я и (N+1)-я вершины будут нужны

'Далее вычисляется угол между i-й стороной и положительным
'направлением оси Ох. Угол отсчитывается против часовой стрелки
' это то самое fi
For i= 0 To N
'вычисляем длину i-й стороны
'i-я сторона идет от i-й вершины к (i+1)-й
'вот нам и понадобились 0-я и N+1-я вершины
len=Sqr (((XM(i)-XM(i+1))^2+(YM(i)-YM(i+1))^2)
'находим синус и косинус вычисляемого угла
sinus= (YM(i+1)-YM(i))/len
cosinus= (XM(i+1)-XM(i))/len
' Дальше считаем сам угол
If sinus>=0 Then
fi(i) =acos(cosinus)
Else
fi(i)=2*Pi-acos(cosinus)
EndIf
Next i

For i =1 to N
angle(i)= Pi+ (fi(i)-fi(i-1))
'здесь понадобилась 0-я сторона
If angle(i)<0 Then angle(i)= angle(i)+2*Pi
angle(i)=angle(i)*180/Pi
Next i
'<...> здесь можем вывести значения углов
'массив углов можно не создавать,тогда
'вывод внутри последнего цикла делаем
End Sub


Время: 09:20.

Время: 09:20.
© OSzone.net 2001-