Нахождение внутренней общей касательной к паре коник

Я пытался получить общие касательные к двум повернутым эллипсам. Я следовал методу, данному Эдвардом Дулиттлом в следующей теме . Два эллипса даны как уравнение, приведенное в Wiki.

В матричной форме эллипс можно изобразить так:
Нахождение внутренней общей касательной к паре коник

Первый эллипс с центром в точке (0,0) повернут на 45 градусов с длиной большой и малой полуосей 2,1. Второй эллипс с центром в точке (15,0), повернут на 120 градусов с длиной большой и малой полуосей 3,1.

Линейная комбинация сопряженных матриц двух эллипсов представляет собой двойственное сочетание двух эллипсов. Нахождение внутренней общей касательной к паре коник
Я получаю это значение
Нахождение внутренней общей касательной к паре коник.

Затем я попытался найти значение t, которое сделает коническую (над матрицей) вырожденной.

Я обнаружил, что значение t равно (-0,05, 0,29, 2,46). Однако, когда я помещаю эти значения обратно в приведенную выше матрицу, я не могу уменьшить матрицу до формы с двумя переменными. Я всегда имею дело с 3 переменными. Например, если я ставлю t = -0,05, то получаю следующее:

Нахождение внутренней общей касательной к паре коник

Может кто-нибудь, пожалуйста, помогите мне с этим?

Ваш вопрос помечен как C++ и Matlab, но для них нет кода. Возможно, вы ищете math.stackexchange.com? Если это проблема с кодированием, пожалуйста, включите свой код. Если вы публикуете сообщения по математике, пожалуйста, включайте уравнения напрямую, а не ссылки на изображения.

Luis 12.12.2020 01:36

У меня есть код Matlab, но я не включил его, потому что он разбросан по нескольким файлам. Но я все подробно объяснил и дал ссылку на то, о чем я говорю. Так что читателю должно быть понятно, о чем я говорю. Да, это более или менее математическая задача.

Kashish Dhal 13.12.2020 15:10
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
352
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Набросал алгоритм на питоне, думаю на вашем примере вроде работает... но торопился и не проверил как следует, так что могут быть баги...

import numpy as np
import math

# technical module, functions, details
def homogenize(x):
    return np.array([x[0], x[1], 1])

def cos_sin(angle_deg):
    return math.cos(angle_deg*math.pi/180), math.sin(angle_deg*math.pi/180)

def rotation(cs_sn):
    return np.array([[cs_sn[0], -cs_sn[1]], 
                     [cs_sn[1],  cs_sn[0]]])

# defining the isometry (the rotation plus translation) transformation
# between the coordinate system aligned with the conic and a general (world) 
# coordinate system
def isom_inverse(angle, translation):
    '''
    isometry from conic-aligned coordinate system (conic attached)
    to global coordinate system (world system) 
    '''
    cos_, sin_ = cos_sin(angle)
    return np.array([[cos_, -sin_, translation[0]], 
                     [sin_,  cos_, translation[1]], 
                     [   0,     0,             1]])
    
def isom(angle, translation):
    '''
    isometry from global coordinate system (world system) 
    to conic-aligned coordinate system (conic attached) 
    '''
    cos_, sin_ = cos_sin(-angle)
    tr = - rotation((cos_, sin_)).dot(translation)
    return np.array([[ cos_, -sin_, tr[0]], 
                     [ sin_,  cos_, tr[1]], 
                     [    0,     0,    1 ]])

# calculating the coinc defined by a pair of axes' lengts, 
# axes rotation angle and center of the conic  
def Conic(major, minor, angle, center):
    D = np.array([[minor**2,        0,                 0],
                  [       0, major**2,                 0], 
                  [       0,        0, -(minor*major)**2]])
    U = isom(angle, center)
    return (U.T).dot(D.dot(U))     

# calculating the coinc dual to the conic defined by a pair of axes' lengths, 
# axes rotation angle and center of the conic  
def dual_Conic(major, minor, angle, center):
    D_1 = np.array([[major**2,        0,  0], 
                    [       0, minor**2,  0], 
                    [       0,        0, -1]])
    U_1 =  isom_inverse(angle, center)
    return (U_1).dot(D_1.dot(U_1.T)) 

# transforming the matrix of a conic into a vector of six coefficients
# of a quadratic equation with two variables
def conic_to_equation(C):
    '''
    c[0]*x**2 + c[1]*x*y + c[2]*y**2 + c[3]*x + c[4]*y + c[5] = 0
    '''
    return np.array([C[0,0], 2*C[0,1], C[1,1], 2*C[0,2], 2*C[1,2], C[2,2]])    

# transforming the vector of six coefficients
# of a quadratic equation with two variables into a matrix of 
# the corresponding conic 
def equation_to_conic(eq):
    '''
    eq[0]*x**2 + eq[1]*x*y + eq[2]*y**2 + eq[3]*x + eq[4]*y + eq[5] = 0
    '''
    return np.array([[2*eq[0],   eq[1],   eq[3]],
                     [  eq[1], 2*eq[2],   eq[4]],
                     [  eq[3],   eq[4], 2*eq[5]]]) / 2

