Моя цель — построить эллипсоид вращения в 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, чем другие.






Примечание: отредактировано, так как ОП теперь хочет, чтобы самолет (и, следовательно, один фокус) находился в воздухе!
Я предлагаю сначала сориентировать эллипсоид в стандартном смысле (с центром в начале координат с полуосями 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()
Выход:
@LeonArchinger, это будет правда, если вы установите c=b. Я установил c равным 5, потому что именно это вы и сделали в своем коде. Однако вскоре вы сможете вместо этого установить c=b, если захотите.
Когда я регулирую положение самолета так, чтобы оно не находилось в плоскости xy, а имело координаты z, равные 5, т. е. как я могу убедиться, что эллипсоид правильно повернут во всех трех измерениях, чтобы фокусы находились ВНУТРИ эллипсоида? Вот где я испытываю большие трудности.
Не могли бы вы уточнить, где вам нужны эти два фокуса? Вам нужен один в плоскости xy (z=0), а другой в плоскости z=5? Честно говоря, в вашем исходном вопросе говорится: «Два фокуса остаются в плоскости xy», так что я теперь немного запутался.
Вы правы, изначально они находились в плоскости x-y. Однако мне нужно его отрегулировать, потому что самолет в этом сценарии летит не в плоскости xy. Наземная станция должна остаться там, где она была изначально [(2, 2, 0)], а местоположение самолета переместиться на [(4, 5, 5)]. Каким-то образом при вычислении угла не учитывается направление z, и я не могу это исправить.
Хорошо, @LeonArchinger, я исправил свой код и описание, и теперь твой самолет летает!
Спасибо за ваш ответ! Последний вопрос к вашей реализации: я запустил код и повернул эллипс в своей симуляции. Когда я выравниваю его так, чтобы смотреть прямо на ось между двумя точками, кажется, что есть точки, которые находятся дальше от самолета, чем другие, что приведет к разным расстояниям на пути фокусы -> поверхность эллипсоида -> фокусы. Это просто вопрос масштабирования и трехмерного представления? поскольку первая реализация в плоскости xy этого не имеет. Я загрузил картинку в свой вопрос
@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. Итак, это определенно эллипсоид с этими точками в качестве фокусов.
Одинаковы ли свойства эллипса у сфероида? Основная характеристика состоит в том, что все расстояния на пути: фокусы1 -> любая точка поверхности сфероида -> фокусы2 должны быть одинаковыми для каждой точки поверхности сфероида. Просто взглянув на вашу симуляцию, я не могу сказать, верно ли это свойство. Поскольку это свойство справедливо для двумерного эллипса в моем коде, я думаю, оно справедливо и для вашего сфероида, но это выглядит не так. Цените помощь!