Skip to content

Attitude

A spacecraft attitude history rendered as an animated orientation: the object's body axes turn over the trajectory, shown as a small body box.

from gmat_czml import to_czml
from orbit_formats import read

attitude = read("spacecraft.aem")  # a CCSDS-AEM quaternion history
to_czml(trajectory, attitude=attitude).save("orbit.czml")

attitude is an orbit-formats Attitude — a CCSDS-AEM quaternion history, naming the two reference frames the rotation maps between (an external reference such as EME2000, and the spacecraft body frame) and a quaternion per epoch.

What the converter does

The attitude becomes a sampled orientation on a child entity, <object>/attitude, that references the object's position and carries a body box. As the playhead moves, the box turns to the spacecraft's orientation at that time, so the body frame is visible against the orbit.

The orientation is sampled epoch-relative — one reference epoch plus a per-sample offset — with a LINEAR interpolation hint, so a Cesium client interpolates smoothly between attitudes. The body box has three distinct dimensions, so which way the body points reads unambiguously.

The reference frame

This is the part that needs care. A CZML orientation is always interpreted as the rotation from the body axes to the Earth-fixed (ECEF) axes — unlike a position, it has no reference-frame field to declare an inertial frame. An AEM attitude, though, is usually expressed against an inertial reference (for example EME2000 → SC_BODY).

So gmat-czml composes the attitude into the body→ECEF convention: it combines the body↔reference rotation from the AEM with the reference→Earth-fixed rotation at each epoch (the same Earth-orientation rotation the ground track uses). An inertial-referenced attitude therefore renders correctly — the body box tracks the spacecraft's real orientation, not one drifting with the Earth's rotation. An attitude already expressed in an Earth-fixed frame passes straight through.

The rotation direction comes from the AEM's ATTITUDE_DIR tag (A2B / B2A), defaulting to A2B when a file omits it. The quaternion components are read scalar-last (Q1 Q2 Q3 QC), matching CZML's [X, Y, Z, W] order directly.

The attitude epochs carry their own time scale (the AEM's TIME_SYSTEM), converted to UTC for the document timeline; the orientation is available over the attitude history's span.

One object at a time

An attitude orients one spacecraft, so it attaches to the single rendered trajectory. Passing attitude for a multi-object document raises AmbiguousAttitudeTargetError — which craft the attitude belongs to cannot be told from the record. Only the quaternion representation is rendered; an Euler-angle or spin attitude raises UnsupportedAttitudeTypeError. An attitude whose two frames do not resolve to one recognised external reference plus one body frame raises AttitudeFrameError.

Packets

The attitude is one packet, <object>/attitude. It references the object's position (<object>#position) and carries the sampled orientation and the body box.

Styling

The body box defaults to translucent cyan. Recolour its fill and outline with the AttitudeStyle on the Style's attitude field; see Styling. The box's dimensions are fixed by the converter; a glTF-model hook waits on an asset pipeline.