debian-skyfield/skyfield/projections.py

72 lines
2.2 KiB
Python

from numpy import sqrt
from .functions import length_of
def _derive_stereographic():
"""Compute the formulae to cut-and-paste into the routine below."""
from sympy import symbols, atan2, acos, rot_axis1, rot_axis3, Matrix
x_c, y_c, z_c, x, y, z = symbols('x_c y_c z_c x y z')
# The angles we'll need to rotate through.
around_z = atan2(x_c, y_c)
around_x = acos(-z_c)
# Apply rotations to produce an "o" = output vector.
v = Matrix([x, y, z])
xo, yo, zo = rot_axis1(around_x) * rot_axis3(-around_z) * v
# Which we then use the stereographic projection to produce the
# final "p" = plotting coordinates.
xp = xo / (1 - zo)
yp = yo / (1 - zo)
return xp, yp
def _optimize(expressions):
from sympy import cse, numbered_symbols
commons, outputs = cse(
expressions,
numbered_symbols('t'),
optimizations='basic',
)
for symbol, expr in commons:
print(symbol, '=', expr)
print()
for expr in outputs:
print(expr)
def build_stereographic_projection(center):
"""Compute *x* and *y* coordinates at which to plot the positions."""
# TODO: Computing the center should really be done using
# optimization, as in:
# https://math.stackexchange.com/questions/409217/
p = center.position.au
u = p / length_of(p)
if len(u.shape) > 1:
c = u.mean(axis=1)
c = c / length_of(c)
else:
c = u
x_c, y_c, z_c = c
def project(position):
p = position.position.au
u = p / length_of(p)
x, y, z = u
# x_out = (x*y_c/sqrt(x_c**2 + y_c**2) - x_c*y/sqrt(x_c**2 + y_c**2))/(x*x_c*sqrt(-z_c**2 + 1)/sqrt(x_c**2 + y_c**2) + y*y_c*sqrt(-z_c**2 + 1)/sqrt(x_c**2 + y_c**2) + z*z_c + 1)
# y_out = (-x*x_c*z_c/sqrt(x_c**2 + y_c**2) - y*y_c*z_c/sqrt(x_c**2 + y_c**2) + z*sqrt(-z_c**2 + 1))/(x*x_c*sqrt(-z_c**2 + 1)/sqrt(x_c**2 + y_c**2) + y*y_c*sqrt(-z_c**2 + 1)/sqrt(x_c**2 + y_c**2) + z*z_c + 1)
# return x_out, y_out
t0 = 1/sqrt(x_c**2 + y_c**2)
t1 = x*x_c
t2 = sqrt(-z_c**2 + 1)
t3 = t0*t2
t4 = y*y_c
t5 = 1/(t1*t3 + t3*t4 + z*z_c + 1)
t6 = t0*z_c
return t0*t5*(x*y_c - x_c*y), -t5*(t1*t6 - t2*z + t4*t6)
return project