Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: e0f13df18d39
Choose a base ref
...
head repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 84bea4e79ad8
Choose a head ref

Commits on Oct 12, 2021

  1. Start to write the body.

    pleroy committed Oct 12, 2021
    Copy the full SHA
    51ad272 View commit details
  2. Copy the full SHA
    6218324 View commit details
  3. Skeleton.

    pleroy committed Oct 12, 2021
    Copy the full SHA
    335cf14 View commit details

Commits on Oct 13, 2021

  1. Copy the full SHA
    415ed2e View commit details
  2. Test skeleton.

    pleroy committed Oct 13, 2021
    Copy the full SHA
    3280aab View commit details
  3. Copy the full SHA
    f4cfeba View commit details

Commits on Oct 14, 2021

  1. Copy the full SHA
    bda2f72 View commit details

Commits on Oct 16, 2021

  1. Constructing a trajectory.

    pleroy committed Oct 16, 2021
    Copy the full SHA
    044095b View commit details
  2. Construction works.

    pleroy committed Oct 16, 2021
    Copy the full SHA
    f6f9006 View commit details
  3. All tests passing.

    pleroy committed Oct 16, 2021
    Copy the full SHA
    57c15c4 View commit details
  4. Iteration.

    pleroy committed Oct 16, 2021
    Copy the full SHA
    b297ebd View commit details
  5. Empty and size.

    pleroy committed Oct 16, 2021
    Copy the full SHA
    a51e832 View commit details
  6. Find.

    pleroy committed Oct 16, 2021
    Copy the full SHA
    f7a3fa6 View commit details
  7. Copy the full SHA
    e1daea8 View commit details
  8. Lower and upper bound.

    pleroy committed Oct 16, 2021
    Copy the full SHA
    7f58076 View commit details
  9. Evaluate.

    pleroy committed Oct 16, 2021
    Copy the full SHA
    c24c438 View commit details
  10. Merge.

    pleroy committed Oct 16, 2021
    Copy the full SHA
    661ee74 View commit details
  11. Copy the full SHA
    7490701 View commit details
  12. Comment.

    pleroy committed Oct 16, 2021
    Copy the full SHA
    7cd2660 View commit details
  13. Formatting.

    pleroy committed Oct 16, 2021
    Copy the full SHA
    4823cbe View commit details

Commits on Oct 17, 2021

  1. Fix build problems.

    pleroy committed Oct 17, 2021
    Copy the full SHA
    0463a7b View commit details
  2. Merge pull request #3154 from pleroy/Trajectory

    DiscreteTrajectory2, first part of the implementation and tests
    pleroy authored Oct 17, 2021
    Copy the full SHA
    84bea4e View commit details
38 changes: 29 additions & 9 deletions physics/discrete_trajectory2.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#pragma once
#pragma once

#include <iterator>
#include <list>
@@ -11,6 +11,7 @@
#include "geometry/named_quantities.hpp"
#include "physics/degrees_of_freedom.hpp"
#include "physics/discrete_trajectory_iterator.hpp"
#include "physics/discrete_trajectory_segment.hpp"
#include "physics/discrete_trajectory_segment_iterator.hpp"
#include "physics/discrete_trajectory_segment_range.hpp"
#include "physics/discrete_trajectory_types.hpp"
@@ -24,7 +25,7 @@ FORWARD_DECLARE_FROM(discrete_trajectory_segment,
TEMPLATE(typename Frame) class,
DiscreteTrajectorySegment);

