diff --git a/physics/discrete_trajectory_iterator_test.cpp b/physics/discrete_trajectory_iterator_test.cpp index 22586a9cc3..7b818f95ed 100644 --- a/physics/discrete_trajectory_iterator_test.cpp +++ b/physics/discrete_trajectory_iterator_test.cpp @@ -12,7 +12,6 @@ #include "physics/discrete_trajectory_segment.hpp" #include "physics/discrete_trajectory_segment_iterator.hpp" #include "physics/discrete_trajectory_types.hpp" -#include "physics/mock_discrete_trajectory_segment.hpp" #include "quantities/quantities.hpp" #include "quantities/si.hpp" @@ -20,6 +19,8 @@ namespace principia { namespace physics { using base::check_not_null; +using base::make_not_null_unique; +using base::not_null; using geometry::Frame; using geometry::Instant; using physics::DegreesOfFreedom; @@ -27,120 +28,71 @@ using quantities::Time; using quantities::si::Second; using ::testing::Return; -namespace { - -// A trajectory that holds a real timeline, where we mock multiple methods to -// return data from that timeline. -template -class FakeDiscreteTrajectorySegment - : public MockDiscreteTrajectorySegment { - public: - FakeDiscreteTrajectorySegment() = default; - - internal_discrete_trajectory_types::Timeline timeline; -}; - -} // namespace - class DiscreteTrajectoryIteratorTest : public ::testing::Test { protected: using World = Frame; - using Segments = internal_discrete_trajectory_types::Segments; - using Timeline = internal_discrete_trajectory_types::Timeline; - - DiscreteTrajectoryIteratorTest() { - // Set up a fake trajectory with 3 segments. After construction, the mocks - // are owned by |segments_|. - auto owned_mock1 = std::make_unique>(); - auto owned_mock2 = std::make_unique>(); - auto owned_mock3 = std::make_unique>(); - auto const& mock1 = *owned_mock1; - auto const& mock2 = *owned_mock2; - auto const& mock3 = *owned_mock3; - - segments_.push_back(std::move(owned_mock1)); - auto const it1 = --segments_.end(); - segments_.push_back(std::move(owned_mock2)); - auto const it2 = --segments_.end(); - segments_.push_back(std::move(owned_mock3)); - auto const it3 = --segments_.end(); - - FillSegment(it1, - Timeline{MakeTimelineValueType(2 * Second), - MakeTimelineValueType(3 * Second), - MakeTimelineValueType(5 * Second), - MakeTimelineValueType(7 * Second), - MakeTimelineValueType(11 * Second)}); - FillSegment(it2, Timeline{MakeTimelineValueType(13 * Second)}); - FillSegment(it3, - Timeline{MakeTimelineValueType(13 * Second), // Duplicated. - MakeTimelineValueType(17 * Second), - MakeTimelineValueType(19 * Second), - MakeTimelineValueType(23 * Second)}); - - // This must happen *after* the segments have been set up. - EXPECT_CALL(mock1, timeline_begin()) - .WillRepeatedly(Return(timeline_begin(it1))); - EXPECT_CALL(mock1, timeline_end()) - .WillRepeatedly(Return(timeline_end(it1))); - EXPECT_CALL(mock2, timeline_begin()) - .WillRepeatedly(Return(timeline_begin(it2))); - EXPECT_CALL(mock2, timeline_end()) - .WillRepeatedly(Return(timeline_end(it2))); - EXPECT_CALL(mock3, timeline_begin()) - .WillRepeatedly(Return(timeline_begin(it3))); - EXPECT_CALL(mock3, timeline_end()) - .WillRepeatedly(Return(timeline_end(it3))); - } - FakeDiscreteTrajectorySegment* DownCast( - std::unique_ptr> const& segment) { - return dynamic_cast*>(segment.get()); - } - - void FillSegment(Segments::iterator const it, Timeline const& timeline) { - auto* const segment = DownCast(*it); - segment->timeline = timeline; + DiscreteTrajectoryIteratorTest() + : segments_(MakeSegments(3)) { + auto it = segments_->begin(); + { + auto& segment1 = *it; + segment1.Append(t0_ + 2 * Second, unmoving_origin_); + segment1.Append(t0_ + 3 * Second, unmoving_origin_); + segment1.Append(t0_ + 5 * Second, unmoving_origin_); + segment1.Append(t0_ + 7 * Second, unmoving_origin_); + segment1.Append(t0_ + 11 * Second, unmoving_origin_); + } + + ++it; + { + auto& segment2 = *it; + segment2.Append(t0_ + 13 * Second, unmoving_origin_); + } + + ++it; + { + auto& segment3 = *it; + segment3.Append(t0_ + 13 * Second, unmoving_origin_); + segment3.Append(t0_ + 17 * Second, unmoving_origin_); + segment3.Append(t0_ + 19 * Second, unmoving_origin_); + segment3.Append(t0_ + 23 * Second, unmoving_origin_); + } } DiscreteTrajectoryIterator MakeBegin( Segments::const_iterator const it) { return DiscreteTrajectoryIterator( - DiscreteTrajectorySegmentIterator( - check_not_null(&segments_), it), - timeline_begin(it)); + DiscreteTrajectorySegmentIterator(segments_.get(), it), + it->timeline_begin()); } DiscreteTrajectoryIterator MakeEnd(Segments::const_iterator it) { return DiscreteTrajectoryIterator( - DiscreteTrajectorySegmentIterator(check_not_null(&segments_), - ++it), + DiscreteTrajectorySegmentIterator(segments_.get(), ++it), std::nullopt); } - Timeline::value_type MakeTimelineValueType(Time const& t) { - static const DegreesOfFreedom unmoving_origin(World::origin, - World::unmoving); - return {t0_ + t, unmoving_origin}; - } - - internal_discrete_trajectory_types::Timeline::const_iterator - timeline_begin(Segments::const_iterator const it) { - return DownCast(*it)->timeline.begin(); - } - - internal_discrete_trajectory_types::Timeline::const_iterator - timeline_end(Segments::const_iterator const it) { - return DownCast(*it)->timeline.end(); + // Constructs a list of |n| segments which are properly initialized. + // TODO(phl): Move to a central place. + static not_null> MakeSegments(const int n) { + auto segments = make_not_null_unique(n); + for (auto it = segments->begin(); it != segments->end(); ++it) { + *it = DiscreteTrajectorySegment( + DiscreteTrajectorySegmentIterator(segments.get(), it)); + } + return segments; } - Segments segments_; + not_null> segments_; Instant const t0_; + DegreesOfFreedom const unmoving_origin_{World::origin, + World::unmoving}; }; TEST_F(DiscreteTrajectoryIteratorTest, ForwardOneSegment) { - auto segment = segments_.begin(); + auto segment = segments_->begin(); auto iterator = MakeBegin(segment); EXPECT_EQ(t0_ + 2 * Second, iterator->first); auto const current = ++iterator; @@ -152,7 +104,7 @@ TEST_F(DiscreteTrajectoryIteratorTest, ForwardOneSegment) { } TEST_F(DiscreteTrajectoryIteratorTest, BackwardOneSegment) { - auto segment = --segments_.end(); + auto segment = --segments_->end(); auto iterator = MakeEnd(segment); --iterator; EXPECT_EQ(t0_ + 23 * Second, (*iterator).first); @@ -165,7 +117,7 @@ TEST_F(DiscreteTrajectoryIteratorTest, BackwardOneSegment) { } TEST_F(DiscreteTrajectoryIteratorTest, ForwardAcrossSegments) { - auto segment = segments_.begin(); + auto segment = segments_->begin(); auto iterator = MakeBegin(segment); for (int i = 0; i < 4; ++i) { ++iterator; @@ -178,7 +130,7 @@ TEST_F(DiscreteTrajectoryIteratorTest, ForwardAcrossSegments) { } TEST_F(DiscreteTrajectoryIteratorTest, BackwardAcrossSegments) { - auto segment = --segments_.end(); + auto segment = --segments_->end(); auto iterator = MakeEnd(segment); for (int i = 0; i < 3; ++i) { --iterator; @@ -193,7 +145,7 @@ TEST_F(DiscreteTrajectoryIteratorTest, BackwardAcrossSegments) { TEST_F(DiscreteTrajectoryIteratorTest, Equality) { // Construct two iterators that denote the time 13 * Second but in different // segments. - auto it1 = MakeEnd(--segments_.end()); + auto it1 = MakeEnd(--segments_->end()); for (int i = 0; i < 3; ++i) { --it1; } @@ -201,7 +153,7 @@ TEST_F(DiscreteTrajectoryIteratorTest, Equality) { --it1; EXPECT_EQ(t0_ + 13 * Second, (*it1).first); - auto it2 = MakeBegin(segments_.begin()); + auto it2 = MakeBegin(segments_->begin()); for (int i = 0; i < 4; ++i) { ++it2; } @@ -210,9 +162,9 @@ TEST_F(DiscreteTrajectoryIteratorTest, Equality) { EXPECT_EQ(t0_ + 13 * Second, it2->first); EXPECT_EQ(it1, it2); - EXPECT_NE(it1, MakeBegin(segments_.begin())); - EXPECT_NE(it2, MakeEnd(--segments_.end())); - EXPECT_NE(MakeBegin(segments_.begin()), MakeEnd(--segments_.end())); + EXPECT_NE(it1, MakeBegin(segments_->begin())); + EXPECT_NE(it2, MakeEnd(--segments_->end())); + EXPECT_NE(MakeBegin(segments_->begin()), MakeEnd(--segments_->end())); } } // namespace physics diff --git a/physics/discrete_trajectory_segment.hpp b/physics/discrete_trajectory_segment.hpp index 13f9c6bad6..803716fe8b 100644 --- a/physics/discrete_trajectory_segment.hpp +++ b/physics/discrete_trajectory_segment.hpp @@ -25,6 +25,7 @@ FORWARD_DECLARE_FROM(discrete_trajectory_factories, namespace physics { class DiscreteTrajectoryIteratorTest; +class DiscreteTrajectorySegmentIteratorTest; class DiscreteTrajectorySegmentTest; namespace internal_discrete_trajectory_segment { @@ -137,6 +138,7 @@ class DiscreteTrajectorySegment : public Trajectory { // For testing. friend class physics::DiscreteTrajectoryIteratorTest; + friend class physics::DiscreteTrajectorySegmentIteratorTest; friend class physics::DiscreteTrajectorySegmentTest; template friend class testing_utilities::DiscreteTrajectoryFactoriesFriend; diff --git a/physics/discrete_trajectory_segment_iterator_body.hpp b/physics/discrete_trajectory_segment_iterator_body.hpp index 198af9ad6c..2608d2b65b 100644 --- a/physics/discrete_trajectory_segment_iterator_body.hpp +++ b/physics/discrete_trajectory_segment_iterator_body.hpp @@ -33,13 +33,13 @@ DiscreteTrajectorySegmentIterator::operator--(int) { // NOLINT template internal_discrete_trajectory_segment::DiscreteTrajectorySegment const& DiscreteTrajectorySegmentIterator::operator*() const { - return **iterator_; + return *iterator_; } template internal_discrete_trajectory_segment::DiscreteTrajectorySegment const* DiscreteTrajectorySegmentIterator::operator->() const { - return iterator_->get(); + return &*iterator_; } template diff --git a/physics/discrete_trajectory_segment_iterator_test.cpp b/physics/discrete_trajectory_segment_iterator_test.cpp index 3342ee60ce..129e818643 100644 --- a/physics/discrete_trajectory_segment_iterator_test.cpp +++ b/physics/discrete_trajectory_segment_iterator_test.cpp @@ -5,17 +5,21 @@ #include "base/not_null.hpp" #include "geometry/frame.hpp" +#include "geometry/named_quantities.hpp" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "physics/discrete_trajectory_segment.hpp" #include "physics/discrete_trajectory_types.hpp" -#include "physics/mock_discrete_trajectory_segment.hpp" +#include "quantities/si.hpp" namespace principia { namespace physics { -using base::check_not_null; +using base::make_not_null_unique; using base::not_null; using geometry::Frame; +using geometry::Instant; +using quantities::si::Second; using ::testing::Return; // We use a mock segment in this test to avoid having to go through a @@ -23,35 +27,61 @@ using ::testing::Return; class DiscreteTrajectorySegmentIteratorTest : public ::testing::Test { protected: using World = Frame; - using Segments = internal_discrete_trajectory_types::Segments; + DiscreteTrajectorySegmentIteratorTest() + : segments_(MakeSegments(3)) { + auto it = segments_->begin(); + { + auto& segment1 = *it; + segment1.Append(t0_ + 2 * Second, unmoving_origin_); + segment1.Append(t0_ + 3 * Second, unmoving_origin_); + segment1.Append(t0_ + 5 * Second, unmoving_origin_); + segment1.Append(t0_ + 7 * Second, unmoving_origin_); + segment1.Append(t0_ + 11 * Second, unmoving_origin_); + } + + ++it; + { + auto& segment2 = *it; + segment2.Append(t0_ + 13 * Second, unmoving_origin_); + } + + ++it; + { + auto& segment3 = *it; + segment3.Append(t0_ + 13 * Second, unmoving_origin_); + segment3.Append(t0_ + 17 * Second, unmoving_origin_); + segment3.Append(t0_ + 19 * Second, unmoving_origin_); + } + } + DiscreteTrajectorySegmentIterator MakeIterator( not_null const segments, Segments::const_iterator const iterator) { return DiscreteTrajectorySegmentIterator(segments, iterator); } -}; -TEST_F(DiscreteTrajectorySegmentIteratorTest, Basic) { - auto owned_mock1 = std::make_unique>(); - auto owned_mock2 = std::make_unique>(); - auto owned_mock3 = std::make_unique>(); - auto const& mock1 = *owned_mock1; - auto const& mock2 = *owned_mock2; - auto const& mock3 = *owned_mock3; - - Segments segments; - segments.push_back(std::move(owned_mock1)); - segments.push_back(std::move(owned_mock2)); - segments.push_back(std::move(owned_mock3)); + // Constructs a list of |n| segments which are properly initialized. + // TODO(phl): Move to a central place. + static not_null> MakeSegments(const int n) { + auto segments = make_not_null_unique(n); + for (auto it = segments->begin(); it != segments->end(); ++it) { + *it = DiscreteTrajectorySegment( + DiscreteTrajectorySegmentIterator(segments.get(), it)); + } + return segments; + } - EXPECT_CALL(mock1, size()).WillRepeatedly(Return(5)); - EXPECT_CALL(mock2, size()).WillRepeatedly(Return(1)); - EXPECT_CALL(mock3, size()).WillRepeatedly(Return(3)); + not_null> segments_; + Instant const t0_; + DegreesOfFreedom const unmoving_origin_{World::origin, + World::unmoving}; +}; +TEST_F(DiscreteTrajectorySegmentIteratorTest, Basic) { { - auto iterator = MakeIterator(check_not_null(&segments), segments.begin()); + auto iterator = MakeIterator(segments_.get(), segments_->begin()); EXPECT_EQ(5, iterator->size()); auto const current = ++iterator; EXPECT_EQ(1, iterator->size()); @@ -61,7 +91,7 @@ TEST_F(DiscreteTrajectorySegmentIteratorTest, Basic) { EXPECT_EQ(1, previous->size()); } { - auto iterator = MakeIterator(check_not_null(&segments), segments.end()); + auto iterator = MakeIterator(segments_.get(), segments_->end()); --iterator; EXPECT_EQ(3, (*iterator).size()); auto const current = --iterator; diff --git a/physics/discrete_trajectory_segment_test.cpp b/physics/discrete_trajectory_segment_test.cpp index 6bf545f5a9..618b4e5f2f 100644 --- a/physics/discrete_trajectory_segment_test.cpp +++ b/physics/discrete_trajectory_segment_test.cpp @@ -20,7 +20,8 @@ namespace principia { namespace physics { -using base::check_not_null; +using base::make_not_null_unique; +using base::not_null; using geometry::Frame; using geometry::Instant; using quantities::Abs; @@ -34,10 +35,9 @@ using quantities::si::Nano; using quantities::si::Radian; using quantities::si::Second; using testing_utilities::AlmostEquals; -using testing_utilities::AppendTrajectorySegment; +using testing_utilities::AppendTrajectoryTimeline; using testing_utilities::IsNear; -using testing_utilities::NewCircularTrajectorySegment; -using testing_utilities::NewEmptyTrajectorySegment; +using testing_utilities::NewCircularTrajectoryTimeline; using testing_utilities::operator""_⑴; using ::testing::Eq; @@ -45,12 +45,11 @@ class DiscreteTrajectorySegmentTest : public ::testing::Test { protected: using World = Frame; - DiscreteTrajectorySegmentTest() : segments_(1) { - auto const it = segments_.begin(); - *it = std::make_unique>( - DiscreteTrajectorySegmentIterator(check_not_null(&segments_), - it)); - segment_ = segments_.cbegin()->get(); + using Segments = internal_discrete_trajectory_types::Segments; + + DiscreteTrajectorySegmentTest() + : segments_(MakeSegments(1)) { + segment_ = &*segments_->begin(); segment_->Append(t0_ + 2 * Second, unmoving_origin_); segment_->Append(t0_ + 3 * Second, unmoving_origin_); @@ -79,8 +78,19 @@ class DiscreteTrajectorySegmentTest : public ::testing::Test { segment.SetDownsampling(downsampling_parameters); } + // Constructs a list of |n| segments which are properly initialized. + // TODO(phl): Move to a central place. + static not_null> MakeSegments(const int n) { + auto segments = make_not_null_unique(n); + for (auto it = segments->begin(); it != segments->end(); ++it) { + *it = DiscreteTrajectorySegment( + DiscreteTrajectorySegmentIterator(segments.get(), it)); + } + return segments; + } + DiscreteTrajectorySegment* segment_; - internal_discrete_trajectory_types::Segments segments_; + not_null> segments_; Instant const t0_; DegreesOfFreedom unmoving_origin_{World::origin, World::unmoving}; }; @@ -180,24 +190,26 @@ TEST_F(DiscreteTrajectorySegmentTest, ForgetBeforeTheBeginning) { } TEST_F(DiscreteTrajectorySegmentTest, Evaluate) { + auto const segments = MakeSegments(1); + auto& circle = *segments->begin(); AngularFrequency const ω = 3 * Radian / Second; Length const r = 2 * Metre; Time const Δt = 10 * Milli(Second); Instant const t1 = t0_; Instant const t2 = t0_ + 10 * Second; - auto circle = NewCircularTrajectorySegment(ω, r, Δt, t1, t2); - auto& segment = **circle->cbegin(); + AppendTrajectoryTimeline( + NewCircularTrajectoryTimeline(ω, r, Δt, t1, t2), /*to=*/circle); - EXPECT_THAT(segment.size(), Eq(1001)); + EXPECT_THAT(circle.size(), Eq(1001)); std::vector position_errors; std::vector velocity_errors; - for (Instant t = segment.t_min(); - t <= segment.t_max(); + for (Instant t = circle.t_min(); + t <= circle.t_max(); t += 1 * Milli(Second)) { position_errors.push_back( - Abs((segment.EvaluatePosition(t) - World::origin).Norm() - r)); + Abs((circle.EvaluatePosition(t) - World::origin).Norm() - r)); velocity_errors.push_back( - Abs(segment.EvaluateVelocity(t).Norm() - r * ω / Radian)); + Abs(circle.EvaluateVelocity(t).Norm() - r * ω / Radian)); } EXPECT_THAT(*std::max_element(position_errors.begin(), position_errors.end()), IsNear(4.2_⑴ * Nano(Metre))); @@ -206,32 +218,34 @@ TEST_F(DiscreteTrajectorySegmentTest, Evaluate) { } TEST_F(DiscreteTrajectorySegmentTest, Downsampling) { - auto const circle = NewEmptyTrajectorySegment(); - auto const downsampled_circle = NewEmptyTrajectorySegment(); + auto const circle_segments = MakeSegments(1); + auto const downsampled_circle_segments = MakeSegments(1); + auto& circle = *circle_segments->begin(); + auto& downsampled_circle = *downsampled_circle_segments->begin(); SetDownsampling({.max_dense_intervals = 50, .tolerance = 1 * Milli(Metre)}, - *downsampled_circle->front()); + downsampled_circle); AngularFrequency const ω = 3 * Radian / Second; Length const r = 2 * Metre; Time const Δt = 10 * Milli(Second); Instant const t1 = t0_; Instant const t2 = t0_ + 10 * Second; - AppendTrajectorySegment( - *NewCircularTrajectorySegment(ω, r, Δt, t1, t2)->front(), - /*to=*/*circle->front()); - AppendTrajectorySegment( - *NewCircularTrajectorySegment(ω, r, Δt, t1, t2)->front(), - /*to=*/*downsampled_circle->front()); - - EXPECT_THAT(circle->front()->size(), Eq(1001)); - EXPECT_THAT(downsampled_circle->front()->size(), Eq(77)); + AppendTrajectoryTimeline( + NewCircularTrajectoryTimeline(ω, r, Δt, t1, t2), + /*to=*/circle); + AppendTrajectoryTimeline( + NewCircularTrajectoryTimeline(ω, r, Δt, t1, t2), + /*to=*/downsampled_circle); + + EXPECT_THAT(circle.size(), Eq(1001)); + EXPECT_THAT(downsampled_circle.size(), Eq(77)); std::vector position_errors; std::vector velocity_errors; - for (auto const& [time, degrees_of_freedom] : *circle->front()) { + for (auto const& [time, degrees_of_freedom] : circle) { position_errors.push_back( - (downsampled_circle->front()->EvaluatePosition(time) - + (downsampled_circle.EvaluatePosition(time) - degrees_of_freedom.position()).Norm()); velocity_errors.push_back( - (downsampled_circle->front()->EvaluateVelocity(time) - + (downsampled_circle.EvaluateVelocity(time) - degrees_of_freedom.velocity()).Norm()); } EXPECT_THAT(*std::max_element(position_errors.begin(), position_errors.end()), @@ -241,12 +255,14 @@ TEST_F(DiscreteTrajectorySegmentTest, Downsampling) { } TEST_F(DiscreteTrajectorySegmentTest, DownsamplingForgetAfter) { - auto const circle = NewEmptyTrajectorySegment(); - auto const forgotten_circle = NewEmptyTrajectorySegment(); + auto const circle_segments = MakeSegments(1); + auto const forgotten_circle_segments = MakeSegments(1); + auto& circle = *circle_segments->begin(); + auto& forgotten_circle = *forgotten_circle_segments->begin(); SetDownsampling({.max_dense_intervals = 50, .tolerance = 1 * Milli(Metre)}, - *circle->front()); + circle); SetDownsampling({.max_dense_intervals = 50, .tolerance = 1 * Milli(Metre)}, - *forgotten_circle->front()); + forgotten_circle); AngularFrequency const ω = 3 * Radian / Second; Length const r = 2 * Metre; Time const Δt = 1.0 / 128.0 * Second; // Yields exact times. @@ -255,33 +271,32 @@ TEST_F(DiscreteTrajectorySegmentTest, DownsamplingForgetAfter) { Instant const t3 = t0_ + 10 * Second; // Construct two identical trajectories with downsampling. - AppendTrajectorySegment( - *NewCircularTrajectorySegment(ω, r, Δt, t1, t3)->front(), - /*to=*/*circle->front()); - AppendTrajectorySegment( - *NewCircularTrajectorySegment(ω, r, Δt, t1, t3)->front(), - /*to=*/*forgotten_circle->front()); + AppendTrajectoryTimeline( + NewCircularTrajectoryTimeline(ω, r, Δt, t1, t3), + /*to=*/circle); + AppendTrajectoryTimeline( + NewCircularTrajectoryTimeline(ω, r, Δt, t1, t3), + /*to=*/forgotten_circle); // Forget one of the trajectories in the middle, and append new points. - Instant const restart_time = - forgotten_circle->front()->lower_bound(t2)->first; - ForgetAfter(t2, *forgotten_circle->front()); - AppendTrajectorySegment( - *NewCircularTrajectorySegment(ω, r, Δt, restart_time, t3)->front(), - /*to=*/*forgotten_circle->front()); - - EXPECT_THAT(circle->front()->size(), Eq(92)); - EXPECT_THAT(forgotten_circle->front()->size(), Eq(circle->front()->size())); + Instant const restart_time = forgotten_circle.lower_bound(t2)->first; + ForgetAfter(t2, forgotten_circle); + AppendTrajectoryTimeline( + NewCircularTrajectoryTimeline(ω, r, Δt, restart_time, t3), + /*to=*/forgotten_circle); + + EXPECT_THAT(circle.size(), Eq(92)); + EXPECT_THAT(forgotten_circle.size(), Eq(circle.size())); std::vector position_errors; std::vector velocity_errors; // Check that the two trajectories are identical. - for (auto const [t, degrees_of_freedom] : *forgotten_circle->front()) { + for (auto const [t, degrees_of_freedom] : forgotten_circle) { position_errors.push_back( - (circle->front()->find(t)->second.position() - + (circle.find(t)->second.position() - degrees_of_freedom.position()).Norm()); velocity_errors.push_back( - (circle->front()->find(t)->second.velocity() - + (circle.find(t)->second.velocity() - degrees_of_freedom.velocity()).Norm()); } EXPECT_THAT(*std::max_element(position_errors.begin(), position_errors.end()), diff --git a/physics/discrete_trajectory_types.hpp b/physics/discrete_trajectory_types.hpp index 4e4e9c8767..28d793652d 100644 --- a/physics/discrete_trajectory_types.hpp +++ b/physics/discrete_trajectory_types.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include "absl/container/btree_map.h" #include "base/macros.hpp" @@ -32,10 +31,8 @@ struct DownsamplingParameters { Length tolerance; }; -// The use of an unique_ptr here makes it possible to only depend on a forward -// declaration of DiscreteTrajectorySegment. template -using Segments = std::list>>; +using Segments = std::list>; template using Timeline = absl::btree_map>; diff --git a/testing_utilities/discrete_trajectory_factories.hpp b/testing_utilities/discrete_trajectory_factories.hpp index 0ccd56d2ad..900ea5a517 100644 --- a/testing_utilities/discrete_trajectory_factories.hpp +++ b/testing_utilities/discrete_trajectory_factories.hpp @@ -20,7 +20,7 @@ using geometry::Instant; using geometry::Velocity; using physics::DegreesOfFreedom; using physics::DiscreteTrajectorySegment; -using physics::internal_discrete_trajectory_types::Segments; +using physics::internal_discrete_trajectory_types::Timeline; using quantities::AngularFrequency; using quantities::Length; using quantities::Time; @@ -33,68 +33,51 @@ class DiscreteTrajectoryFactoriesFriend { static absl::Status Append(Instant const& t, DegreesOfFreedom const& degrees_of_freedom, DiscreteTrajectorySegment& segment); - - static DiscreteTrajectorySegment - MakeDiscreteTrajectorySegment( - Segments const& segments, - typename Segments::const_iterator iterator); }; -// All the functions below return a list of a single segment. -// TODO(phl): Revise this API as needed once we have all the pieces for the new- -// style discrete trajectories. -// TODO(phl): Must return unique_ptr because copying Segments is a bad idea due -// to the pointers within iterators. - -// An empty trajectory. Convenient for initializations. -template -not_null>> -NewEmptyTrajectorySegment(); - // A linear trajectory with constant velocity, going through // |degrees_of_freedom.position()| at t = 0. The first point is at time |t1|, // the last point at a time < |t2|. template -not_null>> -NewLinearTrajectorySegment(DegreesOfFreedom const& degrees_of_freedom, - Time const& Δt, - Instant const& t1, - Instant const& t2); +Timeline +NewLinearTrajectoryTimeline(DegreesOfFreedom const& degrees_of_freedom, + Time const& Δt, + Instant const& t1, + Instant const& t2); // Same as above, going through the origin at t = 0. template -not_null>> -NewLinearTrajectorySegment(Velocity const& v, - Time const& Δt, - Instant const& t1, - Instant const& t2); +Timeline +NewLinearTrajectoryTimeline(Velocity const& v, + Time const& Δt, + Instant const& t1, + Instant const& t2); // A circular trajectory in the plane XY, centred at the origin. The first // point is at time |t1|, the last point at a time < |t2|. template -not_null>> -NewCircularTrajectorySegment(AngularFrequency const& ω, - Length const& r, - Time const& Δt, - Instant const& t1, - Instant const& t2); +Timeline +NewCircularTrajectoryTimeline(AngularFrequency const& ω, + Length const& r, + Time const& Δt, + Instant const& t1, + Instant const& t2); template -not_null>> -NewCircularTrajectorySegment(Time const& period, - Length const& r, - Time const& Δt, - Instant const& t1, - Instant const& t2); +Timeline +NewCircularTrajectoryTimeline(Time const& period, + Length const& r, + Time const& Δt, + Instant const& t1, + Instant const& t2); template -void AppendTrajectorySegment(DiscreteTrajectorySegment const& from, - DiscreteTrajectorySegment& to); +void AppendTrajectoryTimeline(Timeline const& from, + DiscreteTrajectorySegment& to); } // namespace internal_discrete_trajectory_factories -using internal_discrete_trajectory_factories::AppendTrajectorySegment; -using internal_discrete_trajectory_factories::NewCircularTrajectorySegment; -using internal_discrete_trajectory_factories::NewEmptyTrajectorySegment; -using internal_discrete_trajectory_factories::NewLinearTrajectorySegment; +using internal_discrete_trajectory_factories::AppendTrajectoryTimeline; +using internal_discrete_trajectory_factories::NewCircularTrajectoryTimeline; +using internal_discrete_trajectory_factories::NewLinearTrajectoryTimeline; } // namespace testing_utilities } // namespace principia diff --git a/testing_utilities/discrete_trajectory_factories_body.hpp b/testing_utilities/discrete_trajectory_factories_body.hpp index 0a01b4127d..fa17ac7860 100644 --- a/testing_utilities/discrete_trajectory_factories_body.hpp +++ b/testing_utilities/discrete_trajectory_factories_body.hpp @@ -33,64 +33,40 @@ absl::Status DiscreteTrajectoryFactoriesFriend::Append( } template -DiscreteTrajectorySegment -DiscreteTrajectoryFactoriesFriend::MakeDiscreteTrajectorySegment( - Segments const& segments, - typename Segments::const_iterator const iterator) { - return DiscreteTrajectorySegment( - DiscreteTrajectorySegmentIterator(check_not_null(&segments), - iterator)); -} - -template -not_null>> -NewEmptyTrajectorySegment() { - auto segments = std::make_unique>(1); - auto const it = segments->begin(); - *it = std::make_unique>( - DiscreteTrajectoryFactoriesFriend::MakeDiscreteTrajectorySegment( - *segments, it)); - return segments; -} - -template -not_null>> -NewLinearTrajectorySegment(DegreesOfFreedom const& degrees_of_freedom, - Time const& Δt, - Instant const& t1, - Instant const& t2) { +Timeline +NewLinearTrajectoryTimeline(DegreesOfFreedom const& degrees_of_freedom, + Time const& Δt, + Instant const& t1, + Instant const& t2) { static Instant const t0; - auto segments = NewEmptyTrajectorySegment(); - auto& segment = **segments->cbegin(); + Timeline timeline; for (auto t = t1; t < t2; t += Δt) { auto const velocity = degrees_of_freedom.velocity(); auto const position = degrees_of_freedom.position() + velocity * (t - t0); - DiscreteTrajectoryFactoriesFriend::Append( - t, DegreesOfFreedom(position, velocity), segment); + timeline.emplace(t, DegreesOfFreedom(position, velocity)); } - return segments; + return timeline; } template -not_null>> -NewLinearTrajectorySegment(Velocity const& v, +Timeline +NewLinearTrajectoryTimeline(Velocity const& v, Time const& Δt, Instant const& t1, Instant const& t2) { - return NewLinearTrajectory( + return NewLinearTrajectoryTimeline( DegreesOfFreedom(Frame::origin, v), Δt, t1, t2); } template -not_null>> -NewCircularTrajectorySegment(AngularFrequency const& ω, +Timeline +NewCircularTrajectoryTimeline(AngularFrequency const& ω, Length const& r, Time const& Δt, Instant const& t1, Instant const& t2) { static Instant const t0; - auto segments = NewEmptyTrajectorySegment(); - auto& segment = **segments->cbegin(); + Timeline timeline; Speed const v = ω * r / Radian; for (auto t = t1; t < t2; t += Δt) { DegreesOfFreedom const dof = { @@ -100,14 +76,14 @@ NewCircularTrajectorySegment(AngularFrequency const& ω, Velocity{{-v * Sin(ω * (t - t0)), v * Cos(ω * (t - t0)), Speed{}}}}; - DiscreteTrajectoryFactoriesFriend::Append(t, dof, segment); + timeline.emplace(t, dof); } - return segments; + return timeline; } template -not_null>> -NewCircularTrajectorySegment(Time const& period, +Timeline +NewCircularTrajectoryTimeline(Time const& period, Length const& r, Time const& Δt, Instant const& t1, @@ -120,8 +96,8 @@ NewCircularTrajectorySegment(Time const& period, } template -void AppendTrajectorySegment(DiscreteTrajectorySegment const& from, - DiscreteTrajectorySegment& to) { +void AppendTrajectoryTimeline(Timeline const& from, + DiscreteTrajectorySegment& to) { for (auto const& [t, degrees_of_freedom] : from) { DiscreteTrajectoryFactoriesFriend::Append(t, degrees_of_freedom, to); } diff --git a/testing_utilities/discrete_trajectory_factories_test.cpp b/testing_utilities/discrete_trajectory_factories_test.cpp index 364ceb9205..e746d03123 100644 --- a/testing_utilities/discrete_trajectory_factories_test.cpp +++ b/testing_utilities/discrete_trajectory_factories_test.cpp @@ -39,14 +39,8 @@ class DiscreteTrajectoryFactoriesTest : public ::testing::Test { serialization::Frame::TEST>; }; -TEST_F(DiscreteTrajectoryFactoriesTest, NewEmptyTrajectorySegment) { - auto const segments = NewEmptyTrajectorySegment(); - auto const& segment = *segments->front(); - EXPECT_TRUE(segment.empty()); -} - -TEST_F(DiscreteTrajectoryFactoriesTest, NewLinearTrajectorySegment) { - auto const segments = NewLinearTrajectorySegment( +TEST_F(DiscreteTrajectoryFactoriesTest, NewLinearTrajectoryTimeline) { + auto const timeline = NewLinearTrajectoryTimeline( /*degrees_of_freedom=*/ DegreesOfFreedom( World::origin + @@ -56,9 +50,8 @@ TEST_F(DiscreteTrajectoryFactoriesTest, NewLinearTrajectorySegment) { /*Δt=*/0.1 * Second, /*t1=*/Instant() + 4 * Second, /*t2=*/Instant() + 42 * Second); - auto const& segment = *segments->front(); - for (auto const& [time, degrees_of_freedom] : segment) { + for (auto const& [time, degrees_of_freedom] : timeline) { Position const& position = degrees_of_freedom.position(); Velocity const& velocity = degrees_of_freedom.velocity(); @@ -70,23 +63,22 @@ TEST_F(DiscreteTrajectoryFactoriesTest, NewLinearTrajectorySegment) { 1)); EXPECT_THAT(velocity.Norm(), AlmostEquals(Sqrt(77) * Metre / Second, 0, 0)); } - EXPECT_THAT(segment.begin()->first, + EXPECT_THAT(timeline.begin()->first, AlmostEquals(Instant() + 4 * Second, 0)); - EXPECT_THAT(segment.rbegin()->first, + EXPECT_THAT(timeline.rbegin()->first, AlmostEquals(Instant() + 41.9 * Second, 46)); - EXPECT_EQ(380, segment.size()); + EXPECT_EQ(380, timeline.size()); } -TEST_F(DiscreteTrajectoryFactoriesTest, NewCircularTrajectorySegment) { - auto const segments = NewCircularTrajectorySegment( +TEST_F(DiscreteTrajectoryFactoriesTest, NewCircularTrajectoryTimeline) { + auto const timeline = NewCircularTrajectoryTimeline( /*ω=*/3 * Radian / Second, /*r=*/2 * Metre, /*Δt=*/0.1 * Second, /*t1=*/Instant() + 4 * Second, /*t2=*/Instant() + 42 * Second); - auto const& segment = *segments->front(); - for (auto const& [time, degrees_of_freedom] : segment) { + for (auto const& [time, degrees_of_freedom] : timeline) { Position const& position = degrees_of_freedom.position(); Velocity const& velocity = degrees_of_freedom.velocity(); @@ -95,11 +87,11 @@ TEST_F(DiscreteTrajectoryFactoriesTest, NewCircularTrajectorySegment) { EXPECT_THAT(InnerProduct(position - World::origin, velocity), VanishesBefore(1 * Metre * Metre / Second, 0, 8)); } - EXPECT_THAT(segment.begin()->first, + EXPECT_THAT(timeline.begin()->first, AlmostEquals(Instant() + 4 * Second, 0)); - EXPECT_THAT(segment.rbegin()->first, + EXPECT_THAT(timeline.rbegin()->first, AlmostEquals(Instant() + 41.9 * Second, 46)); - EXPECT_EQ(380, segment.size()); + EXPECT_EQ(380, timeline.size()); } } // namespace testing_utilities