# given a point (x,y) define the vector (x^2, xy, y^2, x, y, 1)    
def argument(x):
    return np.array([x[0]**2, x[0]*x[1], x[1]**2, x[0], x[1], 1])

# given x = (x[0],x[1]) calculate the value of the quadratic equation with
# six coefficients coeff
def quadratic_equation(x, coeff):
    '''
    coeff[0]*x**2 + coeff[1]*x*y + coeff[2]*y**2 + coeff[3]*x + coeff[4]*y + coeff[5] = 0
    '''
    return coeff.dot( argument(x) )    

# given a pair of conics, as a pair of symmetric matrices, 
# calculate the vector k = (k[0], k[1], k[2]) of values for each of which 
# the conic c1 - k[i]*c2 from the pencil of conics c1 - t*c2 
# is a degenerate conic (the anti-symmetric product of a pair of linear forms) 
# and also find the matrix U 
# of the projective transformation that simplifies the geometry of 
# the pair of conics, the geometry of the pencil c1 - t*c2 in general, 
# as well as the geometry of the three degenerate conics in particular    
def transform(c1, c2):
    '''
    c1 and c2 are 3 by 3 symmetric matrices of the two conics
    '''
    c21 = np.linalg.inv(c2).dot(c1)
    k, U = np.linalg.eig(c21)
    return k, U

# the same as before, but for a pair of equations instead of matrices of conics
def eq_transform(eq1, eq2):
    '''
    eq1 and eq2 = np.array([eq[0], eq[1], eq[2], eq[3], eq[4], eq[5]])
    '''
    C1 = equation_to_conic(eq1)
    C2 = equation_to_conic(eq2)
    return transform(C1, C2)

# realizing the matrix U as a projective transformation
def proj(U, x):
    if len(x) == 2:
        x = homogenize(x)
    y = U.dot(x)
    y = y / y[2]
    return y[0:2]

# find the common points, i.e. points of intersection of a pair of conics
# represented by a pair of symmetric matrices
def find_common_points(c1, c2):
    k, U = transform(c1, c2)
    L1 = (U.T).dot((c1 - k[0]*c2).dot(U))
    L2 = (U.T).dot((c1 - k[1]*c2).dot(U))
    sol = np.empty((4,3), dtype=float)
    for i in range(2):
        for j in range(2):
            sol[i+2*j,0:2] = np.array([math.sqrt(abs(L2[2,2] / L2[0,0]))*(-1)**i, math.sqrt(abs(L1[2,2] / L1[1,1]))*(-1)**j])
            sol[i+2*j,0:2] = proj(U, sol[i+2*j,0:2])
    sol[:,2] = np.ones(4)
    return sol

# find the solutions, i.e. the points x=(x[0],x[1]) saisfying the pair 
# of quadratic equations 
# represented by a pair of vectors eq1 and eq2 of 6 coefficients
def solve_eq(eq1, eq2):
    conic1 = equation_to_conic(eq1)
    conic2 = equation_to_conic(eq2)
    return find_common_points(conic1, conic2)


'''
Esample of finding the common tangents of a pair of conics:
conic 1: major axis = 2, minor axis = 1, angle = 45, center = (0,0)
conic 2: major axis = 3, minor axis = 1, angle = 120, center = (15,0)
'''

a = 2
b = 1
cntr = np.array([0,0])
w = 45

Q1 = Conic(a, b, w, cntr)
dQ1 = dual_Conic(a, b, w, cntr)

a = 3
b = 1
cntr = np.array([15,0])
w = 120

Q2 = Conic(a, b, w, cntr)
dQ2 = dual_Conic(a, b, w, cntr)

R = find_common_points(dQ1, dQ2)

print('')
print(R)
print('')
print('checking that the output forms common tangent lines: ')
print('')
print('conic 1: ')
print(np.diagonal(R.dot(dQ1.dot(R.T))) )
print('')
print('conic 2: ')
print(np.diagonal(R.dot(dQ2.dot(R.T))) )
#conic_to_equation(dQ1)

Некоторые пояснения: Предположим, вы хотите найти точки пересечения двух коник C1 и C2. Предположим для простоты, что это настоящие эллипсы, пересекающиеся в четырех разных точках (чтобы избежать комплексных чисел).

В случае нахождения общих касательных к паре коник просто преобразуйте две коники в две соответствующие двойственные, а затем найдите точки пересечения из двойников. Эти точки пересечения являются коэффициентами уравнения касательных исходных коник.

