12
12
#include " quantities/named_quantities.hpp"
13
13
#include " quantities/quantities.hpp"
14
14
#include " quantities/si.hpp"
15
+ #include " testing_utilities/almost_equals.hpp"
15
16
#include " testing_utilities/approximate_quantity.hpp"
16
17
#include " testing_utilities/discrete_trajectory_factories.hpp"
17
18
#include " testing_utilities/is_near.hpp"
@@ -32,6 +33,7 @@ using quantities::si::Milli;
32
33
using quantities::si::Nano;
33
34
using quantities::si::Radian;
34
35
using quantities::si::Second;
36
+ using testing_utilities::AlmostEquals;
35
37
using testing_utilities::AppendTrajectorySegment;
36
38
using testing_utilities::IsNear;
37
39
using testing_utilities::NewCircularTrajectorySegment;
@@ -61,6 +63,11 @@ class DiscreteTrajectorySegmentTest : public ::testing::Test {
61
63
segment_->ForgetAfter (t);
62
64
}
63
65
66
+ void ForgetAfter (Instant const & t,
67
+ DiscreteTrajectorySegment<World>& segment) {
68
+ segment.ForgetAfter (t);
69
+ }
70
+
64
71
void ForgetBefore (Instant const & t) {
65
72
segment_->ForgetBefore (t);
66
73
}
@@ -233,5 +240,55 @@ TEST_F(DiscreteTrajectorySegmentTest, Downsampling) {
233
240
IsNear (14_⑴ * Milli (Metre / Second)));
234
241
}
235
242
243
+ TEST_F (DiscreteTrajectorySegmentTest, DownsamplingForgetAfter) {
244
+ auto const circle = NewEmptyTrajectorySegment<World>();
245
+ auto const forgotten_circle = NewEmptyTrajectorySegment<World>();
246
+ SetDownsampling ({.max_dense_intervals = 50 , .tolerance = 1 * Milli (Metre)},
247
+ *circle->front ());
248
+ SetDownsampling ({.max_dense_intervals = 50 , .tolerance = 1 * Milli (Metre)},
249
+ *forgotten_circle->front ());
250
+ AngularFrequency const ω = 3 * Radian / Second;
251
+ Length const r = 2 * Metre;
252
+ Time const Δt = 1.0 / 128.0 * Second; // Yields exact times.
253
+ Instant const t1 = t0_;
254
+ Instant const t2 = t0_ + 5 * Second;
255
+ Instant const t3 = t0_ + 10 * Second;
256
+
257
+ // Construct two identical trajectories with downsampling.
258
+ AppendTrajectorySegment (
259
+ *NewCircularTrajectorySegment<World>(ω, r, Δt, t1, t3)->front (),
260
+ /* to=*/ *circle->front ());
261
+ AppendTrajectorySegment (
262
+ *NewCircularTrajectorySegment<World>(ω, r, Δt, t1, t3)->front (),
263
+ /* to=*/ *forgotten_circle->front ());
264
+
265
+ // Forget one of the trajectories in the middle, and append new points.
266
+ Instant const restart_time =
267
+ forgotten_circle->front ()->lower_bound (t2)->first ;
268
+ ForgetAfter (t2, *forgotten_circle->front ());
269
+ AppendTrajectorySegment (
270
+ *NewCircularTrajectorySegment<World>(ω, r, Δt, restart_time, t3)->front (),
271
+ /* to=*/ *forgotten_circle->front ());
272
+
273
+ EXPECT_THAT (circle->front ()->size (), Eq (92 ));
274
+ EXPECT_THAT (forgotten_circle->front ()->size (), Eq (circle->front ()->size ()));
275
+ std::vector<Length> position_errors;
276
+ std::vector<Speed> velocity_errors;
277
+
278
+ // Check that the two trajectories are identical.
279
+ for (auto const [t, degrees_of_freedom] : *forgotten_circle->front ()) {
280
+ position_errors.push_back (
281
+ (circle->front ()->find (t)->second .position () -
282
+ degrees_of_freedom.position ()).Norm ());
283
+ velocity_errors.push_back (
284
+ (circle->front ()->find (t)->second .velocity () -
285
+ degrees_of_freedom.velocity ()).Norm ());
286
+ }
287
+ EXPECT_THAT (*std::max_element (position_errors.begin (), position_errors.end ()),
288
+ AlmostEquals (0 * Metre, 0 ));
289
+ EXPECT_THAT (*std::max_element (velocity_errors.begin (), velocity_errors.end ()),
290
+ AlmostEquals (0 * Metre / Second, 0 ));
291
+ }
292
+
236
293
} // namespace physics
237
294
} // namespace principia
0 commit comments