TEST_F(BodyCentredNonRotatingDynamicFrameTest, Serialization) {
  serialization::DynamicFrame message;
  small_frame_->WriteToMessage(&message);

  EXPECT_TRUE(message.HasExtension(
      serialization::BodyCentredNonRotatingDynamicFrame::extension));
  auto const extension = message.GetExtension(
      serialization::BodyCentredNonRotatingDynamicFrame::extension);
  EXPECT_TRUE(extension.has_centre());
  EXPECT_EQ(1, extension.centre());

  auto const read_small_frame =
      DynamicFrame<ICRS, Small>::ReadFromMessage(message, ephemeris_.get());
  EXPECT_THAT(read_small_frame, Not(IsNull()));

  Instant const t = t0_ + period_;
  DegreesOfFreedom<Small> const point_dof =
      {Displacement<Small>({10 * Metre, 20 * Metre, 30 * Metre}) +
           Small::origin,
       Velocity<Small>({3 * Metre / Second,
                        2 * Metre / Second,
                        1 * Metre / Second})};
  EXPECT_EQ(small_frame_->GeometricAcceleration(t, point_dof),
            read_small_frame->GeometricAcceleration(t, point_dof));
}
TEST_F(BodySurfaceDynamicFrameTest, Serialization) {
  serialization::DynamicFrame message;
  big_frame_->WriteToMessage(&message);

  EXPECT_TRUE(message.HasExtension(
      serialization::BodySurfaceDynamicFrame::extension));
  auto const extension = message.GetExtension(
      serialization::BodySurfaceDynamicFrame::extension);
  EXPECT_TRUE(extension.has_centre());
  EXPECT_EQ(0, extension.centre());

  auto const read_big_frame =
      DynamicFrame<ICRFJ2000Equator, BigSmallFrame>::ReadFromMessage(
          ephemeris_.get(), message);
  EXPECT_THAT(read_big_frame, Not(IsNull()));

  Instant const t = t0_ + period_;
  DegreesOfFreedom<BigSmallFrame> const point_dof =
      {Displacement<BigSmallFrame>({10 * Metre, 20 * Metre, 30 * Metre}) +
           BigSmallFrame::origin,
       Velocity<BigSmallFrame>({3 * Metre / Second,
                                2 * Metre / Second,
                                1 * Metre / Second})};
  EXPECT_EQ(big_frame_->GeometricAcceleration(t, point_dof),
            read_big_frame->GeometricAcceleration(t, point_dof));
}
Rotation<Frenet<ThisFrame>, ThisFrame>
DynamicFrame<InertialFrame, ThisFrame>::FrenetFrame(
    Instant const& t,
    DegreesOfFreedom<ThisFrame> const& degrees_of_freedom) const {
  Velocity<ThisFrame> const& velocity = degrees_of_freedom.velocity();
  Vector<Acceleration, ThisFrame> const acceleration =
      GeometricAcceleration(t, degrees_of_freedom);
  Vector<Acceleration, ThisFrame> normal_acceleration = acceleration;
  velocity.template Orthogonalize<Acceleration>(&normal_acceleration);
  Vector<double, ThisFrame> tangent = Normalize(velocity);
  Vector<double, ThisFrame> normal = Normalize(normal_acceleration);
  Bivector<double, ThisFrame> binormal = Wedge(tangent, normal);
  // Maps |tangent| to {1, 0, 0}, |normal| to {0, 1, 0}, and |binormal| to
  // {0, 0, 1}.
  return Rotation<Frenet<ThisFrame>, ThisFrame>(
      R3x3Matrix(tangent.coordinates(),
                 normal.coordinates(),
                 binormal.coordinates()).Transpose());
}