/
spivag
/
command_occ
Обзор
Документация
Войти
/
spivag
/
command_occ
Код
Запросы
1
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
initial
tests/gtest_r3.cpp
1 171 строка
43 KB
Spivakov
Initial
10 апр 2026, 13:45
10 апр 2026, 13:45
b2ad868
Код
Авторство
О чём код?
/// @file gtest_r3.cpp /// @brief R³ primitives tests /// @project gtests /// /// (c) Alexander Spivakov on 02.09.2025. /// #include <geometry_types.h> #include <c3d_bridge.hxx> #include <gtest/gtest.h> TEST( R3Point, DefaultCts ) { const R3::Point pnt{}; ASSERT_NEAR( 0., pnt.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., pnt.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., pnt.z(), R1::Distance::Epsilon() ); } TEST( R3Point, CartesianCtor ) { const R3::Point pnt{ 7., -40.8, 6. }; ASSERT_NEAR( 7., pnt.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( -40.8, pnt.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 6., pnt.z(), R1::Distance::Epsilon() ); } TEST( R3Point, CopyCtor ) { const R3::Point pnt{ 7., -40.8, 21. }; const R3::Point pntCopy{ pnt }; const R3::Point pntAssign = pnt; ASSERT_NEAR( pntCopy.x(), pnt.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( pntCopy.y(), pnt.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( pntCopy.z(), pnt.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( pntAssign.x(), pnt.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( pntAssign.y(), pnt.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( pntAssign.z(), pnt.z(), R1::Distance::Epsilon() ); } //TEST( R3Point, Move ) //{ // R3::Point p{}; // R3::Point pInitial = p += R3::Vector::oz(); // ASSERT_NEAR( 0., p.x(), R1::Distance::Epsilon() ); // ASSERT_NEAR( 0., p.y(), R1::Distance::Epsilon() ); // ASSERT_NEAR( 1., p.z(), R1::Distance::Epsilon() ); // ASSERT_NEAR( 0., pInitial.x(), R1::Distance::Epsilon() ); // ASSERT_NEAR( 0., pInitial.y(), R1::Distance::Epsilon() ); // ASSERT_NEAR( 0., pInitial.z(), R1::Distance::Epsilon() ); //} TEST( R3Point, CylinderCtor ) { const R3::Point pnt{ R3::Point::Cylindrical{ R1::Distance{ 3. }, R1::Angle( R1::Angle::Degrees{ 60. } ), 5. } }; ASSERT_NEAR( 3. * 0.5 , pnt.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3. * 0.5 * sqrt( 3. ), pnt.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 5., pnt.z(), R1::Distance::Epsilon() ); } TEST( R3Point, PolarCtor ) { const R3::Point pnt{ R3::Point::Polar{ R1::Distance{ 3. }, R1::Angle( R1::Angle::Degrees{ 60. } ), R1::AngleModPi( R1::Angle::Degrees{ -30. } ) } }; ASSERT_NEAR( 3. * 0.25 * sqrt(3.), pnt.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3. * 0.25 * 3., pnt.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( -3. * 0.5, pnt.z(), R1::Distance::Epsilon() ); } TEST(R3Vector, DefaultCts) { const R3::Vector vec{}; ASSERT_NEAR(0., vec.x(), R1::Distance::Epsilon()); ASSERT_NEAR(0., vec.y(), R1::Distance::Epsilon()); ASSERT_NEAR( 0., vec.z(), R1::Distance::Epsilon() ); } TEST(R3Vector, CartesianCtor) { const R3::Vector vec{7., -40.8, 4.}; ASSERT_NEAR(7., vec.x(), R1::Distance::Epsilon()); ASSERT_NEAR(-40.8, vec.y(), R1::Distance::Epsilon()); ASSERT_NEAR( 4., vec.z(), R1::Distance::Epsilon() ); } TEST( R3Vector, CopyCtor ) { const R3::Vector vec{ 7., -40.8, 1. }; R3::Vector r2vecCopy{ vec }; R3::Vector r2vecAssign = vec; ASSERT_NEAR( r2vecCopy.x(), vec.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( r2vecCopy.y(), vec.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( r2vecCopy.z(), vec.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( r2vecAssign.x(), vec.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( r2vecAssign.y(), vec.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( r2vecAssign.z(), vec.z(), R1::Distance::Epsilon() ); } // // // TEST(R2Vector, PolarCtor) //{ // R2::Vector vec{ R1::Angle{R1::Angle::Degrees{150.}} }; // ASSERT_NEAR( -0.5 * sqrt(3.), vec.x(), R1::Distance::Epsilon()); // ASSERT_NEAR( 0.5, vec.y(), R1::Distance::Epsilon()); // } // // TEST(R2Vector, PointsCtor) //{ // R2::StartPoint startPt{11., -3.}; // R2::EndPoint endPt{ -6., -5.5 }; // R2::Vector vec{ startPt, endPt }; // ASSERT_NEAR(-17., vec.x(), R1::Distance::Epsilon()); // ASSERT_NEAR(-2.5, vec.y(), R1::Distance::Epsilon()); // } TEST( R3Vector, Predefined ) { ASSERT_NEAR( 1., R3::Vector::ox().x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., R3::Vector::ox().y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., R3::Vector::ox().z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., R3::Vector::oy().x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., R3::Vector::oy().y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., R3::Vector::oy().z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., R3::Vector::oz().x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., R3::Vector::oz().y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., R3::Vector::oz().z(), R1::Distance::Epsilon() ); } TEST( R3Vector, Move ) { R3::Vector p{ 5., 2., 6. }; R3::Vector pInitial{ p }; p += R3::Vector::ox(); ASSERT_NEAR( 6., p.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., p.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 5., pInitial.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., pInitial.y(), R1::Distance::Epsilon() ); } // ============= R3Transform tests ============= TEST( R3Transform, DefaultConstructor ) { const R3::Transform trns{}; ASSERT_NEAR( 0., trns.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., trns.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., trns.m_origin.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., trns.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., trns.m_ox.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., trns.m_ox.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., trns.m_oy.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., trns.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., trns.m_oy.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., trns.m_oz.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., trns.m_oz.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., trns.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3Transform, TranslationConstructor ) { const R3::Point origin{ 1., 2., 3. }; const R3::Transform trns{ origin }; ASSERT_NEAR( 1., trns.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., trns.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3., trns.m_origin.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., trns.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., trns.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., trns.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3Transform, FullConstructor ) { const R3::Point origin{ 1., 2., 3. }; const R3::Vector ox{ 2., 0., 0. }; const R3::Vector oy{ 0., 3., 0. }; const R3::Vector oz{ 0., 0., 4. }; const R3::Transform trns{ origin, ox, oy, oz }; ASSERT_NEAR( 1., trns.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., trns.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3., trns.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 4., trns.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3Transform, World ) { const R3::Transform world = R3::Transform::World(); ASSERT_NEAR( 0., world.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., world.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., world.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., world.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3Transform, ApplyPointIdentity ) { const R3::Transform identity = R3::Transform::World(); const R3::Point point{ 2., 3., 4. }; const R3::Point result = identity.Apply( point ); ASSERT_NEAR( 2., result.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3., result.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 4., result.z(), R1::Distance::Epsilon() ); } TEST( R3Transform, ApplyPointTranslation ) { const R3::Transform translation{ R3::Point{ 1., 2., 3. } }; const R3::Point point{ 1., 1., 1. }; const R3::Point result = translation.Apply( point ); ASSERT_NEAR( 2., result.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3., result.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 4., result.z(), R1::Distance::Epsilon() ); } TEST( R3Transform, ApplyPointScaling ) { const R3::Transform scaling{ R3::Point{}, R3::Vector{ 2., 0., 0. }, R3::Vector{ 0., 3., 0. }, R3::Vector{ 0., 0., 4. } }; const R3::Point point{ 1., 1., 1. }; const R3::Point result = scaling.Apply( point ); ASSERT_NEAR( 2., result.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3., result.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 4., result.z(), R1::Distance::Epsilon() ); } TEST( R3Transform, ApplyVectorIdentity ) { const R3::Transform identity = R3::Transform::World(); const R3::Vector r3ver{ 2., 3., 4. }; const R3::Vector result = identity.Apply( r3ver ); ASSERT_NEAR( 2., result.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3., result.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 4., result.z(), R1::Distance::Epsilon() ); } TEST( R3Transform, ApplyVectorTranslation ) { const R3::Transform translation{ R3::Point{ 10., 20., 30. } }; const R3::Vector r3ver{ 1., 2., 3. }; const R3::Vector result = translation.Apply( r3ver ); ASSERT_NEAR( 1., result.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., result.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3., result.z(), R1::Distance::Epsilon() ); } TEST( R3Transform, ApplyVectorScaling ) { const R3::Transform scaling{ R3::Point{}, R3::Vector{ 2., 0., 0. }, R3::Vector{ 0., 0.5, 0. }, R3::Vector{ 0., 0., 3. } }; const R3::Vector r3ver{ 2., 4., 1. }; const R3::Vector result = scaling.Apply( r3ver ); ASSERT_NEAR( 4., result.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., result.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3., result.z(), R1::Distance::Epsilon() ); } TEST( R3Transform, CopyConstructor ) { const R3::Transform original{ R3::Point{ 1., 2., 3. }, R3::Vector{ 1., 0., 0. }, R3::Vector{ 0., 1., 0. }, R3::Vector{ 0., 0., 1. } }; const R3::Transform copy{ original }; ASSERT_NEAR( original.m_origin.x(), copy.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_ox.x(), copy.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oy.y(), copy.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oz.z(), copy.m_oz.z(), R1::Distance::Epsilon() ); } // ============= R3Transform::operator* Extended tests ============= TEST( R3TransformMultiply, IdentityRight ) { // T * I = T const R3::Transform t{ R3::Point{ 1., 2., 3. }, R3::Vector{ 2., 0., 0. }, R3::Vector{ 0., 3., 0. }, R3::Vector{ 0., 0., 4. } }; const R3::Transform identity = R3::Transform::World(); const R3::Transform result = t * identity; ASSERT_NEAR( 1., result.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., result.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3., result.m_origin.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., result.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3., result.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 4., result.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, IdentityLeft ) { // I * T = T const R3::Transform t{ R3::Point{ 1., 2., 3. }, R3::Vector{ 2., 0., 0. }, R3::Vector{ 0., 3., 0. }, R3::Vector{ 0., 0., 4. } }; const R3::Transform identity = R3::Transform::World(); const R3::Transform result = identity * t; ASSERT_NEAR( 1., result.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., result.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3., result.m_origin.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., result.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3., result.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 4., result.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, TranslationComposition ) { // Проверяем последовательное применение двух смещений const R3::Transform t1{ R3::Point{ 1., 0., 0. } }; const R3::Transform t2{ R3::Point{ 0., 2., 0. } }; const R3::Transform result = t1 * t2; // Ожидаем смещение (1, 2, 0) ASSERT_NEAR( 1., result.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., result.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_origin.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., result.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., result.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., result.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, ScalingComposition ) { // Проверяем последовательное применение двух масштабирований const R3::Transform scale1{ R3::Point{}, R3::Vector{ 2., 0., 0. }, R3::Vector{ 0., 2., 0. }, R3::Vector{ 0., 0., 2. } }; const R3::Transform scale2{ R3::Point{}, R3::Vector{ 3., 0., 0. }, R3::Vector{ 0., 3., 0. }, R3::Vector{ 0., 0., 3. } }; const R3::Transform result = scale1 * scale2; // Ожидаем масштаб 6 по всем осям ASSERT_NEAR( 6., result.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 6., result.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 6., result.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, TranslationThenScaling ) { // Сначала смещение, затем масштабирование const R3::Transform translation{ R3::Point{ 1., 2., 3. } }; const R3::Transform scaling{ R3::Point{}, R3::Vector{ 2., 0., 0. }, R3::Vector{ 0., 2., 0. }, R3::Vector{ 0., 0., 2. } }; const R3::Transform result = scaling * translation; // Ожидаем масштабирование начала координат: (1,2,3) * 2 = (2,4,6) ASSERT_NEAR( 2., result.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 4., result.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 6., result.m_origin.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., result.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., result.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., result.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, ScalingThenTranslation ) { // Сначала масштабирование, затем смещение const R3::Transform scaling{ R3::Point{}, R3::Vector{ 2., 0., 0. }, R3::Vector{ 0., 2., 0. }, R3::Vector{ 0., 0., 2. } }; const R3::Transform translation{ R3::Point{ 1., 2., 3. } }; const R3::Transform result = translation * scaling; // Ожидаем смещение (1,2,3) без масштабирования начала координат ASSERT_NEAR( 1., result.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., result.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 3., result.m_origin.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., result.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., result.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 2., result.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, NonUniformScaling ) { // Неравномерное масштабирование по осям const R3::Transform scale1{ R3::Point{}, R3::Vector{ 2., 0., 0. }, R3::Vector{ 0., 3., 0. }, R3::Vector{ 0., 0., 4. } }; const R3::Transform scale2{ R3::Point{}, R3::Vector{ 0.5, 0., 0. }, R3::Vector{ 0., 2., 0. }, R3::Vector{ 0., 0., 0.25 } }; const R3::Transform result = scale1 * scale2; ASSERT_NEAR( 1., result.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 6., result.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., result.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, ComplexComposition ) { // Сложная последовательность преобразований // t1 * t2 * t3 означает: сначала t3, затем t2, затем t1 const R3::Transform t1{ R3::Point{ 1., 0., 0. }, R3::Vector{ 1., 0., 0. }, R3::Vector{ 0., 1., 0. }, R3::Vector{ 0., 0., 1. } }; const R3::Transform t2{ R3::Point{ 0., 2., 0. }, R3::Vector{ 2., 0., 0. }, R3::Vector{ 0., 2., 0. }, R3::Vector{ 0., 0., 2. } }; const R3::Transform t3{ R3::Point{ 0., 0., 3. }, R3::Vector{ 1., 0., 0. }, R3::Vector{ 0., 1., 0. }, R3::Vector{ 0., 0., 1. } }; const R3::Transform result = t1 * t2 * t3; // Проверяем правильность композиции через пошаговое применение const R3::Transform temp = t2 * t3; const R3::Transform expected = t1 * temp; ASSERT_NEAR( expected.m_origin.x(), result.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( expected.m_origin.y(), result.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( expected.m_origin.z(), result.m_origin.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( expected.m_ox.x(), result.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( expected.m_oy.y(), result.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( expected.m_oz.z(), result.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, ApplyToPoint ) { // Проверяем, что T1 * T2 применяется к точке корректно const R3::Transform t1{ R3::Point{ 10., 0., 0. } }; const R3::Transform t2{ R3::Point{ 0., 0., 0. }, R3::Vector{ 2., 0., 0. }, R3::Vector{ 0., 2., 0. }, R3::Vector{ 0., 0., 2. } }; const R3::Point testPoint{ 1., 1., 1. }; // Вручную применяем последовательно T2, затем T1 const R3::Point afterT2 = t2.Apply( testPoint ); const R3::Point afterT1 = t1.Apply( afterT2 ); // Применяем композицию const R3::Transform composition = t1 * t2; const R3::Point result = composition.Apply( testPoint ); ASSERT_NEAR( afterT1.x(), result.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( afterT1.y(), result.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( afterT1.z(), result.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, ApplyToVector ) { // Проверяем, что T1 * T2 применяется к вектору корректно const R3::Transform t1{ R3::Point{ 100., 100., 100. }, // Смещение не должно влиять на вектор R3::Vector{ 3., 0., 0. }, R3::Vector{ 0., 3., 0. }, R3::Vector{ 0., 0., 3. } }; const R3::Transform t2{ R3::Point{ 50., 50., 50. }, // Смещение не должно влиять на вектор R3::Vector{ 2., 0., 0. }, R3::Vector{ 0., 2., 0. }, R3::Vector{ 0., 0., 2. } }; const R3::Vector testVector{ 1., 1., 1. }; // Вручную применяем последовательно T2, затем T1 const R3::Vector afterT2 = t2.Apply( testVector ); const R3::Vector afterT1 = t1.Apply( afterT2 ); // Применяем композицию const R3::Transform composition = t1 * t2; const R3::Vector result = composition.Apply( testVector ); ASSERT_NEAR( afterT1.x(), result.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( afterT1.y(), result.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( afterT1.z(), result.z(), R1::Distance::Epsilon() ); // Также проверим ожидаемые значения (масштаб 6) ASSERT_NEAR( 6., result.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 6., result.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 6., result.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, Associativity ) { // Проверяем ассоциативность: (T1 * T2) * T3 = T1 * (T2 * T3) const R3::Transform t1{ R3::Point{ 1., 0., 0. } }; const R3::Transform t2{ R3::Point{ 0., 2., 0. } }; const R3::Transform t3{ R3::Point{ 0., 0., 3. } }; const R3::Transform left = ( t1 * t2 ) * t3; const R3::Transform right = t1 * ( t2 * t3 ); ASSERT_NEAR( left.m_origin.x(), right.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( left.m_origin.y(), right.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( left.m_origin.z(), right.m_origin.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( left.m_ox.x(), right.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( left.m_oy.y(), right.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( left.m_oz.z(), right.m_oz.z(), R1::Distance::Epsilon() ); } // ============= R3Transform::operator* Rotation tests ============= TEST( R3TransformMultiply, RotationAroundZ_90deg ) { // Вращение на 90 градусов вокруг оси Z // X -> Y, Y -> -X, Z -> Z const R3::Transform rotZ90{ R3::Point{}, R3::Vector{ 0., 1., 0. }, // ox поворачивается на 90° в плоскости XY R3::Vector{ -1., 0., 0. }, // oy поворачивается на 90° в плоскости XY R3::Vector{ 0., 0., 1. } // oz остается неизменным }; const R3::Point testPoint{ 1., 0., 0. }; const R3::Point result = rotZ90.Apply( testPoint ); ASSERT_NEAR( 0., result.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., result.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, RotationAroundZ_TwoSequential90deg ) { // Два последовательных вращения на 90° вокруг Z = вращение на 180° const R3::Transform rotZ90{ R3::Point{}, R3::Vector{ 0., 1., 0. }, R3::Vector{ -1., 0., 0. }, R3::Vector{ 0., 0., 1. } }; const R3::Transform result = rotZ90 * rotZ90; // После двух поворотов на 90°: X -> -X, Y -> -Y, Z -> Z ASSERT_NEAR( -1., result.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_ox.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_ox.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_oy.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( -1., result.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_oy.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_oz.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_oz.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., result.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, RotationAroundZ_FourSequential90deg ) { // Четыре последовательных вращения на 90° вокруг Z = полный оборот (тождество) const R3::Transform rotZ90{ R3::Point{}, R3::Vector{ 0., 1., 0. }, R3::Vector{ -1., 0., 0. }, R3::Vector{ 0., 0., 1. } }; const R3::Transform result = rotZ90 * rotZ90 * rotZ90 * rotZ90; // Должны получить единичное преобразование ASSERT_NEAR( 1., result.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_ox.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., result.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_oy.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., result.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, RotationAroundX_90deg ) { // Вращение на 90 градусов вокруг оси X // X -> X, Y -> Z, Z -> -Y const R3::Transform rotX90{ R3::Point{}, R3::Vector{ 1., 0., 0. }, // ox остается неизменным R3::Vector{ 0., 0., 1. }, // oy поворачивается: Y -> Z R3::Vector{ 0., -1., 0. } // oz поворачивается: Z -> -Y }; const R3::Point testPoint{ 0., 1., 0. }; const R3::Point result = rotX90.Apply( testPoint ); ASSERT_NEAR( 0., result.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., result.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, RotationAroundY_90deg ) { // Вращение на 90 градусов вокруг оси Y // X -> -Z, Y -> Y, Z -> X const R3::Transform rotY90{ R3::Point{}, R3::Vector{ 0., 0., -1. }, // ox поворачивается: X -> -Z R3::Vector{ 0., 1., 0. }, // oy остается неизменным R3::Vector{ 1., 0., 0. } // oz поворачивается: Z -> X }; const R3::Point testPoint{ 1., 0., 0. }; const R3::Point result = rotY90.Apply( testPoint ); ASSERT_NEAR( 0., result.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( -1., result.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, RotationAroundXThenY ) { // Последовательное вращение: сначала вокруг Y на 90°, затем вокруг X на 90° const R3::Transform rotX90{ R3::Point{}, R3::Vector{ 1., 0., 0. }, R3::Vector{ 0., 0., 1. }, R3::Vector{ 0., -1., 0. } }; const R3::Transform rotY90{ R3::Point{}, R3::Vector{ 0., 0., -1. }, R3::Vector{ 0., 1., 0. }, R3::Vector{ 1., 0., 0. } }; const R3::Transform result = rotX90 * rotY90; // Проверяем применение к точке (1, 0, 0) const R3::Point testPoint{ 1., 0., 0. }; const R3::Point afterRotY = rotY90.Apply( testPoint ); // -> (0, 0, -1) const R3::Point afterBoth = rotX90.Apply( afterRotY ); // -> (0, 1, 0) const R3::Point resultPoint = result.Apply( testPoint ); ASSERT_NEAR( afterBoth.x(), resultPoint.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( afterBoth.y(), resultPoint.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( afterBoth.z(), resultPoint.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, RotationAroundYThenZ ) { // Последовательное вращение: сначала вокруг Z на 90°, затем вокруг Y на 90° const R3::Transform rotY90{ R3::Point{}, R3::Vector{ 0., 0., -1. }, R3::Vector{ 0., 1., 0. }, R3::Vector{ 1., 0., 0. } }; const R3::Transform rotZ90{ R3::Point{}, R3::Vector{ 0., 1., 0. }, R3::Vector{ -1., 0., 0. }, R3::Vector{ 0., 0., 1. } }; const R3::Transform result = rotY90 * rotZ90; // Проверяем применение к точке (1, 0, 0) const R3::Point testPoint{ 1., 0., 0. }; const R3::Point afterRotZ = rotZ90.Apply( testPoint ); // -> (0, 1, 0) const R3::Point afterBoth = rotY90.Apply( afterRotZ ); // -> (0, 1, 0) const R3::Point resultPoint = result.Apply( testPoint ); ASSERT_NEAR( afterBoth.x(), resultPoint.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( afterBoth.y(), resultPoint.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( afterBoth.z(), resultPoint.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, RotationAroundZThenX ) { // Последовательное вращение: сначала вокруг X на 90°, затем вокруг Z на 90° const R3::Transform rotZ90{ R3::Point{}, R3::Vector{ 0., 1., 0. }, R3::Vector{ -1., 0., 0. }, R3::Vector{ 0., 0., 1. } }; const R3::Transform rotX90{ R3::Point{}, R3::Vector{ 1., 0., 0. }, R3::Vector{ 0., 0., 1. }, R3::Vector{ 0., -1., 0. } }; const R3::Transform result = rotZ90 * rotX90; // Проверяем применение к точке (0, 1, 0) const R3::Point testPoint{ 0., 1., 0. }; const R3::Point afterRotX = rotX90.Apply( testPoint ); // -> (0, 0, 1) const R3::Point afterBoth = rotZ90.Apply( afterRotX ); // -> (0, 0, 1) const R3::Point resultPoint = result.Apply( testPoint ); ASSERT_NEAR( afterBoth.x(), resultPoint.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( afterBoth.y(), resultPoint.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( afterBoth.z(), resultPoint.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, TranslationThenRotationAroundZ ) { // Сначала смещение, затем вращение const R3::Transform translation{ R3::Point{ 1., 0., 0. } }; const R3::Transform rotZ90{ R3::Point{}, R3::Vector{ 0., 1., 0. }, R3::Vector{ -1., 0., 0. }, R3::Vector{ 0., 0., 1. } }; const R3::Transform result = rotZ90 * translation; // Начало координат (1, 0, 0) после вращения должно стать (0, 1, 0) ASSERT_NEAR( 0., result.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., result.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_origin.z(), R1::Distance::Epsilon() ); // Базисные векторы тоже повернуты ASSERT_NEAR( 0., result.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., result.m_ox.y(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, RotationAroundZThenTranslation ) { // Сначала вращение, затем смещение const R3::Transform rotZ90{ R3::Point{}, R3::Vector{ 0., 1., 0. }, R3::Vector{ -1., 0., 0. }, R3::Vector{ 0., 0., 1. } }; const R3::Transform translation{ R3::Point{ 1., 0., 0. } }; const R3::Transform result = translation * rotZ90; // Начало координат смещено на (1, 0, 0), базисные векторы повернуты ASSERT_NEAR( 1., result.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_origin.z(), R1::Distance::Epsilon() ); // Базисные векторы повернуты ASSERT_NEAR( 0., result.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., result.m_ox.y(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, ComplexRotationAndTranslation ) { // Комбинация: смещение -> вращение вокруг Z -> смещение const R3::Transform trans1{ R3::Point{ 1., 0., 0. } }; const R3::Transform rotZ90{ R3::Point{}, R3::Vector{ 0., 1., 0. }, R3::Vector{ -1., 0., 0. }, R3::Vector{ 0., 0., 1. } }; const R3::Transform trans2{ R3::Point{ 0., 1., 0. } }; const R3::Transform result = trans2 * rotZ90 * trans1; // Проверяем пошаговое применение к точке (0, 0, 0) const R3::Point origin{}; const R3::Point afterTrans1 = trans1.Apply( origin ); // -> (1, 0, 0) const R3::Point afterRot = rotZ90.Apply( afterTrans1 ); // -> (0, 1, 0) const R3::Point afterTrans2 = trans2.Apply( afterRot ); // -> (0, 2, 0) const R3::Point resultOrigin = result.Apply( origin ); ASSERT_NEAR( afterTrans2.x(), resultOrigin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( afterTrans2.y(), resultOrigin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( afterTrans2.z(), resultOrigin.z(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, RotationAroundX_Minus90deg ) { // Вращение на -90 градусов вокруг оси X (обратное вращению на +90°) // X -> X, Y -> -Z, Z -> Y const R3::Transform rotXMinus90{ R3::Point{}, R3::Vector{ 1., 0., 0. }, R3::Vector{ 0., 0., -1. }, R3::Vector{ 0., 1., 0. } }; const R3::Transform rotX90{ R3::Point{}, R3::Vector{ 1., 0., 0. }, R3::Vector{ 0., 0., 1. }, R3::Vector{ 0., -1., 0. } }; // Вращение на 90° и затем на -90° должно дать единичное преобразование const R3::Transform result = rotXMinus90 * rotX90; ASSERT_NEAR( 1., result.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., result.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 1., result.m_oz.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_ox.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_oy.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( 0., result.m_oz.x(), R1::Distance::Epsilon() ); } TEST( R3TransformMultiply, ThreeAxisRotationComposition ) { // Последовательное вращение вокруг всех трех осей на 90° const R3::Transform rotX90{ R3::Point{}, R3::Vector{ 1., 0., 0. }, R3::Vector{ 0., 0., 1. }, R3::Vector{ 0., -1., 0. } }; const R3::Transform rotY90{ R3::Point{}, R3::Vector{ 0., 0., -1. }, R3::Vector{ 0., 1., 0. }, R3::Vector{ 1., 0., 0. } }; const R3::Transform rotZ90{ R3::Point{}, R3::Vector{ 0., 1., 0. }, R3::Vector{ -1., 0., 0. }, R3::Vector{ 0., 0., 1. } }; const R3::Transform result = rotZ90 * rotY90 * rotX90; // Проверяем последовательное применение к точке (1, 0, 0) const R3::Point testPoint{ 1., 0., 0. }; const R3::Point afterX = rotX90.Apply( testPoint ); const R3::Point afterY = rotY90.Apply( afterX ); const R3::Point afterZ = rotZ90.Apply( afterY ); const R3::Point resultPoint = result.Apply( testPoint ); ASSERT_NEAR( afterZ.x(), resultPoint.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( afterZ.y(), resultPoint.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( afterZ.z(), resultPoint.z(), R1::Distance::Epsilon() ); } // TEST( R2Vector, Rotate ) //{ // R2::Point p{ R2::Point::Polar{ R1::Distance{ 10. }, R1::Angle02pi{ R1::Angle::Degrees{ 45. } } } }; // const R2::Point pCenter{ R2::Point::Polar{ R1::Distance{ 5. }, R1::Angle02pi{ R1::Angle::Degrees{ 45. } } } }; // p.RotateCcw( pCenter, R1::Angle{ R1::Angle::Degrees{ 180. } } ); // ASSERT_NEAR( 0., p.x(), R1::Distance::Epsilon() ); // ASSERT_NEAR( 0., p.y(), R1::Distance::Epsilon() ); // } // // // TEST(R2Placement, DefaultCtor) //{ // R2::Placement place{}; // ASSERT_NEAR( 0., place.Origin().x(), R1::Distance::Epsilon() ); // ASSERT_NEAR( 0., place.Origin().y(), R1::Distance::Epsilon() ); // ASSERT_NEAR( 1., place.Axis().x(), R1::Distance::Epsilon() ); // ASSERT_NEAR( 0., place.Axis().y(), R1::Distance::Epsilon() ); // } // // // TEST( R2Placement, CtorPoint ) //{ // const R2::Point center{ -11., 21.2 }; // R2::Placement place{ center }; // ASSERT_NEAR( center.x(), place.Origin().x(), R1::Distance::Epsilon() ); // ASSERT_NEAR( center.y(), place.Origin().y(), R1::Distance::Epsilon() ); // ASSERT_NEAR( 1., place.Axis().x(), R1::Distance::Epsilon() ); // ASSERT_NEAR( 0., place.Axis().y(), R1::Distance::Epsilon() ); // } // // // TEST( R2Placement, CtorPointAngle ) //{ // const R2::Point center{ -11., 21.2 }; // R2::Placement place{ center, R1::Angle{ R1::Angle::Degrees{45.} } }; // ASSERT_NEAR( center.x(), place.Origin().x(), R1::Distance::Epsilon() ); // ASSERT_NEAR( center.y(), place.Origin().y(), R1::Distance::Epsilon() ); // ASSERT_NEAR( sqrt(0.5), place.Axis().x(), R1::Distance::Epsilon() ); // ASSERT_NEAR( sqrt( 0.5 ), place.Axis().y(), R1::Distance::Epsilon() ); // } // // // TEST( R2Placement, Move ) //{ // R2::Placement place{ {}, R1::Angle{ R1::Angle::Degrees{ 45. } } }; // R2::Vector center{ 3., -56. }; // place += center; // ASSERT_NEAR( center.x(), place.Origin().x(), R1::Distance::Epsilon() ); // ASSERT_NEAR( center.y(), place.Origin().y(), R1::Distance::Epsilon() ); // ASSERT_NEAR( sqrt( 0.5 ), place.Axis().x(), R1::Distance::Epsilon() ); // ASSERT_NEAR( sqrt( 0.5 ), place.Axis().y(), R1::Distance::Epsilon() ); // } // // // TEST( R2Placement, Rotate ) //{ // R2::Placement place{ R2::Point{ 1., 0. }, R1::Angle{ R1::Angle::Degrees{ 45. } } }; // R2::Point center{ 1., 1. }; // place.RotateCcw( center, R1::Angle{ R1::Angle::Degrees{90.} } ); // ASSERT_NEAR( 2., place.Origin().x(), R1::Distance::Epsilon() ); // ASSERT_NEAR( 1., place.Origin().y(), R1::Distance::Epsilon() ); // ASSERT_NEAR( -sqrt( 0.5 ), place.Axis().x(), R1::Distance::Epsilon() ); // ASSERT_NEAR( sqrt( 0.5 ), place.Axis().y(), R1::Distance::Epsilon() ); // } // // // TEST( R2_Gabarit, DefaultConstructor ) //{ // R2::Gabarit r{}; // ASSERT_TRUE( r.IsEmpty() ); // ASSERT_FALSE( r.PointIn( R2::Point{} ) ); // } // ////TEST( R2_Gabarit, ConstructorOneValue ) ////{ //// for ( double value = -10.; value <= 10.0; value += 5.0 ) //// { //// R2::Gabarit r{ value }; //// ASSERT_TRUE( r.Contains( value ) ); //// ASSERT_FALSE( r.Contains( value + R1::Distance::Epsilon() ) ); //// ASSERT_FALSE( r.Contains( value - R1::Distance::Epsilon() ) ); //// ASSERT_FALSE( r.IsEmpty() ); //// } ////} //// ////TEST( R1_Range, ConstructorTwoValuesAscending ) ////{ //// R1::Range r{ 0., 10. }; //// ASSERT_TRUE( r.Contains( 3. ) ); //// ASSERT_FALSE( r.Contains( 12. ) ); //// ASSERT_FALSE( r.Contains( -120. ) ); //// ASSERT_FALSE( r.IsEmpty() ); ////} //// ////TEST( R1_Range, ConstructorTwoValuesDescending ) ////{ //// R1::Range r{ 10., 3. }; //// ASSERT_TRUE( r.Contains( 3. ) ); //// ASSERT_FALSE( r.Contains( 12. ) ); //// ASSERT_FALSE( r.Contains( -120. ) ); //// ASSERT_FALSE( r.IsEmpty() ); ////} // // TEST( R2_Gabarit, Empty ) //{ // R2::Gabarit r; // ASSERT_TRUE( r.IsEmpty() ); // r.Append( R2::Point{3., 3.} ); // ASSERT_FALSE( r.IsEmpty() ); // r.SetEmpty(); // ASSERT_TRUE( r.IsEmpty() ); //} // // TEST( R2_Gabarit, InterpositionNotAppliable ) //{ // const R2::Gabarit r1{}, r2{ R2::Point{} }; // ASSERT_EQ( Interposition::notAppliable, r1.InterpositionWith( r2 ) ); // ASSERT_EQ( Interposition::notAppliable, r2.InterpositionWith( r1 ) ); // ASSERT_EQ( Interposition::notAppliable, r1.InterpositionWith( r1 ) ); // ASSERT_NE( Interposition::notAppliable, r2.InterpositionWith( r2 ) ); //} // // TEST( R2_Gabarit, InterpositionSame ) //{ // const R2::Gabarit r1{ R2::Point{}, R2::Point{} }, r2{ R2::Point{} }; // ASSERT_EQ( Interposition::same, r1.InterpositionWith( r2 ) ); // ASSERT_EQ( Interposition::same, r2.InterpositionWith( r1 ) ); //} // // TEST( R2_Gbabrit, InterpositionConainsIncluded ) //{ // const R2::Gabarit r1{ R2::Point{ -10., -10. }, R2::Point{ 10., 10. } }, r2{ R2::Point{}, R2::Point{ 1., 1. } }; // ASSERT_EQ( Interposition::contains, r1.InterpositionWith( r2 ) ); // ASSERT_EQ( Interposition::included, r2.InterpositionWith( r1 ) ); //} // // TEST( R2_Gabarit, InterpositionIntersect ) //{ // const R2::Gabarit r1{ R2::Point{ -10., -10. }, R2::Point{ 10., 10. } }, r2{ R2::Point{}, R2::Point{ 18., 16. } }; // ASSERT_EQ( Interposition::intersected, r1.InterpositionWith( r2 ) ); // ASSERT_EQ( Interposition::intersected, r2.InterpositionWith( r1 ) ); //} // // TEST( R2_Gabarit, InterpositionIsolated ) //{ // const R2::Gabarit r1{ R2::Point{ -10., -10. }, R2::Point{ 10., 10. } }, r2{ R2::Point{ 16., 40. }, // R2::Point{ 18., 20. } }; ASSERT_EQ( Interposition::isolated, r1.InterpositionWith( r2 ) ); ASSERT_EQ( // Interposition::isolated, r2.InterpositionWith( r1 ) ); //} TEST( R3Transform, C3DBridgeIdentity ) { const R3::Transform original; const auto c3d = c3d_bridge::MakeC3dPlacement( original ); const auto restored = c3d_bridge::GetTransform( c3d ); // Verify origin ASSERT_NEAR( original.m_origin.x(), restored.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_origin.y(), restored.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_origin.z(), restored.m_origin.z(), R1::Distance::Epsilon() ); // Verify basis vectors ASSERT_NEAR( original.m_ox.x(), restored.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_ox.y(), restored.m_ox.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_ox.z(), restored.m_ox.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oy.x(), restored.m_oy.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oy.y(), restored.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oy.z(), restored.m_oy.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oz.x(), restored.m_oz.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oz.y(), restored.m_oz.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oz.z(), restored.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3Transform, C3DBridgeTranslation ) { const R3::Transform original( R3::Point{ 5., 10., 15. } ); const auto c3d = c3d_bridge::MakeC3dPlacement( original ); const auto restored = c3d_bridge::GetTransform( c3d ); // Verify origin ASSERT_NEAR( original.m_origin.x(), restored.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_origin.y(), restored.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_origin.z(), restored.m_origin.z(), R1::Distance::Epsilon() ); // Verify basis vectors (should be standard basis) ASSERT_NEAR( original.m_ox.x(), restored.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_ox.y(), restored.m_ox.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_ox.z(), restored.m_ox.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oy.x(), restored.m_oy.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oy.y(), restored.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oy.z(), restored.m_oy.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oz.x(), restored.m_oz.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oz.y(), restored.m_oz.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oz.z(), restored.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3Transform, C3DBridgeScaling ) { const R3::Vector ox{ 2., 0., 0. }; const R3::Vector oy{ 0., 3., 0. }; const R3::Vector oz{ 0., 0., 4. }; const R3::Transform original( R3::Point{}, ox, oy, oz ); const auto c3d = c3d_bridge::MakeC3dPlacement( original ); const auto restored = c3d_bridge::GetTransform( c3d ); // Verify origin ASSERT_NEAR( original.m_origin.x(), restored.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_origin.y(), restored.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_origin.z(), restored.m_origin.z(), R1::Distance::Epsilon() ); // Verify scaled basis vectors ASSERT_NEAR( original.m_ox.x(), restored.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_ox.y(), restored.m_ox.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_ox.z(), restored.m_ox.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oy.x(), restored.m_oy.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oy.y(), restored.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oy.z(), restored.m_oy.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oz.x(), restored.m_oz.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oz.y(), restored.m_oz.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oz.z(), restored.m_oz.z(), R1::Distance::Epsilon() ); } TEST( R3Transform, C3DBridgeRotation ) { // Create a transform with rotation: basis vectors rotated 45 degrees around Z axis const double sqrt2_2 = std::sqrt( 2. ) / 2.; const R3::Vector ox{ sqrt2_2, sqrt2_2, 0. }; const R3::Vector oy{ -sqrt2_2, sqrt2_2, 0. }; const R3::Vector oz{ 0., 0., 1. }; const R3::Point origin{ 1., 2., 3. }; const R3::Transform original( origin, ox, oy, oz ); const auto c3d = c3d_bridge::MakeC3dPlacement( original ); const auto restored = c3d_bridge::GetTransform( c3d ); // Verify origin ASSERT_NEAR( original.m_origin.x(), restored.m_origin.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_origin.y(), restored.m_origin.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_origin.z(), restored.m_origin.z(), R1::Distance::Epsilon() ); // Verify rotated basis vectors ASSERT_NEAR( original.m_ox.x(), restored.m_ox.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_ox.y(), restored.m_ox.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_ox.z(), restored.m_ox.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oy.x(), restored.m_oy.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oy.y(), restored.m_oy.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oy.z(), restored.m_oy.z(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oz.x(), restored.m_oz.x(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oz.y(), restored.m_oz.y(), R1::Distance::Epsilon() ); ASSERT_NEAR( original.m_oz.z(), restored.m_oz.z(), R1::Distance::Epsilon() ); }