29 out <<
"{x=" << vector3D.
x <<
", y=" << vector3D.
y <<
", z=" << vector3D.
z <<
'}';
38TEST(geom, single_point_no_transform) {
39 constexpr double error = 0.001;
41 Location translation (0.0, 0.0, 0.0);
43 Transform transform (translation, rotation);
47 Location result_point(1.0, 1.0, 1.0);
49 ASSERT_NEAR(
point.x, result_point.
x, error);
50 ASSERT_NEAR(
point.y, result_point.
y, error);
51 ASSERT_NEAR(
point.z, result_point.
z, error);
55TEST(geom, single_point_translation) {
56 constexpr double error = 0.001;
60 Transform transform (translation, rotation);
64 Location result_point(2.0, 5.0, 7.0);
66 ASSERT_NEAR(
point.x, result_point.
x, error);
67 ASSERT_NEAR(
point.y, result_point.
y, error);
68 ASSERT_NEAR(
point.z, result_point.
z, error);
72TEST(geom, single_point_transform_inverse_transform_coherence) {
73 constexpr double error = 0.001;
76 const Location translation (1.41f, -4.7f, 9.2f);
77 const Rotation rotation (-47.0f, 37.0f, 250.2f);
78 const Transform transform (translation, rotation);
80 auto transformed_point =
point;
83 auto point_back_to_normal = transformed_point;
86 ASSERT_NEAR(
point.x, point_back_to_normal.x, error) <<
"result.x is " << point_back_to_normal.x <<
" but expected " <<
point.x;
87 ASSERT_NEAR(
point.y, point_back_to_normal.y, error) <<
"result.y is " << point_back_to_normal.y <<
" but expected " <<
point.y;
88 ASSERT_NEAR(
point.z, point_back_to_normal.z, error) <<
"result.z is " << point_back_to_normal.z <<
" but expected " <<
point.z;
92TEST(geom, bbox_get_local_vertices_get_world_vertices_coherence) {
93 constexpr double error = 0.001;
97 const Location bbox_location(-3.14f, 1.337f, 4.20f);
98 const Rotation bbox_rotation (-59.0f, 17.0f, -650.2f);
99 const Transform bbox_transform(bbox_location, bbox_rotation);
103 for (
auto i = 0u; i < local_vertices.size(); ++i){
104 const auto &local_vertex = local_vertices[i];
106 auto transformed_local_vertex = local_vertex;
109 const auto &world_vertex = world_vertices[i];
111 ASSERT_NEAR(transformed_local_vertex.x, world_vertex.x, error) <<
"result.x is " << transformed_local_vertex.x <<
" but expected " << world_vertex.x;
112 ASSERT_NEAR(transformed_local_vertex.y, world_vertex.y, error) <<
"result.y is " << transformed_local_vertex.y <<
" but expected " << world_vertex.y;
113 ASSERT_NEAR(transformed_local_vertex.z, world_vertex.z, error) <<
"result.z is " << transformed_local_vertex.z <<
" but expected " << world_vertex.z;
118TEST(geom, single_point_rotation) {
119 constexpr double error = 0.001;
123 Transform transform (translation, rotation);
127 Location result_point(0.0, 0.0, 1.0);
128 ASSERT_NEAR(
point.x, result_point.
x, error);
129 ASSERT_NEAR(
point.y, result_point.
y, error);
130 ASSERT_NEAR(
point.z, result_point.
z, error);
133TEST(geom, single_point_translation_and_rotation) {
134 constexpr double error = 0.001;
142 Location translation (0.0,0.0,-1.0);
144 Transform transform (translation, rotation);
148 Location result_point(-2.0, 0.0, -1.0);
149 ASSERT_NEAR(
point.x, result_point.
x, error);
150 ASSERT_NEAR(
point.y, result_point.
y, error);
151 ASSERT_NEAR(
point.z, result_point.
z, error);
155 constexpr double error = .01;
157 ASSERT_NEAR(
Math::Distance({1, 1, 1}, {0, 0, 0}), 1.732051, error);
158 ASSERT_NEAR(
Math::Distance({0, 0, 0}, {1, 1, 1}), 1.732051, error);
159 ASSERT_NEAR(
Math::Distance({-1, -1, -1}, {0, 0, 0}), 1.732051, error);
160 ASSERT_NEAR(
Math::Distance({0, 0, 0}, {-1, -1, -1}), 1.732051, error);
161 ASSERT_NEAR(
Math::Distance({7, 4, 3}, {17, 6, 2}), 10.246951, error);
162 ASSERT_NEAR(
Math::Distance({7, -4, 3}, {-17, 6, 2}), 26.019224, error);
163 ASSERT_NEAR(
Math::Distance({5, 6, 7}, {-6, 3, -4}), 15.84298, error);
164 ASSERT_NEAR(
Math::Distance({7, 4, 3}, {17, 6, 2}), 10.246951, error);
167TEST(geom, nearest_point_segment) {
168 const float segment[] = {
194 const int results[] = {
195 0, 1, 7, 9, 8, 2, 9, 2, 8, 3
198 for (
int i = 0; i < 10; ++i) {
199 double min_dist = std::numeric_limits<double>::max();
201 for (
int j = 0; j < 40; j += 4) {
204 {segment[j + 0], segment[j + 1], 0},
205 {segment[j + 2], segment[j + 3], 0}).second;
206 if (dist < min_dist) {
211 ASSERT_EQ(
id, results[i]) <<
"Fails point number: " << i;
217 constexpr float eps = 2.0f * std::numeric_limits<float>::epsilon();
220 (std::abs(expected.x - result.x) < eps) &&
221 (std::abs(expected.y - result.y) < eps) &&
222 (std::abs(expected.z - result.z) < eps))
223 <<
"result = " << result <<
'\n'
224 <<
"expected = " << expected;
227 compare({ 0.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f});
228 compare({ 0.0f, 0.0f, 123.0f}, {1.0f, 0.0f, 0.0f});
229 compare({360.0f, 360.0f, 0.0f}, {1.0f, 0.0f, 0.0f});
230 compare({ 0.0f, 90.0f, 0.0f}, {0.0f, 1.0f, 0.0f});
231 compare({ 0.0f, -90.0f, 0.0f}, {0.0f,-1.0f, 0.0f});
236 compare({ 90.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f});
237 compare({180.0f, -90.0f, 0.0f}, {0.0f, 1.0f, 0.0f});
242 Vector3D(0,0,0), 1.57f, 0, 1).second, 0.414214f, 0.01f);
244 Vector3D(0,0,0), 1.57f, 0, 1).second, 1.0f, 0.01f);
246 Vector3D(0,0,0), 1.57f, 0, 1).second, 1.0f, 0.01f);
248 Vector3D(0,0,0), 1.57f, 0, 1).second, 1.0f, 0.01f);
251TEST(geom, right_handed_vector3d_boundary_negation) {
253 const Vector3D lh{1.0f, 2.0f, 3.0f};
255 ASSERT_FLOAT_EQ(rh.x, 1.0f);
256 ASSERT_FLOAT_EQ(rh.y, -2.0f);
257 ASSERT_FLOAT_EQ(rh.z, 3.0f);
261 ASSERT_FLOAT_EQ(round_trip.
x, 1.0f);
262 ASSERT_FLOAT_EQ(round_trip.
y, 2.0f);
263 ASSERT_FLOAT_EQ(round_trip.
z, 3.0f);
266TEST(geom, quaternion_default_is_identity) {
268 ASSERT_FLOAT_EQ(q.
x, 0.0f);
269 ASSERT_FLOAT_EQ(q.
y, 0.0f);
270 ASSERT_FLOAT_EQ(q.
z, 0.0f);
271 ASSERT_FLOAT_EQ(q.
w, 1.0f);
276 ASSERT_NEAR(out.
x, v.x, 1e-5f);
277 ASSERT_NEAR(out.
y, v.y, 1e-5f);
278 ASSERT_NEAR(out.
z, v.z, 1e-5f);
281TEST(geom, quaternion_get_forward_matches_rotation_get_forward) {
285 constexpr float eps = 1e-4f;
286 const float angles[] = {-180.0f, -90.0f, -45.0f, 0.0f, 30.0f, 90.0f, 123.0f, 180.0f};
287 for (
const float a : angles) {
288 for (
const auto axis : {0, 1, 2}) {
290 if (axis == 0) r.
pitch = a;
291 else if (axis == 1) r.yaw = a;
294 const Vector3D r_forward = r.GetForwardVector();
296 EXPECT_NEAR(q_forward.
x, r_forward.
x, eps) <<
"axis=" << axis <<
" angle=" << a;
297 EXPECT_NEAR(q_forward.
y, r_forward.
y, eps) <<
"axis=" << axis <<
" angle=" << a;
298 EXPECT_NEAR(q_forward.
z, r_forward.
z, eps) <<
"axis=" << axis <<
" angle=" << a;
303TEST(geom, quaternion_get_yaw_round_trip) {
306 constexpr float eps = 1e-3f;
307 for (
float yaw_deg = -150.0f; yaw_deg <= 150.0f; yaw_deg += 30.0f) {
310 EXPECT_NEAR(r.
yaw, yaw_deg, eps) <<
"yaw=" << yaw_deg;
311 EXPECT_NEAR(r.
pitch, 0.0f, eps);
312 EXPECT_NEAR(r.
roll, 0.0f, eps);
316TEST(geom, quaternion_inverse_is_left_inverse) {
319 constexpr float eps = 1e-4f;
325 {15.0f, 25.0f, 10.0f},
326 {-45.0f, 90.0f, -30.0f},
328 for (
const auto &r : samples) {
331 EXPECT_NEAR(identity.
x, 0.0f, eps) << r.pitch <<
"/" << r.yaw <<
"/" << r.roll;
332 EXPECT_NEAR(identity.
y, 0.0f, eps);
333 EXPECT_NEAR(identity.
z, 0.0f, eps);
334 EXPECT_NEAR(std::abs(identity.
w), 1.0f, eps);
338TEST(geom, quaternion_pitch_90_forward_is_positive_z) {
343 const Vector3D forward = q.GetForwardVector();
344 EXPECT_NEAR(forward.
x, 0.0f, 1e-5f);
345 EXPECT_NEAR(forward.
y, 0.0f, 1e-5f);
346 EXPECT_NEAR(forward.
z, 1.0f, 1e-5f);
349TEST(geom, engine_convention_pitch_up_roll_right_side_down) {
358 constexpr float eps = 1e-5f;
360 const Rotation pitched{20.0f, 0.0f, 0.0f};
361 const Vector3D forward = pitched.GetForwardVector();
362 EXPECT_GT(forward.
z, 0.0f);
365 const Rotation rolled{0.0f, 0.0f, 25.0f};
366 const Vector3D right = rolled.GetRightVector();
367 EXPECT_LT(right.
z, 0.0f);
372 const Vector3D up = rolled.GetUpVector();
373 EXPECT_GT(up.
y, 0.0f);
377TEST(geom, get_matrix_agrees_with_rotate_vector_and_basis_vectors) {
382 constexpr float eps = 1e-4f;
386 {-20.0f, 0.0f, 0.0f},
388 {0.0f, 0.0f, -25.0f},
389 {13.0f, 47.0f, -31.0f},
390 {-62.0f, -155.0f, 88.0f},
393 {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
395 for (
const auto &r : samples) {
397 const std::array<float, 16> m = t.GetMatrix();
399 r.GetForwardVector(), r.GetRightVector(), r.GetUpVector()};
405 for (
int col = 0; col < 3; ++col) {
406 const Vector3D rotated = r.RotateVector(axes[col]);
408 const float mx = m[
static_cast<size_t>(col)];
409 const float my = m[
static_cast<size_t>(4 + col)];
410 const float mz = m[
static_cast<size_t>(8 + col)];
411 EXPECT_NEAR(mx, rotated.
x, eps) <<
"col=" << col;
412 EXPECT_NEAR(my, rotated.
y, eps) <<
"col=" << col;
413 EXPECT_NEAR(mz, rotated.
z, eps) <<
"col=" << col;
414 EXPECT_NEAR(basis[col].
x, rotated.
x, eps) <<
"col=" << col;
415 EXPECT_NEAR(basis[col].
y, rotated.
y, eps) <<
"col=" << col;
416 EXPECT_NEAR(basis[col].
z, rotated.
z, eps) <<
"col=" << col;
417 EXPECT_NEAR(q_basis[col].
x, rotated.
x, eps) <<
"col=" << col;
418 EXPECT_NEAR(q_basis[col].
y, rotated.
y, eps) <<
"col=" << col;
419 EXPECT_NEAR(q_basis[col].
z, rotated.
z, eps) <<
"col=" << col;
424TEST(geom, get_inverse_matrix_is_inverse_of_get_matrix) {
427 constexpr float eps = 1e-3f;
433 for (
const auto &t : samples) {
434 const std::array<float, 16> m = t.GetMatrix();
435 const std::array<float, 16> mi = t.GetInverseMatrix();
436 for (
int row = 0; row < 4; ++row) {
437 for (
int col = 0; col < 4; ++col) {
439 for (
int k = 0; k < 4; ++k) {
440 acc += mi[
static_cast<size_t>(row * 4 + k)] *
441 m[
static_cast<size_t>(k * 4 + col)];
443 EXPECT_NEAR(acc, (row == col) ? 1.0f : 0.0f, eps)
444 <<
"row=" << row <<
" col=" << col;
450TEST(geom, inverse_rotate_vector_undoes_rotate_vector) {
451 constexpr float eps = 1e-4f;
453 {20.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 25.0f}, {13.0f, 47.0f, -31.0f}};
454 for (
const auto &r : samples) {
455 const Vector3D v{1.0f, -2.0f, 3.0f};
457 r.RotateVector(round_trip);
458 r.InverseRotateVector(round_trip);
459 EXPECT_NEAR(round_trip.
x, v.x, eps);
460 EXPECT_NEAR(round_trip.
y, v.y, eps);
461 EXPECT_NEAR(round_trip.
z, v.z, eps);
465TEST(geom, velocity_inherits_vector3d_storage) {
469 const Velocity v{1.5f, -2.0f, 0.25f};
470 EXPECT_FLOAT_EQ(v.x, 1.5f);
471 EXPECT_FLOAT_EQ(v.y, -2.0f);
472 EXPECT_FLOAT_EQ(v.z, 0.25f);
476 EXPECT_FLOAT_EQ(v2.
x, 2.0f);
477 EXPECT_FLOAT_EQ(v2.
y, -1.0f);
478 EXPECT_FLOAT_EQ(v2.
z, 0.25f);
481TEST(geom, angular_velocity_and_acceleration_inherit_vector3d_storage) {
483 EXPECT_FLOAT_EQ(w.x, 45.0f);
484 EXPECT_FLOAT_EQ(w.y, 0.0f);
487 EXPECT_FLOAT_EQ(a.y, 9.81f);
492 "Velocity must stay layout-compatible with Vector3D");
494 "AngularVelocity must stay layout-compatible with Vector3D");
496 "Acceleration must stay layout-compatible with Vector3D");
499TEST(geom, quaternion_basis_vectors_for_identity) {
502 constexpr float eps = 1e-5f;
506 EXPECT_NEAR(forward.
x, 1.0f, eps);
507 EXPECT_NEAR(forward.
y, 0.0f, eps);
508 EXPECT_NEAR(forward.
z, 0.0f, eps);
511 EXPECT_NEAR(right.
x, 0.0f, eps);
512 EXPECT_NEAR(right.
y, 1.0f, eps);
513 EXPECT_NEAR(right.
z, 0.0f, eps);
516 EXPECT_NEAR(up.
x, 0.0f, eps);
517 EXPECT_NEAR(up.
y, 0.0f, eps);
518 EXPECT_NEAR(up.
z, 1.0f, eps);
521TEST(geom, quaternion_basis_vectors_for_yaw_90) {
524 constexpr float eps = 1e-4f;
527 const Vector3D forward = q.GetForwardVector();
528 EXPECT_NEAR(forward.
x, 0.0f, eps);
529 EXPECT_NEAR(forward.
y, 1.0f, eps);
530 EXPECT_NEAR(forward.
z, 0.0f, eps);
532 const Vector3D right = q.GetRightVector();
533 EXPECT_NEAR(right.
x, -1.0f, eps);
534 EXPECT_NEAR(right.
y, 0.0f, eps);
535 EXPECT_NEAR(right.
z, 0.0f, eps);
537 const Vector3D up = q.GetUpVector();
538 EXPECT_NEAR(up.
x, 0.0f, eps);
539 EXPECT_NEAR(up.
y, 0.0f, eps);
540 EXPECT_NEAR(up.
z, 1.0f, eps);
543TEST(geom, quaternion_hamilton_product_yaw_compose) {
546 constexpr float eps = 1e-4f;
551 EXPECT_NEAR(forward.
x, 0.0f, eps);
552 EXPECT_NEAR(forward.
y, 1.0f, eps);
553 EXPECT_NEAR(forward.
z, 0.0f, eps);
556TEST(geom, quaternion_conjugate_equals_inverse_for_unit_quaternion) {
560 constexpr float eps = 1e-5f;
566 {15.0f, 25.0f, 10.0f},
568 for (
const auto &r : samples) {
572 EXPECT_NEAR(qc.
x, qi.
x, eps) << r.pitch <<
"/" << r.yaw <<
"/" << r.roll;
573 EXPECT_NEAR(qc.
y, qi.
y, eps);
574 EXPECT_NEAR(qc.
z, qi.
z, eps);
575 EXPECT_NEAR(qc.
w, qi.
w, eps);
599 std::array<float, 16> MirrorY(
const std::array<float, 16> &m) {
600 std::array<float, 16> out{};
601 for (
int row = 0; row < 4; ++row) {
602 for (
int col = 0; col < 4; ++col) {
603 const float sign = ((row == 1) != (col == 1)) ? -1.0f : 1.0f;
604 out[
static_cast<size_t>(row * 4 + col)] =
605 sign * m[
static_cast<size_t>(row * 4 + col)];
623TEST(geom, right_handed_rotation_negates_pitch_and_yaw) {
627 const Rotation carla_rotation{20.0f, 30.0f, 10.0f};
629 EXPECT_FLOAT_EQ(flu.
roll, 10.0f);
630 EXPECT_FLOAT_EQ(flu.
pitch, -20.0f);
631 EXPECT_FLOAT_EQ(flu.
yaw, -30.0f);
639 EXPECT_FLOAT_EQ(back.
pitch, carla_rotation.pitch);
640 EXPECT_FLOAT_EQ(back.
yaw, carla_rotation.yaw);
641 EXPECT_FLOAT_EQ(back.
roll, carla_rotation.roll);
644TEST(geom, right_handed_location_mirrors_y) {
645 const Location carla_location{10.0f, 20.0f, 30.0f};
647 EXPECT_FLOAT_EQ(flu.
x, 10.0f);
648 EXPECT_FLOAT_EQ(flu.
y, -20.0f);
649 EXPECT_FLOAT_EQ(flu.
z, 30.0f);
652 EXPECT_FLOAT_EQ(back.
x, carla_location.x);
653 EXPECT_FLOAT_EQ(back.
y, carla_location.y);
654 EXPECT_FLOAT_EQ(back.
z, carla_location.z);
657TEST(geom, right_handed_transform_round_trips) {
658 constexpr float eps = 1e-4f;
659 for (
const auto &t : kBoundarySamples) {
661 EXPECT_FLOAT_EQ(flu.
location.
x, t.location.x);
662 EXPECT_FLOAT_EQ(flu.
location.
y, -t.location.y);
663 EXPECT_FLOAT_EQ(flu.
location.
z, t.location.z);
666 EXPECT_FLOAT_EQ(flu.
rotation.
yaw, -t.rotation.yaw);
669 EXPECT_NEAR(back.
location.
x, t.location.x, eps);
670 EXPECT_NEAR(back.
location.
y, t.location.y, eps);
671 EXPECT_NEAR(back.
location.
z, t.location.z, eps);
673 EXPECT_NEAR(back.
rotation.
yaw, t.rotation.yaw, eps);
678TEST(geom, right_handed_matrix_is_s_m_s) {
682 constexpr float eps = 1e-5f;
683 for (
const auto &t : kBoundarySamples) {
684 const std::array<float, 16> expected = MirrorY(t.GetMatrix());
685 const std::array<float, 16> actual = t.ToRightHanded().GetMatrix();
686 for (
size_t i = 0; i < 16; ++i) {
687 EXPECT_NEAR(actual[i], expected[i], eps)
688 <<
"element " << i <<
" for rotation " << t.rotation.pitch <<
"/"
689 << t.rotation.yaw <<
"/" << t.rotation.roll;
694TEST(geom, right_handed_matrix_is_a_proper_rotation) {
698 constexpr float eps = 1e-4f;
699 for (
const auto &t : kBoundarySamples) {
700 const std::array<float, 16> m = t.ToRightHanded().GetMatrix();
702 m[0] * (m[5] * m[10] - m[6] * m[9]) -
703 m[1] * (m[4] * m[10] - m[6] * m[8]) +
704 m[2] * (m[4] * m[9] - m[5] * m[8]);
705 EXPECT_NEAR(det, 1.0f, eps);
709TEST(geom, right_handed_quaternion_agrees_with_ros2_bridge) {
713 constexpr float eps = 1e-5f;
714 for (
const auto &t : kBoundarySamples) {
718 t.location.x, t.location.y, t.location.z,
719 t.rotation.pitch, t.rotation.yaw, t.rotation.roll);
721 EXPECT_NEAR(flu.
location.
x, bridge.translation[0], eps);
722 EXPECT_NEAR(flu.
location.
y, bridge.translation[1], eps);
723 EXPECT_NEAR(flu.
location.
z, bridge.translation[2], eps);
725 EXPECT_NEAR(q.
w, bridge.rotation[0], eps) <<
"w";
726 EXPECT_NEAR(q.
x, bridge.rotation[1], eps) <<
"x";
727 EXPECT_NEAR(q.
y, bridge.rotation[2], eps) <<
"y";
728 EXPECT_NEAR(q.
z, bridge.rotation[3], eps) <<
"z";
732TEST(geom, right_handed_quaternion_reproduces_right_handed_matrix) {
735 constexpr float eps = 1e-4f;
741 for (
const auto &t : kBoundarySamples) {
743 const std::array<float, 16> m = flu.
GetMatrix();
745 for (
int col = 0; col < 3; ++col) {
748 EXPECT_NEAR(m[
static_cast<size_t>(col)], rotated.
x, eps) <<
"col=" << col;
749 EXPECT_NEAR(m[
static_cast<size_t>(4 + col)], rotated.
y, eps) <<
"col=" << col;
750 EXPECT_NEAR(m[
static_cast<size_t>(8 + col)], rotated.
z, eps) <<
"col=" << col;
755TEST(geom, quaternion_right_handed_rotation_round_trips) {
758 constexpr float eps = 1e-3f;
761 {10.0f, -20.0f, -30.0f},
762 {-40.0f, 15.0f, 120.0f},
763 {88.0f, -62.0f, -155.0f},
765 for (
const auto &r : samples) {
767 EXPECT_NEAR(back.
roll, r.roll, eps);
768 EXPECT_NEAR(back.
pitch, r.pitch, eps);
769 EXPECT_NEAR(back.
yaw, r.yaw, eps);
773TEST(geom, right_handed_boundary_leaves_engine_convention_untouched) {
778 constexpr float eps = 1e-5f;
780 const Rotation pitched{20.0f, 0.0f, 0.0f};
781 EXPECT_NEAR(pitched.GetForwardVector().z, std::sin(
Math::ToRadians(20.0f)), eps);
782 EXPECT_FLOAT_EQ(pitched.ToRightHanded().pitch, -20.0f);
784 const Rotation rolled{0.0f, 0.0f, 25.0f};
785 EXPECT_NEAR(rolled.GetRightVector().z, -std::sin(
Math::ToRadians(25.0f)), eps);
786 EXPECT_FLOAT_EQ(rolled.ToRightHanded().roll, 25.0f);
std::array< Location, 8 > GetLocalVertices() const
Returns the positions of the 8 vertices of this BoundingBox in local space.
std::array< Location, 8 > GetWorldVertices(const Transform &in_bbox_to_world_tr) const
Returns the positions of the 8 vertices of this BoundingBox in world space.
static constexpr T ToRadians(T deg)
static std::pair< float, float > DistanceSegmentToPoint(const Vector3D &p, const Vector3D &v, const Vector3D &w)
Returns a pair containing:
static auto Distance(const Vector3D &a, const Vector3D &b)
static std::pair< float, float > DistanceArcToPoint(Vector3D p, Vector3D start_pos, float length, float heading, float curvature)
Returns a pair containing:
Quaternion representing a 3D rotation, stored as (x, y, z, w).
Quaternion Conjugate() const
Conjugate of this quaternion.
Vector3D GetRightVector() const
Unit vector pointing toward the local Y axis of this rotation, expressed in CARLA's left-handed frame...
RightHandedRotation ToRightHandedRotation() const
This rotation as right-handed (FLU) Euler angles, degrees, intrinsic Z-Y-X.
Vector3D GetForwardVector() const
Unit vector pointing toward the local X axis of this rotation, expressed in CARLA's left-handed frame...
RightHandedVector3D RotatedVector(const RightHandedVector3D &in) const
Rotate a right-handed vector by this quaternion.
Quaternion Inverse() const
Inverse of this quaternion (assumes non-zero norm).
Vector3D GetUpVector() const
Unit vector pointing toward the local Z axis of this rotation, expressed in CARLA's left-handed frame...
Euler angles of a rotation in CARLA's / Unreal's left-handed frame: x forward, y right,...
static constexpr Rotation FromRightHanded(const RightHandedRotation &rhs)
Inverse of ToRightHanded().
Vector3D GetForwardVector() const
std::ostream & operator<<(std::ostream &out, const Vector3D &vector3D)
TransformQuaternion TransformFromCarlaRotation(float tx, float ty, float tz, float pitch_deg, float yaw_deg, float roll_deg) noexcept
This file contains definitions of common data structures used in traffic manager.
Linear acceleration in metres per second squared.
Angular velocity in degrees per second.
static constexpr Location FromRightHanded(const RightHandedVector3D &rhs)
Inverse of ToRightHanded().
Euler angles of a rotation expressed in a right-handed frame, in degrees.
float yaw
Rotation about the up (+Z) axis, degrees, right-hand rule.
float roll
Rotation about the forward (+X) axis, degrees, right-hand rule.
float pitch
Rotation about the left (+Y) axis, degrees, right-hand rule.
Internal adapter that holds a Vector3D in a right-handed coordinate frame.
Linear velocity in metres per second.
TEST(geom, single_point_no_transform)