// // Project: scccl // File: test/math/geom2d_test.cpp // Author: Kyle Isom // Date: 2017-06-05 // // geom2d_test runs a set of unit tests on the 2D parts of the // math::geom namespace. // // Copyright 2017 Kyle Isom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include #include #include using namespace scmp::geom; using namespace sctest; namespace { #define CHECK_ROTATE(theta, expected) if (!scmp::WithinTolerance(scmp::RotateRadians((double)theta, 0), (double)expected, (double)0.0001)) { \ std::cerr << "Expected " << theta << " to wrap to " << expected << "\n"; \ std::cerr << " have " << scmp::RotateRadians(theta, 0) << "\n"; \ return false; \ } bool geomValidateAngularRotation() { CHECK_ROTATE(0, 0); CHECK_ROTATE(M_PI/4, M_PI/4); CHECK_ROTATE(M_PI/2, M_PI/2); CHECK_ROTATE(3 * M_PI / 4, 3 * M_PI / 4); CHECK_ROTATE(M_PI, M_PI); CHECK_ROTATE(5 * M_PI / 4, -3 * M_PI / 4); CHECK_ROTATE(3 * M_PI / 2, -(M_PI / 2)); CHECK_ROTATE(7 * M_PI / 4, -(M_PI / 4)); CHECK_ROTATE(4 * M_PI, 0) return true; } bool geomConversionIdentities() { const std::array points = { Point2D(1, 0), Point2D(0, 1), Point2D(-1, 0), Point2D(0, -1) }; const std::array polars = { Polar2D(1, 0), Polar2D(1, scmp::DegreesToRadiansD(90)), Polar2D(1, scmp::DegreesToRadiansD(180)), Polar2D(1, scmp::DegreesToRadiansD(-90)), }; for (auto i = 0; i < 4; i++) { const Polar2D pol(points.at(i)); if (pol != polars.at(i)) { std::cerr << "! measured value outside tolerance (" << i << ")\n"; std::cerr << " " << points.at(i) << " → " << pol << " ← " << polars.at(i) << "\n"; return false; } const Point2D point(pol); SCTEST_CHECK(point == points.at(i)); } return true; } bool geomVerifyBasicProperties() { const Point2D pt1(1, 1); const Point2D pt2(2, 2); const Point2D pt3(3, 3); SCTEST_CHECK((pt1 + pt2) == pt3); SCTEST_CHECK((pt3 - pt2) == pt1); // commutative SCTEST_CHECK((pt1 + pt2) == (pt2 + pt1)); SCTEST_CHECK((pt1 + pt3) == (pt3 + pt1)); SCTEST_CHECK((pt2 + pt3) == (pt3 + pt2)); // associative SCTEST_CHECK(((pt1 + pt2) + pt3) == (pt1 + (pt2 + pt3))); // transitive const Point2D pt4(1, 1); const Point2D pt5(1, 1); SCTEST_CHECK(pt1 == pt4); SCTEST_CHECK(pt4 == pt5); SCTEST_CHECK(pt1 == pt5); // scaling const Point2D pt6(2, 3); const Point2D pt7(8, 12); SCTEST_CHECK((pt6 * 4) == pt7); return true; } bool geomComparePoint2D() { const Point2D pt1(1, 1); const Point2D pt2(1, 1); const Point2D pt3(0, 1); SCTEST_CHECK(pt1 == pt2); SCTEST_CHECK_FALSE(pt2 == pt3); return true; } bool geomRotatePoint2D() { std::array vertices = { Point2D(1, 0), // θ = 0 Point2D(0, 1), // θ = π/2 Point2D(-1, 0), // θ = π Point2D(0, -1) // θ = 3π/2 }; for (auto i = 0; i < 4; i++) { auto first = i % 4; auto expected = (i + 1) % 4; Point2D vertex; vertices.at(first).Rotate(vertex, 1.5708); if (vertex != vertices.at(expected)) { std::cerr << "expected: " << expected << "\n"; std::cerr << " have: " << vertex << "\n"; return false; } } return true; } bool geomRotatePointsAboutOrigin() { Point2D origin(3, 3); double theta = 0; const std::vector vertices { Polar2D(2, 0), Polar2D(1.41421, 2.35619), Polar2D(1.41421, -2.35619) }; // expected coordinates with no rotation std::vector rotated0 { Point2D(5, 3), Point2D(2, 4), Point2D(2, 2) }; auto rotated = origin.Rotate(vertices, theta); for (auto i = 0; i < 3; i++) { SCTEST_CHECK(rotated.at(i) == rotated0.at(i)); } // expected after 90° rotation theta = scmp::DegreesToRadiansD(90); std::vector rotated90 { Point2D(3, 5), Point2D(2, 2), Point2D(4, 2) }; rotated = origin.Rotate(vertices, theta); for (auto i = 0; i < 3; i++) { SCTEST_CHECK(rotated.at(i) == rotated90.at(i)); } // expected after 180° rotation theta = scmp::DegreesToRadiansD(180); std::vector rotated180 { Point2D(1, 3), Point2D(4, 2), Point2D(4, 4) }; rotated = origin.Rotate(vertices, theta); for (auto i = 0; i < 3; i++) { SCTEST_CHECK(rotated.at(i) == rotated180.at(i)); } return true; } } // anonymous namespace int main() { SimpleSuite suite; suite.AddTest("geomValidateAngularRotation", geomValidateAngularRotation); suite.AddTest("geomConversionIdentities", geomConversionIdentities); suite.AddTest("geomVerifyBasicProperties", geomVerifyBasicProperties); suite.AddTest("geomComparePoint2D", geomComparePoint2D); suite.AddTest("geomRotatePoint2D", geomRotatePoint2D); suite.AddTest("geomRotatePointsAboutOrigin", geomRotatePointsAboutOrigin); auto result = suite.Run(); std::cout << suite << "\n"; return result ? 0 : 1; }