namespace internal_discrete_trajectory {
namespace internal_discrete_trajectory2 {

using base::not_null;
using geometry::Instant;
@@ -48,7 +49,7 @@ class DiscreteTrajectory2 : public Trajectory<Frame> {
using ReverseSegmentRange =
DiscreteTrajectorySegmentRange<ReverseSegmentIterator>;

DiscreteTrajectory2() = default;
DiscreteTrajectory2();

// Moveable.
DiscreteTrajectory2(DiscreteTrajectory2&&) = default;
@@ -62,6 +63,9 @@ class DiscreteTrajectory2 : public Trajectory<Frame> {
reverse_iterator rbegin() const;
reverse_iterator rend() const;

bool empty() const;
std::int64_t size() const;

iterator find(Instant const& t) const;

iterator lower_bound(Instant const& t) const;
@@ -89,10 +93,10 @@ class DiscreteTrajectory2 : public Trajectory<Frame> {
Instant t_min() const override;
Instant t_max() const override;

Position<Frame> EvaluatePosition(Instant const& time) const override;
Velocity<Frame> EvaluateVelocity(Instant const& time) const override;
Position<Frame> EvaluatePosition(Instant const& t) const override;
Velocity<Frame> EvaluateVelocity(Instant const& t) const override;
DegreesOfFreedom<Frame> EvaluateDegreesOfFreedom(
Instant const& time) const override;
Instant const& t) const override;

void WriteToMessage(
not_null<serialization::DiscreteTrajectory*> message,
@@ -113,12 +117,28 @@ class DiscreteTrajectory2 : public Trajectory<Frame> {
private:
using Segments = internal_discrete_trajectory_types::Segments<Frame>;

Segments segments_;
typename Segments::iterator FindSegment(Instant const& t);
typename Segments::const_iterator FindSegment(Instant const& t) const;

// We need a level of indirection here to make sure that the pointer to
// Segments in the DiscreteTrajectorySegmentIterator remain valid when the
// DiscreteTrajectory moves. This field is never null and never empty.
not_null<std::unique_ptr<Segments>> segments_;

// This list is never empty. For an empty trajectory, there is a sentinel
// with time -∞ denoting the single segment of the trajectory. As soon as a
// point is appended to the trajectory, the sentinel is removed and a bona
// fide entry replaces it. To access the segment for time t, use
// |--upper_bound(t)|.
absl::btree_map<Instant,
typename Segments::iterator> segment_by_left_endpoint_;
};

} // namespace internal_discrete_trajectory
} // namespace internal_discrete_trajectory2

using internal_discrete_trajectory::DiscreteTrajectory2;
using internal_discrete_trajectory2::DiscreteTrajectory2;

} // namespace physics
} // namespace principia

#include "physics/discrete_trajectory2_body.hpp"
270 changes: 270 additions & 0 deletions physics/discrete_trajectory2_body.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
#pragma once

#include "physics/discrete_trajectory2.hpp"

#include <vector>

#include "astronomy/epoch.hpp"

namespace principia {
namespace physics {
namespace internal_discrete_trajectory2 {

using astronomy::InfinitePast;
using base::make_not_null_unique;

template<typename Frame>
DiscreteTrajectory2<Frame>::DiscreteTrajectory2()
: segments_(make_not_null_unique<Segments>(1)) {
auto const sit = segments_->begin();
*sit =
DiscreteTrajectorySegment<Frame>(SegmentIterator(segments_.get(), sit));
segment_by_left_endpoint_.emplace(InfinitePast, sit);
}

template<typename Frame>
typename DiscreteTrajectory2<Frame>::iterator
DiscreteTrajectory2<Frame>::begin() const {
return segments_->front().begin();
}

template<typename Frame>
typename DiscreteTrajectory2<Frame>::iterator
DiscreteTrajectory2<Frame>::end() const {
return segments_->back().end();
}

template<typename Frame>
typename DiscreteTrajectory2<Frame>::reverse_iterator
DiscreteTrajectory2<Frame>::rbegin() const {
return reverse_iterator(end());
}

template<typename Frame>
typename DiscreteTrajectory2<Frame>::reverse_iterator
DiscreteTrajectory2<Frame>::rend() const {
return reverse_iterator(begin());
}

template<typename Frame>
bool DiscreteTrajectory2<Frame>::empty() const {
for (auto const& segment : *segments_) {
if (!segment.empty()) {
return false;
}
}
return true;
}

template<typename Frame>
std::int64_t DiscreteTrajectory2<Frame>::size() const {
std::int64_t size = 1;
for (auto const& segment : *segments_) {
size += segment.size();
}
size -= segments_->size(); // The junction points.
return size;
}

template<typename Frame>
typename DiscreteTrajectory2<Frame>::iterator
DiscreteTrajectory2<Frame>::find(Instant const& t) const {
auto const sit = FindSegment(t);
auto const it = sit->find(t);
if (it == sit->end()) {
return end();
} else {
return it;
}
}

template<typename Frame>
typename DiscreteTrajectory2<Frame>::iterator
DiscreteTrajectory2<Frame>::lower_bound(Instant const& t) const {
auto const sit = FindSegment(t);
auto const it = sit->lower_bound(t);
if (it == sit->end()) {
return end();
} else {
return it;
}
}

template<typename Frame>
typename DiscreteTrajectory2<Frame>::iterator
DiscreteTrajectory2<Frame>::upper_bound(Instant const& t) const {
auto const sit = FindSegment(t);
auto const it = sit->upper_bound(t);
if (it == sit->end()) {
return end();
} else {
return it;
}
}

template<typename Frame>
typename DiscreteTrajectory2<Frame>::SegmentRange
DiscreteTrajectory2<Frame>::segments() const {
return SegmentRange(SegmentIterator(
segments_.get(), segments_->begin()),
SegmentIterator(
segments_.get(), segments_->end()));
}

template<typename Frame>
typename DiscreteTrajectory2<Frame>::ReverseSegmentRange
DiscreteTrajectory2<Frame>::rsegments() const {
// TODO(phl): Implement.
}

template<typename Frame>
typename DiscreteTrajectory2<Frame>::SegmentIterator
DiscreteTrajectory2<Frame>::NewSegment() {
auto& last_segment = segments_->back();
CHECK(!last_segment.empty())
<< "Cannot create a new segment after an empty one";

auto const& new_segment = segments_->emplace_back();
auto const new_segment_sit = --segments_->end();
*new_segment_sit = DiscreteTrajectorySegment<Frame>(
SegmentIterator(segments_.get(), new_segment_sit));

auto const& [last_time, last_degrees_of_freedom] = *last_segment.rbegin();
new_segment_sit->Append(last_time, last_degrees_of_freedom);
segment_by_left_endpoint_.emplace_hint(
segment_by_left_endpoint_.end(), last_time, new_segment_sit);

return SegmentIterator(segments_.get(), new_segment_sit);
}

template<typename Frame>
typename DiscreteTrajectory2<Frame>::DiscreteTrajectory2
DiscreteTrajectory2<Frame>::DetachSegments(iterator begin) {
// TODO(phl): Implement.
}

template<typename Frame>
typename DiscreteTrajectory2<Frame>::SegmentIterator
DiscreteTrajectory2<Frame>::AttachSegments(
DiscreteTrajectory2&& trajectory) {
// TODO(phl): Implement.
}

template<typename Frame>
void DiscreteTrajectory2<Frame>::DeleteSegments(iterator begin) {
// TODO(phl): Implement.
}

template<typename Frame>
void DiscreteTrajectory2<Frame>::ForgetAfter(Instant const& t) {
// TODO(phl): Drop segments as needed.
return FindSegment(t)->ForgetAfter(t);
}

template<typename Frame>
void DiscreteTrajectory2<Frame>::ForgetAfter(iterator begin) {
// TODO(phl): Implement.
}

template<typename Frame>
void DiscreteTrajectory2<Frame>::ForgetBefore(Instant const& t) {
// TODO(phl): Drop segments as needed.
return FindSegment(t)->ForgetBefore(t);
}

template<typename Frame>
void DiscreteTrajectory2<Frame>::ForgetBefore(iterator end) {
// TODO(phl): Implement.
}

template<typename Frame>
void DiscreteTrajectory2<Frame>::Append(
Instant const& t,
DegreesOfFreedom<Frame> const& degrees_of_freedom) {
auto sit = FindSegment(t);
// If this is the first point appended to this trajectory, insert a proper
// left endpoint and remove the sentinel.
if (empty()) {
segment_by_left_endpoint_.emplace_hint(
segment_by_left_endpoint_.end(), t, sit);
segment_by_left_endpoint_.erase(segment_by_left_endpoint_.begin());
}
sit->Append(t, degrees_of_freedom);
}

template<typename Frame>
Instant DiscreteTrajectory2<Frame>::t_min() const {
return segments_->front().t_min();
}

template<typename Frame>
Instant DiscreteTrajectory2<Frame>::t_max() const {
return segments_->back().t_max();
}

template<typename Frame>
Position<Frame> DiscreteTrajectory2<Frame>::EvaluatePosition(
Instant const& t) const {
return FindSegment(t)->EvaluatePosition(t);
}

template<typename Frame>
Velocity<Frame> DiscreteTrajectory2<Frame>::EvaluateVelocity(
Instant const& t) const {
return FindSegment(t)->EvaluateVelocity(t);
}

template<typename Frame>
DegreesOfFreedom<Frame> DiscreteTrajectory2<Frame>::EvaluateDegreesOfFreedom(
Instant const& t) const {
return FindSegment(t)->EvaluateDegreesOfFreedom(t);
}

template<typename Frame>
void DiscreteTrajectory2<Frame>::WriteToMessage(
not_null<serialization::DiscreteTrajectory*> message,
std::vector<SegmentIterator> const& tracked,
std::vector<iterator> const& exact) const {
// TODO(phl): Implement.
}

template<typename Frame>
void DiscreteTrajectory2<Frame>::WriteToMessage(
not_null<serialization::DiscreteTrajectory*> message,
iterator begin,
iterator end,
std::vector<SegmentIterator> const& tracked,
std::vector<iterator> const& exact) const {
// TODO(phl): Implement.
}

template<typename Frame>
template<typename F, typename>
not_null<std::unique_ptr<DiscreteTrajectory2<Frame>>>
DiscreteTrajectory2<Frame>::ReadFromMessage(
serialization::DiscreteTrajectory const& message,
std::vector<DiscreteTrajectory2**> const& tracked) {
// TODO(phl): Implement.
}

template<typename Frame>
typename DiscreteTrajectory2<Frame>::Segments::iterator
DiscreteTrajectory2<Frame>::FindSegment(
Instant const& t) {
auto it = segment_by_left_endpoint_.upper_bound(t);
CHECK(it != segment_by_left_endpoint_.begin()) << "No segment covering " << t;
return (--it)->second;
}

template<typename Frame>
typename DiscreteTrajectory2<Frame>::Segments::const_iterator
DiscreteTrajectory2<Frame>::FindSegment(
Instant const& t) const {
auto it = segment_by_left_endpoint_.upper_bound(t);
CHECK(it != segment_by_left_endpoint_.begin()) << "No segment covering " << t;
return (--it)->second;
}

} // namespace internal_discrete_trajectory2
} // namespace physics
} // namespace principia
303 changes: 303 additions & 0 deletions physics/discrete_trajectory2_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,303 @@
#include "physics/discrete_trajectory2.hpp"

#include <vector>

#include "geometry/frame.hpp"
#include "geometry/named_quantities.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "quantities/si.hpp"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/componentwise.hpp"
#include "testing_utilities/discrete_trajectory_factories.hpp"

namespace principia {
namespace physics {

using geometry::Displacement;
using geometry::Frame;
using geometry::Instant;
using geometry::Velocity;
using quantities::si::Metre;
using quantities::si::Second;
using testing_utilities::AlmostEquals;
using testing_utilities::Componentwise;
using testing_utilities::NewLinearTrajectoryTimeline;
using ::testing::ElementsAre;

class DiscreteTrajectory2Test : public ::testing::Test {
protected:
using World = Frame<enum class WorldTag>;

// Constructs a trajectory with three 5-second segments.
DiscreteTrajectory2<World> MakeTrajectory() {
DiscreteTrajectory2<World> trajectory;
std::optional<DegreesOfFreedom<World>> last_degrees_of_freedom;

Velocity<World> const v1({1 * Metre / Second,
0 * Metre / Second,
0 * Metre / Second});
for (auto const& [t, degrees_of_freedom] :
NewLinearTrajectoryTimeline(v1,
/*Δt=*/1 * Second,
/*t1=*/t0_,
/*t2=*/t0_ + 5 * Second)) {
last_degrees_of_freedom = degrees_of_freedom;
trajectory.Append(t, degrees_of_freedom);
}

trajectory.NewSegment();
Velocity<World> const v2({0 * Metre / Second,
1 * Metre / Second,
0 * Metre / Second});
for (auto const& [t, degrees_of_freedom] :
NewLinearTrajectoryTimeline(DegreesOfFreedom<World>(
last_degrees_of_freedom->position(),
v2),
/*Δt=*/1 * Second,
/*t1=*/t0_ + 5 * Second,
/*t2=*/t0_ + 10 * Second)) {
last_degrees_of_freedom = degrees_of_freedom;
trajectory.Append(t, degrees_of_freedom);
}

trajectory.NewSegment();
Velocity<World> const v3({0 * Metre / Second,
0 * Metre / Second,
1 * Metre / Second});
for (auto const& [t, degrees_of_freedom] :
NewLinearTrajectoryTimeline(DegreesOfFreedom<World>(
last_degrees_of_freedom->position(),
v3),
/*Δt=*/1 * Second,
/*t1=*/t0_ + 10 * Second,
/*t2=*/t0_ + 15 * Second)) {
trajectory.Append(t, degrees_of_freedom);
}

return trajectory;
}

Instant const t0_;
};

TEST_F(DiscreteTrajectory2Test, Make) {
auto const trajectory = MakeTrajectory();
}

TEST_F(DiscreteTrajectory2Test, IterateForward) {
auto const trajectory = MakeTrajectory();
std::vector<Instant> times;
for (auto const& [t, _] : trajectory) {
times.push_back(t);
}
EXPECT_THAT(times,
ElementsAre(t0_,
t0_ + 1 * Second,
t0_ + 2 * Second,
t0_ + 3 * Second,
t0_ + 4 * Second,
t0_ + 5 * Second,
t0_ + 6 * Second,
t0_ + 7 * Second,
t0_ + 8 * Second,
t0_ + 9 * Second,
t0_ + 10 * Second,
t0_ + 11 * Second,
t0_ + 12 * Second,
t0_ + 13 * Second,
t0_ + 14 * Second));
}

TEST_F(DiscreteTrajectory2Test, IterateBackward) {
auto const trajectory = MakeTrajectory();
std::vector<Instant> times;
for (auto it = trajectory.rbegin(); it != trajectory.rend(); ++it) {
times.push_back(it->first);
}
EXPECT_THAT(times,
ElementsAre(t0_ + 14 * Second,
t0_ + 13 * Second,
t0_ + 12 * Second,
t0_ + 11 * Second,
t0_ + 10 * Second,
t0_ + 9 * Second,
t0_ + 8 * Second,
t0_ + 7 * Second,
t0_ + 6 * Second,
t0_ + 5 * Second,
t0_ + 4 * Second,
t0_ + 3 * Second,
t0_ + 2 * Second,
t0_ + 1 * Second,
t0_));
}

TEST_F(DiscreteTrajectory2Test, Empty) {
DiscreteTrajectory2<World> trajectory;
EXPECT_TRUE(trajectory.empty());
trajectory = MakeTrajectory();
EXPECT_FALSE(trajectory.empty());
}

TEST_F(DiscreteTrajectory2Test, Size) {
DiscreteTrajectory2<World> trajectory;
EXPECT_EQ(0, trajectory.size());
trajectory = MakeTrajectory();
EXPECT_EQ(15, trajectory.size());
}

TEST_F(DiscreteTrajectory2Test, Find) {
auto const trajectory = MakeTrajectory();
{
auto const it = trajectory.find(t0_ + 3 * Second);
auto const& [t, degrees_of_freedom] = *it;
EXPECT_EQ(t, t0_ + 3 * Second);
EXPECT_EQ(degrees_of_freedom.position(),
World::origin + Displacement<World>({3 * Metre,
0 * Metre,
0 * Metre}));
}
{
auto const it = trajectory.find(t0_ + 13 * Second);
auto const& [t, degrees_of_freedom] = *it;
EXPECT_EQ(t, t0_ + 13 * Second);
EXPECT_EQ(degrees_of_freedom.position(),
World::origin + Displacement<World>({4 * Metre,
4 * Metre,
3 * Metre}));
}
{
auto const it = trajectory.find(t0_ + 3.14 * Second);
EXPECT_TRUE(it == trajectory.end());
}
}

TEST_F(DiscreteTrajectory2Test, LowerBound) {
auto const trajectory = MakeTrajectory();
{
auto const it = trajectory.lower_bound(t0_ + 3.9 * Second);
auto const& [t, degrees_of_freedom] = *it;
EXPECT_EQ(t, t0_ + 4 * Second);
EXPECT_EQ(degrees_of_freedom.position(),
World::origin + Displacement<World>({4 * Metre,
0 * Metre,
0 * Metre}));
}
{
auto const it = trajectory.lower_bound(t0_ + 4 * Second);
auto const& [t, degrees_of_freedom] = *it;
EXPECT_EQ(t, t0_ + 4 * Second);
EXPECT_EQ(degrees_of_freedom.position(),
World::origin + Displacement<World>({4 * Metre,
0 * Metre,
0 * Metre}));
}
{
auto const it = trajectory.lower_bound(t0_ + 4.1 * Second);
auto const& [t, degrees_of_freedom] = *it;
EXPECT_EQ(t, t0_ + 5 * Second);
EXPECT_EQ(degrees_of_freedom.position(),
World::origin + Displacement<World>({4 * Metre,
0 * Metre,
0 * Metre}));
}
{
auto const it = trajectory.lower_bound(t0_ + 13 * Second);
auto const& [t, degrees_of_freedom] = *it;
EXPECT_EQ(t, t0_ + 13 * Second);
EXPECT_EQ(degrees_of_freedom.position(),
World::origin + Displacement<World>({4 * Metre,
4 * Metre,
3 * Metre}));
}
{
auto const it = trajectory.lower_bound(t0_ + 14.2 * Second);
EXPECT_TRUE(it == trajectory.end());
}
}

TEST_F(DiscreteTrajectory2Test, UpperBound) {
auto const trajectory = MakeTrajectory();
{
auto const it = trajectory.upper_bound(t0_ + 3.9 * Second);
auto const& [t, degrees_of_freedom] = *it;
EXPECT_EQ(t, t0_ + 4 * Second);
EXPECT_EQ(degrees_of_freedom.position(),
World::origin + Displacement<World>({4 * Metre,
0 * Metre,
0 * Metre}));
}
{
auto const it = trajectory.upper_bound(t0_ + 4 * Second);
auto const& [t, degrees_of_freedom] = *it;
EXPECT_EQ(t, t0_ + 5 * Second);
EXPECT_EQ(degrees_of_freedom.position(),
World::origin + Displacement<World>({4 * Metre,
0 * Metre,
0 * Metre}));
}
{
auto const it = trajectory.upper_bound(t0_ + 4.1 * Second);
auto const& [t, degrees_of_freedom] = *it;
EXPECT_EQ(t, t0_ + 5 * Second);
EXPECT_EQ(degrees_of_freedom.position(),
World::origin + Displacement<World>({4 * Metre,
0 * Metre,
0 * Metre}));
}
{
auto const it = trajectory.upper_bound(t0_ + 13 * Second);
auto const& [t, degrees_of_freedom] = *it;
EXPECT_EQ(t, t0_ + 14 * Second);
EXPECT_EQ(degrees_of_freedom.position(),
World::origin + Displacement<World>({4 * Metre,
4 * Metre,
4 * Metre}));
}
{
auto const it = trajectory.upper_bound(t0_ + 14.2 * Second);
EXPECT_TRUE(it == trajectory.end());
}
}

TEST_F(DiscreteTrajectory2Test, Segments) {
auto const trajectory = MakeTrajectory();
std::vector<Instant> begin;
std::vector<Instant> rbegin;
for (auto const& sit : trajectory.segments()) {
begin.push_back(sit.begin()->first);
rbegin.push_back(sit.rbegin()->first);
}
EXPECT_THAT(
begin,
ElementsAre(t0_, t0_ + 4 * Second, t0_ + 9 * Second));
EXPECT_THAT(
rbegin,
ElementsAre(t0_ + 4 * Second, t0_ + 9 * Second, t0_ + 14 * Second));
}

TEST_F(DiscreteTrajectory2Test, TMinTMaxEvaluate) {
auto const trajectory = MakeTrajectory();
EXPECT_EQ(t0_, trajectory.t_min());
EXPECT_EQ(t0_ + 14 * Second, trajectory.t_max());
EXPECT_THAT(trajectory.EvaluateDegreesOfFreedom(t0_ + 3.14 * Second),
Componentwise(AlmostEquals(
World::origin + Displacement<World>({3.14 * Metre,
0 * Metre,
0 * Metre}), 0),
AlmostEquals(Velocity<World>({1 * Metre / Second,
0 * Metre / Second,
0 * Metre / Second}), 0)));
EXPECT_THAT(trajectory.EvaluateDegreesOfFreedom(t0_ + 6.78 * Second),
Componentwise(AlmostEquals(
World::origin + Displacement<World>({4 * Metre,
1.78 * Metre,
0 * Metre}), 1),
AlmostEquals(Velocity<World>({0 * Metre / Second,
1 * Metre / Second,
0 * Metre / Second}), 0)));
}

} // namespace physics
} // namespace principia
9 changes: 7 additions & 2 deletions physics/discrete_trajectory_segment.hpp
Original file line number Diff line number Diff line change
@@ -24,6 +24,10 @@ FORWARD_DECLARE_FROM(discrete_trajectory_factories,

namespace physics {

FORWARD_DECLARE_FROM(discrete_trajectory2,
TEMPLATE(typename Frame) class,
DiscreteTrajectory2);

class DiscreteTrajectoryIteratorTest;
class DiscreteTrajectorySegmentIteratorTest;
class DiscreteTrajectorySegmentTest;
@@ -134,8 +138,9 @@ class DiscreteTrajectorySegment : public Trajectory<Frame> {
std::int64_t number_of_dense_points_ = 0;

template<typename F>
friend class internal_discrete_trajectory_iterator::
DiscreteTrajectoryIterator;
friend class physics::DiscreteTrajectory2;
template<typename F>
friend class physics::DiscreteTrajectoryIterator;

// For testing.
friend class physics::DiscreteTrajectoryIteratorTest;
5 changes: 5 additions & 0 deletions physics/discrete_trajectory_segment_iterator.hpp
Original file line number Diff line number Diff line change
@@ -16,6 +16,9 @@ FORWARD_DECLARE_FROM(discrete_trajectory_factories,

namespace physics {

FORWARD_DECLARE_FROM(discrete_trajectory2,
TEMPLATE(typename Frame) class,
DiscreteTrajectory2);
FORWARD_DECLARE_FROM(discrete_trajectory_iterator,
TEMPLATE(typename Frame) class,
DiscreteTrajectoryIterator);
@@ -67,6 +70,8 @@ class DiscreteTrajectorySegmentIterator {
Segments const* segments_ = nullptr;
typename Segments::const_iterator iterator_;

template<typename F>
friend class physics::DiscreteTrajectory2;
template<typename F>
friend class physics::DiscreteTrajectoryIterator;

30 changes: 0 additions & 30 deletions physics/mock_discrete_trajectory_segment.hpp

This file was deleted.

3 changes: 2 additions & 1 deletion physics/physics.vcxproj
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@
<ClInclude Include="checkpointer.hpp" />
<ClInclude Include="checkpointer_body.hpp" />
<ClInclude Include="discrete_trajectory2.hpp" />
<ClInclude Include="discrete_trajectory2_body.hpp" />
<ClInclude Include="discrete_trajectory_iterator.hpp" />
<ClInclude Include="discrete_trajectory_iterator_body.hpp" />
<ClInclude Include="discrete_trajectory_segment.hpp" />
@@ -55,7 +56,6 @@
<ClInclude Include="euler_solver_body.hpp" />
<ClInclude Include="geopotential.hpp" />
<ClInclude Include="geopotential_body.hpp" />
<ClInclude Include="mock_discrete_trajectory_segment.hpp" />
<ClInclude Include="protector.hpp" />
<ClInclude Include="hierarchical_system.hpp" />
<ClInclude Include="hierarchical_system_body.hpp" />
@@ -103,6 +103,7 @@
<ClCompile Include="body_surface_frame_field_test.cpp" />
<ClCompile Include="body_test.cpp" />
<ClCompile Include="checkpointer_test.cpp" />
<ClCompile Include="discrete_trajectory2_test.cpp" />
<ClCompile Include="discrete_trajectory_iterator_test.cpp" />
<ClCompile Include="discrete_trajectory_segment_iterator_test.cpp" />
<ClCompile Include="discrete_trajectory_segment_range_test.cpp" />
9 changes: 6 additions & 3 deletions physics/physics.vcxproj.filters
Original file line number Diff line number Diff line change
@@ -218,12 +218,12 @@
<ClInclude Include="discrete_trajectory_iterator_body.hpp">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="mock_discrete_trajectory_segment.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="discrete_trajectory_segment_body.hpp">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="discrete_trajectory2_body.hpp">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="degrees_of_freedom_test.cpp">
@@ -334,5 +334,8 @@
<ClCompile Include="discrete_trajectory_segment_test.cpp">
<Filter>Test Files</Filter>
</ClCompile>
<ClCompile Include="discrete_trajectory2_test.cpp">
<Filter>Test Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
12 changes: 10 additions & 2 deletions testing_utilities/discrete_trajectory_factories.hpp
Original file line number Diff line number Diff line change
@@ -36,15 +36,23 @@ class DiscreteTrajectoryFactoriesFriend {
};

// A linear trajectory with constant velocity, going through
// |degrees_of_freedom.position()| at t = 0. The first point is at time |t1|,
// |degrees_of_freedom.position()| at t = t0. The first point is at time |t1|,
// the last point at a time < |t2|.
template<typename Frame>
Timeline<Frame>
NewLinearTrajectoryTimeline(DegreesOfFreedom<Frame> const& degrees_of_freedom,
Time const& Δt,
Instant const& t0,
Instant const& t1,
Instant const& t2);
// Same as above, going through the origin at t = 0.
// Same as above, going through |degrees_of_freedom.position()| at t = t1.
template<typename Frame>
Timeline<Frame>
NewLinearTrajectoryTimeline(DegreesOfFreedom<Frame> const& degrees_of_freedom,
Time const& Δt,
Instant const& t1,
Instant const& t2);
// Same as above, going through the origin at t = t1.
template<typename Frame>
Timeline<Frame>
NewLinearTrajectoryTimeline(Velocity<Frame> const& v,
13 changes: 11 additions & 2 deletions testing_utilities/discrete_trajectory_factories_body.hpp
Original file line number Diff line number Diff line change
@@ -36,9 +36,9 @@ template<typename Frame>
Timeline<Frame>
NewLinearTrajectoryTimeline(DegreesOfFreedom<Frame> const& degrees_of_freedom,
Time const& Δt,
Instant const& t0,
Instant const& t1,
Instant const& t2) {
static Instant const t0;
Timeline<Frame> timeline;
for (auto t = t1; t < t2; t += Δt) {
auto const velocity = degrees_of_freedom.velocity();
@@ -48,14 +48,23 @@ NewLinearTrajectoryTimeline(DegreesOfFreedom<Frame> const& degrees_of_freedom,
return timeline;
}

template<typename Frame>
Timeline<Frame>
NewLinearTrajectoryTimeline(DegreesOfFreedom<Frame> const& degrees_of_freedom,
Time const& Δt,
Instant const& t1,
Instant const& t2) {
return NewLinearTrajectoryTimeline(degrees_of_freedom, Δt, /*t0=*/t1, t1, t2);
}

template<typename Frame>
Timeline<Frame>
NewLinearTrajectoryTimeline(Velocity<Frame> const& v,
Time const& Δt,
Instant const& t1,
Instant const& t2) {
return NewLinearTrajectoryTimeline(
DegreesOfFreedom<Frame>(Frame::origin, v), Δt, t1, t2);
DegreesOfFreedom<Frame>(Frame::origin, v), Δt, /*t0=*/t1, t1, t2);
}

template<typename Frame>
1 change: 1 addition & 0 deletions testing_utilities/discrete_trajectory_factories_test.cpp
Original file line number Diff line number Diff line change
@@ -48,6 +48,7 @@ TEST_F(DiscreteTrajectoryFactoriesTest, NewLinearTrajectoryTimeline) {
Velocity<World>(
{6 * Metre / Second, 5 * Metre / Second, 4 * Metre / Second})),
/*Δt=*/0.1 * Second,
/*t0=*/Instant(),
/*t1=*/Instant() + 4 * Second,
/*t2=*/Instant() + 42 * Second);