# Path: spyce/vector.py
# class Mat3(list):
#     def __init__(cls, *args, **kwargs):
#         if args or kwargs:
#             super().__init__(*args, **kwargs)
#         else:
#             super().__init__([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
# 
#     def __sub__(A, B):
#         # used by assertAlmostEqual()
#         return Mat3([x-y for a, b in zip(A, B) for x, y in zip(a, b)])
# 
#     def __abs__(A):
#         """Maximum metric (see Chebyshev distance)"""
#         # used by assertAlmostEqual()
#         return max(abs(a) for a in A)
# 
#     def __mul__(self, x):
#         if isinstance(x, Mat3):  # matrix-matrix multiplication
#             m = Mat3(zip(*x))
#             return Mat3([m*row for row in self])
#         else:  # matrix-vector multiplication
#             return Vec3([sum(a*b for a, b in zip(row, x)) for row in self])
# 
#     @classmethod
#     def rotation(cls, angle, x, y, z):
#         """Rotation matrix of given angle (radians) around axis (x,y,z)"""
#         s = math.sin(angle)
#         c = math.cos(angle)
#         d = math.sqrt(x*x + y*y + z*z)
#         x, y, z = x/d, y/d, z/d
#         return cls([
#             [x*x*(1-c)+c,   x*y*(1-c)-z*s, x*z*(1-c)+y*s],
#             [y*x*(1-c)+z*s, y*y*(1-c)+c,   y*z*(1-c)-x*s],
#             [z*x*(1-c)-y*s, z*y*(1-c)+x*s, z*z*(1-c)+c],
#         ])
# 
#     @classmethod
#     def from_euler_angles(cls, alpha, beta, gamma):
#         """Return the rotation matrix from the given Z1X2Z3 Euler angles"""
#         # see https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
#         c1, s1 = math.cos(alpha), math.sin(alpha)
#         c2, s2 = math.cos(beta),  math.sin(beta)
#         c3, s3 = math.cos(gamma), math.sin(gamma)
#         return cls([
#             [c1*c3-c2*s1*s3, -c1*s3-c2*c3*s1, s1*s2],
#             [c3*s1+c1*c2*s3, c1*c2*c3-s1*s3,  -c1*s2],
#             [s2*s3,          c3*s2,           c2],
#         ])


import math
import spyce.orbit_determination
import spyce.orbit_angles
import spyce.orbit_state
import spyce.orbit_target
from spyce.vector import Mat3
        self.argument_of_periapsis = float(argument_of_periapsis)
        self.epoch = float(epoch)
        self.mean_anomaly_at_epoch = float(mean_anomaly_at_epoch)

        # semi-major axis
        if self.eccentricity == 1:  # parabolic trajectory
            self.semi_major_axis = math.inf
        else:
            self.semi_major_axis = self.periapsis / (1 - self.eccentricity)

        # other distances
        self.apoapsis = self.semi_major_axis * (1 + self.eccentricity)
        self.semi_latus_rectum = self.periapsis * (1 + self.eccentricity)
        e2 = 1-self.eccentricity**2
        self.semi_minor_axis = self.semi_major_axis * math.sqrt(abs(e2))
        self.focus = self.semi_major_axis * self.eccentricity

        # mean motion
        mu = self.primary.gravitational_parameter
        if self.eccentricity == 1:  # parabolic trajectory
            self.mean_motion = 3 * math.sqrt(mu / self.semi_latus_rectum**3)
        else:
            self.mean_motion = math.sqrt(mu / abs(self.semi_major_axis)**3)

        # period
        if self.eccentricity >= 1:  # parabolic/hyperbolic trajectory
            self.period = math.inf
        else:  # circular/elliptic orbit
            self.period = 2*math.pi / self.mean_motion


# Path: spyce/vector.py
# class Mat3(list):
#     def __init__(cls, *args, **kwargs):
#         if args or kwargs:
#             super().__init__(*args, **kwargs)
#         else:
#             super().__init__([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
# 
#     def __sub__(A, B):
#         # used by assertAlmostEqual()
#         return Mat3([x-y for a, b in zip(A, B) for x, y in zip(a, b)])
# 
#     def __abs__(A):
#         """Maximum metric (see Chebyshev distance)"""
#         # used by assertAlmostEqual()
#         return max(abs(a) for a in A)
# 
#     def __mul__(self, x):
#         if isinstance(x, Mat3):  # matrix-matrix multiplication
#             m = Mat3(zip(*x))
#             return Mat3([m*row for row in self])
#         else:  # matrix-vector multiplication
#             return Vec3([sum(a*b for a, b in zip(row, x)) for row in self])
# 
#     @classmethod
#     def rotation(cls, angle, x, y, z):
#         """Rotation matrix of given angle (radians) around axis (x,y,z)"""
#         s = math.sin(angle)
#         c = math.cos(angle)
#         d = math.sqrt(x*x + y*y + z*z)
#         x, y, z = x/d, y/d, z/d
#         return cls([
#             [x*x*(1-c)+c,   x*y*(1-c)-z*s, x*z*(1-c)+y*s],
#             [y*x*(1-c)+z*s, y*y*(1-c)+c,   y*z*(1-c)-x*s],
#             [z*x*(1-c)-y*s, z*y*(1-c)+x*s, z*z*(1-c)+c],
#         ])
# 
#     @classmethod
#     def from_euler_angles(cls, alpha, beta, gamma):
#         """Return the rotation matrix from the given Z1X2Z3 Euler angles"""
#         # see https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
#         c1, s1 = math.cos(alpha), math.sin(alpha)
#         c2, s2 = math.cos(beta),  math.sin(beta)
#         c3, s3 = math.cos(gamma), math.sin(gamma)
#         return cls([
#             [c1*c3-c2*s1*s3, -c1*s3-c2*c3*s1, s1*s2],
#             [c3*s1+c1*c2*s3, c1*c2*c3-s1*s3,  -c1*s2],
#             [s2*s3,          c3*s2,           c2],
#         ])


# Path: spyce/orbit.py
import math
import spyce.orbit_determination
import spyce.orbit_angles
import spyce.orbit_state
import spyce.orbit_target
from spyce.vector import Mat3

        self.argument_of_periapsis = float(argument_of_periapsis)
        self.epoch = float(epoch)
        self.mean_anomaly_at_epoch = float(mean_anomaly_at_epoch)

        # semi-major axis
        if self.eccentricity == 1:  # parabolic trajectory
            self.semi_major_axis = math.inf
        else:
            self.semi_major_axis = self.periapsis / (1 - self.eccentricity)

        # other distances
        self.apoapsis = self.semi_major_axis * (1 + self.eccentricity)
        self.semi_latus_rectum = self.periapsis * (1 + self.eccentricity)
        e2 = 1-self.eccentricity**2
        self.semi_minor_axis = self.semi_major_axis * math.sqrt(abs(e2))
        self.focus = self.semi_major_axis * self.eccentricity

        # mean motion
        mu = self.primary.gravitational_parameter
        if self.eccentricity == 1:  # parabolic trajectory
            self.mean_motion = 3 * math.sqrt(mu / self.semi_latus_rectum**3)
        else:
            self.mean_motion = math.sqrt(mu / abs(self.semi_major_axis)**3)

        # period
        if self.eccentricity >= 1:  # parabolic/hyperbolic trajectory
            self.period = math.inf
        else:  # circular/elliptic orbit
            self.period = 2*math.pi / self.mean_motion


        self.transform = Mat3.from_euler_angles(