James Kuszmaul | 9f9676d | 2019-01-25 21:27:58 -0800 | [diff] [blame] | 1 | #include "frc971/control_loops/pose.h" |
| 2 | |
| 3 | #include "gtest/gtest.h" |
| 4 | |
| 5 | namespace frc971 { |
| 6 | namespace control_loops { |
| 7 | namespace testing { |
| 8 | |
| 9 | // Test that basic accessors on an individual Pose object work as expected. |
| 10 | TEST(PoseTest, BasicPoseTest) { |
| 11 | // Provide a basic Pose with non-zero components for everything. |
| 12 | Pose pose({1, 1, 0.5}, 0.5); |
| 13 | // The xy_norm should just be based on the x/y positions, not the Z; hence |
| 14 | // sqrt(2) rather than sqrt(1^2 + 1^2 + 0.5^2). |
| 15 | EXPECT_DOUBLE_EQ(::std::sqrt(2.0), pose.xy_norm()); |
| 16 | // Similarly, heading should just be atan2(y, x). |
| 17 | EXPECT_DOUBLE_EQ(M_PI / 4.0, pose.heading()); |
| 18 | // Global and relative poses should be the same since we did not construct |
| 19 | // this off of a separate Pose. |
| 20 | EXPECT_EQ(1.0, pose.rel_pos().x()); |
| 21 | EXPECT_EQ(1.0, pose.rel_pos().y()); |
| 22 | EXPECT_EQ(0.5, pose.rel_pos().z()); |
| 23 | |
| 24 | EXPECT_EQ(1.0, pose.abs_pos().x()); |
| 25 | EXPECT_EQ(1.0, pose.abs_pos().y()); |
James Kuszmaul | 090563a | 2019-02-09 14:43:20 -0800 | [diff] [blame^] | 26 | EXPECT_EQ(1.0, pose.abs_xy().x()); |
| 27 | EXPECT_EQ(1.0, pose.abs_xy().y()); |
James Kuszmaul | 9f9676d | 2019-01-25 21:27:58 -0800 | [diff] [blame] | 28 | EXPECT_EQ(0.5, pose.abs_pos().z()); |
| 29 | |
| 30 | EXPECT_EQ(0.5, pose.rel_theta()); |
| 31 | EXPECT_EQ(0.5, pose.abs_theta()); |
| 32 | |
| 33 | pose.set_theta(3.14); |
| 34 | EXPECT_EQ(3.14, pose.rel_theta()); |
| 35 | pose.mutable_pos()->x() = 9.71; |
| 36 | EXPECT_EQ(9.71, pose.rel_pos().x()); |
James Kuszmaul | 090563a | 2019-02-09 14:43:20 -0800 | [diff] [blame^] | 37 | |
| 38 | EXPECT_EQ(nullptr, pose.base()); |
| 39 | Pose new_base; |
| 40 | pose.set_base(&new_base); |
| 41 | EXPECT_EQ(&new_base, pose.base()); |
James Kuszmaul | 9f9676d | 2019-01-25 21:27:58 -0800 | [diff] [blame] | 42 | } |
| 43 | |
| 44 | // Check that Poses behave as expected when constructed relative to another |
| 45 | // POse. |
| 46 | TEST(PoseTest, BaseTest) { |
| 47 | // Tolerance for the EXPECT_NEARs. Because we are doing enough trig operations |
| 48 | // under the hood we actually start to lose some precision. |
| 49 | constexpr double kEps = 1e-15; |
| 50 | // The points we will construct have absolute positions at: |
| 51 | // base1: (1, 1) |
| 52 | // base2: (-1, 1) |
| 53 | // rel1: (0, 2) |
| 54 | // Where rel1 is expressed as compared to base1, noting that because base1 |
| 55 | // has a yaw of M_PI, the position of rel1 compared to base1 is (1, -1) |
| 56 | // rather than (-1, 1). |
| 57 | Pose base1({1, 1, 0}, M_PI); |
| 58 | Pose base2({-1, 1, 0}, -M_PI / 2.0); |
| 59 | Pose rel1(&base1, {1, -1, 0}, 0.0); |
| 60 | EXPECT_NEAR(0.0, rel1.abs_pos().x(), kEps); |
| 61 | EXPECT_NEAR(2.0, rel1.abs_pos().y(), kEps); |
| 62 | EXPECT_NEAR(M_PI, rel1.abs_theta(), kEps); |
| 63 | // Check that, when rebasing to base2, the absolute position does not change |
| 64 | // and the relative POse changes to be relative to base2. |
| 65 | Pose rel2 = rel1.Rebase(&base2); |
| 66 | EXPECT_NEAR(rel1.abs_pos().x(), rel2.abs_pos().x(), kEps); |
| 67 | EXPECT_NEAR(rel1.abs_pos().y(), rel2.abs_pos().y(), kEps); |
| 68 | EXPECT_NEAR(rel1.abs_pos().z(), rel2.abs_pos().z(), kEps); |
| 69 | EXPECT_NEAR(rel1.abs_theta(), rel2.abs_theta(), kEps); |
| 70 | EXPECT_NEAR(-1.0, rel2.rel_pos().x(), kEps); |
| 71 | EXPECT_NEAR(1.0, rel2.rel_pos().y(), kEps); |
| 72 | EXPECT_NEAR(-M_PI / 2.0, rel2.rel_theta(), kEps); |
| 73 | // Check that rebasing onto nullptr results in a Pose based in the global |
| 74 | // frame. |
| 75 | Pose abs = rel1.Rebase(nullptr); |
| 76 | EXPECT_NEAR(rel1.abs_pos().x(), abs.abs_pos().x(), kEps); |
| 77 | EXPECT_NEAR(rel1.abs_pos().y(), abs.abs_pos().y(), kEps); |
| 78 | EXPECT_NEAR(rel1.abs_pos().z(), abs.abs_pos().z(), kEps); |
| 79 | EXPECT_NEAR(rel1.abs_theta(), abs.abs_theta(), kEps); |
| 80 | EXPECT_NEAR(rel1.abs_pos().x(), abs.rel_pos().x(), kEps); |
| 81 | EXPECT_NEAR(rel1.abs_pos().y(), abs.rel_pos().y(), kEps); |
| 82 | EXPECT_NEAR(rel1.abs_pos().z(), abs.rel_pos().z(), kEps); |
| 83 | EXPECT_NEAR(rel1.abs_theta(), abs.rel_theta(), kEps); |
| 84 | } |
| 85 | |
James Kuszmaul | 090563a | 2019-02-09 14:43:20 -0800 | [diff] [blame^] | 86 | // Tests that basic accessors for LineSegment behave as expected. |
| 87 | TEST(LineSegmentTest, BasicAccessorTest) { |
| 88 | LineSegment l; |
| 89 | EXPECT_EQ(0.0, l.pose1().rel_theta()); |
| 90 | l.mutable_pose1()->set_theta(1.234); |
| 91 | EXPECT_EQ(1.234, l.pose1().rel_theta()); |
| 92 | EXPECT_EQ(0.0, l.pose2().rel_theta()); |
| 93 | l.mutable_pose2()->set_theta(5.678); |
| 94 | EXPECT_EQ(5.678, l.pose2().rel_theta()); |
| 95 | |
| 96 | const ::std::vector<Pose> plot_pts = l.PlotPoints(); |
| 97 | ASSERT_EQ(2u, plot_pts.size()); |
| 98 | EXPECT_EQ(l.pose1().rel_theta(), plot_pts[0].rel_theta()); |
| 99 | EXPECT_EQ(l.pose2().rel_theta(), plot_pts[1].rel_theta()); |
| 100 | } |
| 101 | |
James Kuszmaul | 9f9676d | 2019-01-25 21:27:58 -0800 | [diff] [blame] | 102 | // Tests that basic checks for intersection function as expected. |
| 103 | TEST(LineSegmentTest, TrivialIntersectTest) { |
| 104 | Pose p1({0, 0, 0}, 0.0), p2({2, 0, 0}, 0.0); |
| 105 | // A line segment from (0, 0) to (0, 2). |
| 106 | LineSegment l1(p1, p2); |
| 107 | Pose q1({1, -1, 0}, 0.0), q2({1, 1, 0}, 0.0); |
| 108 | // A line segment from (1, -1) to (1, 1). |
| 109 | LineSegment l2(q1, q2); |
| 110 | // The two line segments should intersect. |
| 111 | EXPECT_TRUE(l1.Intersects(l2)); |
| 112 | EXPECT_TRUE(l2.Intersects(l1)); |
| 113 | |
| 114 | // If we switch around the orderings such that the line segments are |
| 115 | // (0, 0) -> (1, -1) and (2, 0)->(1, 1) then the line segments do not |
| 116 | // intersect. |
| 117 | LineSegment l3(p1, q1); |
| 118 | LineSegment l4(p2, q2); |
| 119 | EXPECT_FALSE(l3.Intersects(l4)); |
| 120 | EXPECT_FALSE(l4.Intersects(l3)); |
| 121 | } |
| 122 | |
| 123 | // Check that when we construct line segments that are collinear, both with |
| 124 | // overlapping bits and without overlapping bits, they register as not |
| 125 | // intersecting. |
| 126 | // We may want this behavior to change in the future, but for now check for |
| 127 | // consistency. |
| 128 | TEST(LineSegmentTest, CollinearIntersectTest) { |
| 129 | Pose p1({0, 0, 0}, 0.0), p2({1, 0, 0}, 0.0), p3({2, 0, 0}, 0.0), |
| 130 | p4({3, 0, 0}, 0.0); |
| 131 | // These two line segments overlap and are collinear, one going from 0 to 2 |
| 132 | // and the other from 1 to 3 on the X-axis. |
| 133 | LineSegment l1(p1, p3); |
| 134 | LineSegment l2(p2, p4); |
| 135 | EXPECT_FALSE(l1.Intersects(l2)); |
| 136 | EXPECT_FALSE(l2.Intersects(l1)); |
| 137 | |
| 138 | // These two line segments do not overlap and are collinear, one going from 0 |
| 139 | // to 1 and the other from 2 to 3 on the X-axis. |
| 140 | LineSegment l3(p1, p2); |
| 141 | LineSegment l4(p3, p4); |
| 142 | EXPECT_FALSE(l3.Intersects(l4)); |
| 143 | EXPECT_FALSE(l4.Intersects(l3)); |
| 144 | |
| 145 | // Test when one line segment is completely contained within the other. |
| 146 | LineSegment l5(p1, p4); |
| 147 | LineSegment l6(p3, p2); |
| 148 | EXPECT_FALSE(l5.Intersects(l6)); |
| 149 | EXPECT_FALSE(l6.Intersects(l5)); |
| 150 | } |
| 151 | |
| 152 | } // namespace testing |
| 153 | } // namespace control_loops |
| 154 | } // namespace frc971 |