Могу ли я получить пояснение к этому Python коду ниже? - PullRequest
0 голосов
/ 29 марта 2020

Я новичок в Python, и я пытаюсь вычислить углы (-26,6 и 18,4) для этого рисунка ниже и так далее для остальных квадратов, используя код Python.

Angle range

Я нашел код ниже, и я пытаюсь понять очень хорошо. Как это может работать здесь? Любые уточнения, пожалуйста?

Python Код:

def computeDegree(a,b,c):
    babc = (a[0]-b[0])*(c[0]-b[0])+(a[1]-b[1])*(c[1]-b[1])

    norm_ba = math.sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2)
    norm_bc = math.sqrt((c[0]-b[0])**2 + (c[1]-b[1])**2)
    norm_babc = norm_ba * norm_bc

    radian = math.acos(babc/norm_babc)
    degree = math.degrees(radian)
    return round(degree, 1)

def funcAngle(p, s, sn):
    a = (s[0]-p[0], s[1]-p[1])
    b = (sn[0]-p[0], sn[1]-p[1])
    c = a[0] * b[1] - a[1] * b[0]

    if p != sn:
        d = computeDegree(s, p, sn)
    else:
        d = 0

    if c > 0:
        result = d
    elif c < 0:
        result = -d
    elif c == 0:
        result = 0
    return result

p = (1,4)
s = (2,2)
listSn= ((1,2),(2,3),(3,2),(2,1))

for sn in listSn:
    func(p,s,sn)

Результаты

Я ожидал получить углы на картинке, такие как -26,6, 18,4 .. .

Ответы [ 2 ]

3 голосов
/ 29 марта 2020

По сути, здесь используется определение точечных произведений для определения угла. Вы можете прочитать больше на по этой ссылке (также там, где я нашел эти изображения).

Vector Graph

Чтобы решить для угла, который вы сначала нужно преобразовать 3 входные точки в два вектора.

# Vector from b to a
# BA = (a[0] - b[0], a[1] - b[1])
BA = a - b

# Vector from b to c
# BC = (a[0] - c[0], a[1] - c[1])
BC = c - b

Dot Product Formulas

Используя два вектора, вы можете сначала найти угол между ними найти значение точечного произведения со второй формулой.

# babc = (a[0]-b[0])*(c[0]-b[0])+(a[1]-b[1])*(c[1]-b[1])
dot_product = BA[0] * BC[0] + BA[1] * BC[1]

Затем, вернувшись к первому определению, вы можете разделить длины двух входных векторов, и полученное значение должно быть косинусом угол между векторами. Это может быть трудно читать с помощью обозначения массива, но оно просто использует теорему Пифагора.

# Length/magnitude of vector BA
# norm_ba = math.sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2)
length_ba = math.sqrt(BA[0]**2 + BA[1]**2)

# Length/magnitude of vector BC
# norm_bc = math.sqrt((c[0]-b[0])**2 + (c[1]-b[1])**2)
length_bc = math.sqrt(BC[0]**2 + BC[1]**2)

# Then using acos (essentially inverse of cosine), you can get the angle
# radian = math.acos(babc/norm_babc)
angle = Math.acos(dot_product / (length_ba * length_bc))

Большинство других вещей просто для того, чтобы ловить случаи, когда программа может случайно попытаться разделить на ноль. Надеюсь, это поможет объяснить, почему это выглядит так.

Редактировать : я ответил на этот вопрос, потому что мне было скучно и я не видел вреда в объяснении математики, стоящей за этим кодом, однако в будущем старайтесь не задавать вопросы типа «как работает этот код» в будущем.

1 голос
/ 29 марта 2020

Давайте начнем с funcAngle, так как позже он вызывает computeDegree.

Первое, что он делает, определяет a как кортеж из двух элементов. Большая часть этого кода, кажется, использует два набора элементов, с двумя частями, на которые ссылаются v[0] и v[1] или аналогичные. Это почти наверняка какие-то двухмерные векторы.

Я запишу их как ? для вектора, а также vₓ и vᵧ, поскольку они, вероятно, являются двумя компонентами. [не смотрите слишком внимательно на этот второй индекс, он полностью да, а не гамма ...]

a - это разность векторов между s и p: то есть

a = (s[0]-p[0], s[1]-p[1])

- это aₓ = sₓ-pₓ и aᵧ = sᵧ-pᵧ; или просто ? = ?-? в векторе.

b = (sn[0]-p[0], sn[1]-p[1])

снова; ? = ??-?

c = a[0] * b[1] - a[1] * b[0]

с = aₓbᵧ-aᵧbₓ; c - это перекрестное произведение ? и ? (и это просто число)

if p != sn:
    d = computeDegree(s, p, sn)
else:
    d = 0

Я бы взял вышесказанное в обратном порядке: если ? и ?? одинаковы, то мы уже знаем угол между ними ноль (и, возможно, алгоритм плохо работает), поэтому не вычисляйте его. В противном случае вычислите угол (мы рассмотрим это позже).

if c > 0:
    result = d
elif c < 0:
    result = -d
elif c == 0:
    result = 0

Если c указывает в нормальном направлении (через правило левой руки - правило правой руки - не помню) это нормально: если это не так, нам нужно отрицать угол, по-видимому.

return result

Передать число, которое мы только что разработали, в другой код.

Вы, вероятно, можете вызвать этот код, добавив что-то вроде:

print (funcangle((1,0),(0,1),(2,2))

в конце и запустив его. (На самом деле эти числа не проверялись)


Так что эта функция вырабатывает a и b для получения c; все просто, чтобы свести на нет угол, если он направлен не туда. На самом деле ни одна из этих переменных не передается в computeDegree.

, поэтому computeDegree ():

def computeDegree(a,b,c):

Первое, на что следует обратить внимание, - это то, что переменные до этого были переименованы. funcAngle прошло s, p и sn, но теперь они называются a, b и c. И обратите внимание, порядок, в котором они переданы, не совпадает с тем, что они переданы funcAngle, что неприятно и сбивает с толку.

babc = (a[0]-b[0])*(c[0]-b[0])+(a[1]-b[1])*(c[1]-b[1])

bab c = (aₓ-bₓ) (cₓ -bₓ) + (aᵧ-bᵧ) (cᵧ-bᵧ)

Если ? 'и ?' - это ?-? и ?-? соответственно, это просто

a'ₓ c 'ₓ + a'ᵧ c' ᵧ, или скалярное произведение ? 'и ?'.

norm_ba = math.sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2)
norm_bc = math.sqrt((c[0]-b[0])**2 + (c[1]-b[1])**2)

norm_ba = √ [(aₓ-bₓ) ² + (aᵧ-bᵧ ) ²] (и norm_bc аналогично).

Это похоже на длину гипотенузы ? '(и ?' соответственно)

norm_babc = norm_ba * norm_bc

, которую мы затем умножаем вместе

radian = math.acos(babc/norm_babc)

Мы используем функцию arccosine (обратный косинус, cos ^ -1) с длиной этих умноженных гипотенуз в качестве гипотенузы и этого точечного произведения в качестве смежной длины ...

degree = math.degrees(radian)
return round(degree, 1)

но это в радианах, поэтому мы конвертируем в градусы и округляем его для хорошего форматирования.


Хорошо, так что теперь это в математике, а не Python, но это все еще не очень легко понять .

(sidenote: именно поэтому имена и документы описательных переменных - друг каждого!)

...