Вращение эллипса вдоль его главных осей

Моя цель — построить эллипсоид вращения в 3D. У меня есть код для создания моделирования соответствующего эллипса в 2D:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse

# Define ground station and airplane positions
ground_station = np.array([2, 2])
airplane = np.array([4, 5])

# Actual distance between ground station and airplane
true_distance = np.linalg.norm(ground_station - airplane)

# Distance measured by DME
dme_distance = 1.25 * true_distance

# Calculate the center of the ellipse (midpoint between ground station and airplane)
center = (ground_station + airplane) / 2

# Calculate the semi-major and semi-minor axes of the ellipse
a = dme_distance / 2
b = np.sqrt(a**2 - (true_distance / 2)**2)

# Calculate the angle of rotation for the ellipse
angle = np.arctan2(airplane[1] - ground_station[1], airplane[0] - ground_station[0])

# Visualize the ellipse
ellipse = Ellipse(xy=center, width=2 * a, height=2 * b, angle=np.degrees(angle), edgecolor='r', linestyle='dotted', fill=False)

# Visualize simulation
plt.figure(figsize=(8, 6))
plt.plot(*ground_station, 'ro', label='Ground Station')
plt.plot(*airplane, 'bo', label='Airplane')
plt.xlabel('X')
plt.ylabel('Y')
plt.title('2D Simulation')
plt.legend()
plt.grid(True)

plt.gca().add_patch(ellipse)
plt.axis('equal')
plt.show()

Получается такой эллипс:

Теперь мне нужно расширить это 2D-представление в 3D. Два фокуса остаются в плоскости xy, а свойства эллипса остаются прежними. Цель состоит в том, чтобы повернуть эллипс вдоль его большой оси, чтобы получить эллипсоид вращения.

Мой подход заключался в создании 360 эллипсов, где каждый эллипс поворачивается на 1 градус. Почему-то я не могу заставить его просто вращаться, не меняя его свойств.

Другой подход заключался в том, чтобы просто построить его в виде эллипсоида. Вот мой код для этого:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.patches import Ellipse

ground_station_3d = np.array([2, 2, 0])  
airplane_3d = np.array([4, 5, 0])        

true_distance = np.linalg.norm(ground_station_3d[:2] - airplane_3d[:2])

dme_distance = 1.25 * true_distance

center = (ground_station_3d + airplane_3d) / 2

a = dme_distance / 2
b = np.sqrt(a**2 - (true_distance / 2)**2)

angle = np.arctan2(airplane_3d[1] - ground_station_3d[1], airplane_3d[0] - ground_station_3d[0])

ellipse_height = 5

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = center[0] + a * np.outer(np.cos(u), np.sin(v))
y = center[1] + b * np.outer(np.sin(u), np.sin(v))
z = center[2] + ellipse_height * np.outer(np.ones(np.size(u)), np.cos(v))
ax.plot_surface(x, y, z, color='r', alpha=0.5)

ax.scatter(*ground_station_3d, color='b', label='Bodenstation')
ax.scatter(*airplane_3d, color='g', label='Flugzeug')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('3D-Simulation')
ax.legend()

plt.show()

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

Мне нужна помощь в поиске правильного способа вращения эллипса вдоль его главной оси. Если в Python нет подходящего способа сделать это, я был бы признателен за помощь в поиске способов в других языках программирования.

С уважением

Обновлено: Использование матрицы вращения и построение эллипсоида дает следующую картину:

Как вы можете видеть, при выравнивании его вокруг оси между обоими фокусами кажется, что он ориентирован неправильно и что есть точки, которые имеют большее расстояние на пути фокус1->эллипсоид->фокус2, чем другие.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
118
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Примечание: отредактировано, так как ОП теперь хочет, чтобы самолет (и, следовательно, один фокус) находился в воздухе!

Я предлагаю сначала сориентировать эллипсоид в стандартном смысле (с центром в начале координат с полуосями a, b, c вдоль направлений x, y, z), затем повернуть на соответствующий угол вокруг оси z, одновременно перемещая в сторону правильный центр.

Для канонического выравнивания:

xp = a cos(u)
yp = b sin(u) cos(v)
zp = c sin(u) sin(v)

Затем вы добавляете перевод в центр (как делаете сейчас) и одновременно вращаете. Вращение состоит из вращения вокруг старой оси Z для выравнивания плоскости xy, а затем вращения вокруг НОВОЙ оси Y для получения угла возвышения самолета. Вы могли бы сделать это двумя последовательными поворотами, но проще сформулировать одно линейное преобразование, заметив, что его столбцы представляют собой просто преобразованные единичные декартовы векторы. Таким образом, новая ось x (ex) смотрит в направлении самолета, новая ось y (ey) просто вращается в плоскости xy, а новая ось z (ez) формируется для создания правостороннего ортогонального набора. . Вы (ну, я) должны помнить, что массивы numpy 1-d по сути представляют собой векторы-строки, что имеет последствия при создании матриц или умножении матриц.

В коде это выглядит так

import math
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

ground_station_3d = np.array([2, 2, 0])  
airplane_3d = np.array([4, 5, 5])

true_distance = np.linalg.norm( airplane_3d - ground_station_3d )
center = ( ground_station_3d + airplane_3d ) / 2