Возможно, существует несколько различных геометрических интерпретаций этой задачи, но давайте остановимся на карандаше коник. Две коники C1 и C2 представлены 3 на 3 симметричными матрицами с ненулевыми определителями, которые я обозначил C1 и C2. Линейная комбинация, называемая пучком коник, порожденных C1 и C2, представляет собой t-параметризованное семейство коник C1 - t*C2 , где t — просто число. Важно то, что каждая коника C1 - tC2 проходит через точки пересечения C1 и C2, и это единственные четыре общие точки. Вы можете доказать это, заметив, что если x.T * C1 * x = x.T * C1 * x = 0, то x.T * (C1 - t*C2) * x = x.T * C1 * x - t * x.T * C2 * x = 0 - t*0 = 0. Кроме того, если вы возьмете точку пересечения C1 и C1 - t*C2, то C2 = C1 - t*C2 + s*C2 вы можете применить тот же аргумент, когда s = t.

В этом семействе коник есть три вырожденных коники, которые геометрически представляют собой три пары прямых. Они возникают именно тогда, когда t таково, что det( C1 - t*C2 ) = 0. Это полиномиальное уравнение степени 3 относительно t, поэтому существует три, скажем, разных решения k[0], k[1], k[2], из-за правильности C1 и C2. Проективно говоря, каждая вырожденная коника C1 - k[j]*C2 представляет собой пару прямых, имеющих общую точку пересечения u[:,j] = [ u[0,j] : u[1,j] : u[2,j] ]. Тем более rank(C1 - k[j]*C2) = 2, так ker(C1 - k[j]*C2) = 1. Эта точка u[:,j] характеризуется как решение уравнения (C1 - k[j]*C2) * u[:,j] = 0. Поскольку C2 обратимо (невырожденное), умножьте обе части уравнения на inverse(C2) и получите эквивалентное уравнение ( (inverse(C2) * C1) - k[j]*Identity ) * u[:,j] = 0, которое является уравнением на собственные значения, с k[j] в качестве собственного значения и u[:,j] в качестве собственного вектора. Выходом функции transform() является массив 1 на 3 k собственных значений и матрица 3 на 3 U = [ u[:,0], u[:,1], u[:,2] ] собственных векторов.

Сопряжение C1 - k[j]*C2 by U, i.e. (U.T)*(C1 - k[j]*C2)*U геометрически эквивалентно выполнению проективного преобразования, которое переводит u[:,0] и u[:,1] в бесконечность, а u[:,2] в начало координат. Таким образом, U меняет систему координат с общей на специальную систему координат, в которой две вырожденные коники задаются парами параллельных прямых и в сумме пересекаются в прямоугольнике. Третья коника представлена ​​диагнолами прямоугольника.

На этой новой картинке проблема пересечения может быть легко решена, просто считывая одно решение из элементов матриц (U.T)*(C1 - k[j]*C2)*U (точки пересечения являются вершинами прямоугольника, поэтому, если вы найдете одну из них, другие просто зеркально симметричны друг другу).

Привет @Futurologist, Спасибо за ответ! Не могли бы вы объяснить, что вы делаете в функции преобразования. И если возможно, пожалуйста, пролейте свет на линейную алгебру, используемую для получения решения.

Kashish Dhal 06.01.2021 16:31

@KashishDhal Я добавил некоторые пояснения.

Futurologist 07.01.2021 23:10

Спасибо, вы рекомендуете прочитать какой-либо материал (книги и т. д.), чтобы лучше понять концепции проективной геометрии, о которых мы здесь говорим?

Kashish Dhal 07.01.2021 23:51

Привет @Futurologist, Есть ли способ найти угол между внутренними касательными линиями, не получая точку пересечения с кониками?

Kashish Dhal 12.02.2021 03:22

@KashishDhal Честно говоря, я не знаю навскидку, но вполне может быть такой метод. Я просто не осознаю этого в данный момент и недостаточно об этом думаю.

Futurologist 12.02.2021 03:58

@KashishDhal Подожди, может быть, я неправильно понял. Вы спрашиваете, можно ли найти угол между внутренними касательными, не находя в первую очередь какое-то представление для общих касательных (например, векторов нормалей), или вы спрашиваете, можно ли найти угол, не пытаясь найти точки касания каждой касательной с кониками?

Futurologist 12.02.2021 05:04

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

Futurologist 12.02.2021 05:08

Пожалуйста, посмотрите на эту ссылку, если вы думаете, что можете помочь! Спасибо! math.stackexchange.com/questions/4025052/…

Kashish Dhal 14.02.2021 05:33

есть ли способ процитировать эту статью? Я вижу опцию цитирования на mathstackexchange, но не здесь stackoverflow. Пожалуйста, дайте мне знать.

Kashish Dhal 22.03.2021 04:42

Кроме того, я хотел знать, как вы читаете вершины прямоугольника в специальной системе координат в строке здесь, np.array([math.sqrt(abs(L2[2,2]/L2[0,0])) *(-1)**i, math.sqrt(abs(L1[2,2] / L1[1,1]))*(-1)**j])

Kashish Dhal 22.03.2021 04:46

Другие вопросы по теме