Войти

Показать полную графическую версию : Нахождение внутренних углов в многоугольнике


mrcnn
31-05-2008, 17:08
В декартовой системе координат, образованной окном 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
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
280 вполне логичное значение т.к 360-280=90 »
Извините, конечно, но проверьте на калькуляторе :lol:

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
Графически задача выглядит так:
http://xpoint.ru/illustrations/262069.JPG

http://xpoint.ru/illustrations/262070.JPG


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

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

Admiral
31-05-2008, 19:47
mrcnn, а ведь если б по ссылке сходил из соседней темы
mrcnn, MSDN нету?
...
Math.Acos Method (http://msdn.microsoft.com/en-us/library/system.math.acos.aspx) »
то там бы нашёл бы рулёзную формулу
Remarks

Multiply the return value by 180/Math.PI to convert from radians to degrees. >> (http://msdn.microsoft.com/en-us/library/system.math.acos.aspx)
Потому что Pi это 180 градусов, а 3.14... это в радиальной мере.
И выходит пропорция
Pi это 180 градусов 3.14... радиан
Х градусов Х радиан
Х градусов=180 градусов*Х Радиан/3.14... радиан (то есть Pi)

mrcnn
31-05-2008, 20:05
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
mrcnn, теперь на примере пропорции ясность есть?
Да ещё по коду, я бы сделал одну процедуру которая считает угол между отрезками, координаты точек которых известно, а потом бы вызвал эту процедуру n раз, на количество вершин многоугольника.

mrcnn
31-05-2008, 20:23
mrcnn, теперь на примере пропорции ясность есть?

Да. Спасибо.

Altair86
01-06-2008, 14:51
Еще возможен альтернативный способ:
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




© OSzone.net 2001-2012