dme_distance = 1.25 * true_distance
a = dme_distance / 2
b = np.sqrt( a ** 2 - ( true_distance / 2 ) ** 2 )
c = b

# construct rotation matrix R (columns are the transforms of the cartesian basis vectors)
diffx = airplane_3d[0] -  ground_station_3d[0]
diffy = airplane_3d[1] -  ground_station_3d[1]
ex = ( airplane_3d - ground_station_3d ) / true_distance     # new x axis stares at aircraft
ey = np.array( [ -diffy, diffx, 0 ] ) / math.sqrt( diffx * diffx + diffy * diffy )
ez = np.cross( ex, ey )
R = ( np.vstack( ( ex, ey, ez ) ) ).T

N = 100
u = np.linspace( 0, 2 * np.pi, N )
v = np.linspace( 0, np.pi, N )

# First form an ellipsoid conventionally aligned with the axes (semi-axes are a, b, c)
xp = a * np.outer( np.cos(u), np.ones(N) )
yp = b * np.outer( np.sin(u), np.cos(v) )
zp = c * np.outer( np.sin(u), np.sin(v))

# Now rotate (with R) and translate (by center)
x = np.zeros( ( N, N ) )
y = np.zeros( ( N, N ) )
z = np.zeros( ( N, N ) )
for i in range( N ):
    for j in range( N ):
        xyzp = np.array( ( xp[i,j], yp[i,j], zp[i,j] ) )   # row vector (unfortunately)
        xyz = center + xyzp @ ( R.T )                      # ditto
        x[i,j] = xyz[0]
        y[i,j] = xyz[1]
        z[i,j] = xyz[2]

# Plot
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x, y, z, color='r', alpha=0.3)
ax.scatter(*ground_station_3d, color='b', label='Bodenstation')
ax.scatter(*airplane_3d, color='g', label='Flugzeug')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('3D-Simulation')
ax.legend()
plt.show()

Выход:

Одинаковы ли свойства эллипса у сфероида? Основная характеристика состоит в том, что все расстояния на пути: фокусы1 -> любая точка поверхности сфероида -> фокусы2 должны быть одинаковыми для каждой точки поверхности сфероида. Просто взглянув на вашу симуляцию, я не могу сказать, верно ли это свойство. Поскольку это свойство справедливо для двумерного эллипса в моем коде, я думаю, оно справедливо и для вашего сфероида, но это выглядит не так. Цените помощь!

Leon Archinger 22.03.2024 14:22

@LeonArchinger, это будет правда, если вы установите c=b. Я установил c равным 5, потому что именно это вы и сделали в своем коде. Однако вскоре вы сможете вместо этого установить c=b, если захотите.

lastchance 22.03.2024 14:55

Когда я регулирую положение самолета так, чтобы оно не находилось в плоскости xy, а имело координаты z, равные 5, т. е. как я могу убедиться, что эллипсоид правильно повернут во всех трех измерениях, чтобы фокусы находились ВНУТРИ эллипсоида? Вот где я испытываю большие трудности.

Leon Archinger 22.03.2024 16:09

Не могли бы вы уточнить, где вам нужны эти два фокуса? Вам нужен один в плоскости xy (z=0), а другой в плоскости z=5? Честно говоря, в вашем исходном вопросе говорится: «Два фокуса остаются в плоскости xy», так что я теперь немного запутался.

lastchance 22.03.2024 16:14

Вы правы, изначально они находились в плоскости x-y. Однако мне нужно его отрегулировать, потому что самолет в этом сценарии летит не в плоскости xy. Наземная станция должна остаться там, где она была изначально [(2, 2, 0)], а местоположение самолета переместиться на [(4, 5, 5)]. Каким-то образом при вычислении угла не учитывается направление z, и я не могу это исправить.

Leon Archinger 22.03.2024 16:32

Хорошо, @LeonArchinger, я исправил свой код и описание, и теперь твой самолет летает!

lastchance 22.03.2024 18:25

Спасибо за ваш ответ! Последний вопрос к вашей реализации: я запустил код и повернул эллипс в своей симуляции. Когда я выравниваю его так, чтобы смотреть прямо на ось между двумя точками, кажется, что есть точки, которые находятся дальше от самолета, чем другие, что приведет к разным расстояниям на пути фокусы -> поверхность эллипсоида -> фокусы. Это просто вопрос масштабирования и трехмерного представления? поскольку первая реализация в плоскости xy этого не имеет. Я загрузил картинку в свой вопрос

Leon Archinger 26.03.2024 14:53

@LeonArchinger, свойство эллипса (и, соответственно, эллипсоида) заключается в том, что сумма расстояний от любой точки на нем до двух фокусов должна быть постоянной. Если вы создадите новый массив dist = np.zeros( ( N, N ) ), а затем добавите строку dist[i,j] = np.linalg.norm( airplane_3d - xyz ) + np.linalg.norm( ground_station_3d - xyz ) в конец вложенного цикла i,j, а затем print( dist ) после цикла, то вы обнаружите, что сумма расстояний от двух фокусов всех точек равна 7,7055175. Итак, это определенно эллипсоид с этими точками в качестве фокусов.

lastchance 26.03.2024 15:19

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