diff options
-rw-r--r-- | include/llmr/text/rotation_range.hpp | 2 | ||||
-rw-r--r-- | src/text/rotation_range.cpp | 4 | ||||
-rw-r--r-- | test/rotation_range.cpp | 137 | ||||
-rw-r--r-- | test/test.gyp | 13 |
4 files changed, 153 insertions, 3 deletions
diff --git a/include/llmr/text/rotation_range.hpp b/include/llmr/text/rotation_range.hpp index 6cc67f323b..e3d3ab6987 100644 --- a/include/llmr/text/rotation_range.hpp +++ b/include/llmr/text/rotation_range.hpp @@ -10,7 +10,7 @@ namespace llmr { -typedef vec2<int16_t> CollisionPoint; +typedef vec2<float> CollisionPoint; typedef vec2<float> CollisionAnchor; typedef std::array<float, 2> PlacementRange; diff --git a/src/text/rotation_range.cpp b/src/text/rotation_range.cpp index e276003c81..496b6108f5 100644 --- a/src/text/rotation_range.cpp +++ b/src/text/rotation_range.cpp @@ -233,8 +233,8 @@ CollisionRange rotationRange(const CollisionBox &inserting, const CollisionBox &b = blocker; // Instead of scaling the boxes, we move the anchors - CollisionAnchor relativeAnchor{(b.anchor.x - a.anchor.x) * scale, - (b.anchor.y - a.anchor.y) * scale}; + CollisionAnchor relativeAnchor{static_cast<float>((b.anchor.x - a.anchor.x) * scale), + static_cast<float>((b.anchor.y - a.anchor.y) * scale)}; // Generate a list of collision interval if (a.rotate && b.rotate) { diff --git a/test/rotation_range.cpp b/test/rotation_range.cpp new file mode 100644 index 0000000000..70126f978f --- /dev/null +++ b/test/rotation_range.cpp @@ -0,0 +1,137 @@ +#include <iostream> +#include "gtest/gtest.h" + +#include <llmr/text/rotation_range.hpp> + +using namespace llmr; + +double deg(double x) { return x / M_PI * 180.0; } + +TEST(RotationRange, mergeCollisions) { + // merge overlapping ranges + EXPECT_EQ( + CollisionRange({{1.0 / 8.0 * M_PI, 6.0 / 8.0 * M_PI}}), + mergeCollisions( + CollisionList( + {{CollisionRange({{3.0 / 8.0 * M_PI, 5.0 / 8.0 * M_PI}}), + CollisionRange({{4.0 / 8.0 * M_PI, 6.0 / 8.0 * M_PI}}), + CollisionRange({{1.0 / 8.0 * M_PI, 2.0 / 8.0 * M_PI}})}}), + PlacementRange({{2.0 * M_PI, 0.0}}))); + + // ignore collision within ignore range + EXPECT_EQ( + CollisionRange({{5.0 / 4.0 * M_PI, 6.0 / 4.0 * M_PI}}), + mergeCollisions(CollisionList({{CollisionRange({{M_PI / 2, M_PI}}), + CollisionRange({{5.0 / 4.0 * M_PI, + 6.0 / 4.0 * M_PI}})}}), + PlacementRange({{0, M_PI}}))); + + // crop collision that ends within ignore range + EXPECT_EQ(CollisionRange({{1.0 / 2.0 * M_PI, 3.0 / 4.0 * M_PI}}), + mergeCollisions( + CollisionList({{CollisionRange({{1.0 / 2.0 * M_PI, M_PI}})}}), + PlacementRange({{3.0 / 4.0 * M_PI, 3.0 / 2.0 * M_PI}}))); + + // crop collision that starts within ignore range + EXPECT_EQ(CollisionRange({{3.0 / 4.0 * M_PI, M_PI}}), + mergeCollisions( + CollisionList({{CollisionRange({{1.0 / 2.0 * M_PI, M_PI}})}}), + PlacementRange({{1.0 / 4.0 * M_PI, 3.0 / 4.0 * M_PI}}))); +} + +TEST(RotationRange, rotatingFixedCollisions) { + // returns collisions + + auto collisions = rotatingFixedCollisions( + CollisionRect{CollisionPoint{-1, 0}, CollisionPoint{0, 1}}, + CollisionRect{CollisionPoint{1.4142, -10}, CollisionPoint{10, 10}}); + + EXPECT_EQ(1, collisions.size()); + EXPECT_EQ(135, round(deg(collisions.front()[0]))); + EXPECT_EQ(135, round(deg(collisions.front()[1]))); +} + +TEST(RotationRange, cornerBoxCollisions) { + { + // returns intersections in sorted order as angles 0..2PI + CollisionList list; + cornerBoxCollisions( + std::back_inserter(list), CollisionPoint{1, 1}, + CollisionCorners{{CollisionPoint{0, 0}, CollisionPoint{0, 10}, + CollisionPoint{10, 10}, CollisionPoint{10, 0}}}); + EXPECT_EQ(1, list.size()); + EXPECT_EQ((CollisionRange{{M_PI / 4.0, M_PI * 7.0 / 4.0}}), list[0]); + } + + { + // handles no intersections + CollisionList list; + cornerBoxCollisions( + std::back_inserter(list), CollisionPoint{200, 200}, + CollisionCorners{{CollisionPoint{1, 1}, CollisionPoint{1, 10}, + CollisionPoint{10, 10}, CollisionPoint{10, 1}}}); + EXPECT_EQ(0, list.size()); + } +} + +TEST(RotationRange, circleEdgeCollisions) { + { + // handles two intersection points + CollisionAngles list; + circleEdgeCollisions(std::back_inserter(list), CollisionPoint{0, 1}, 1, + CollisionPoint{-10, 0}, CollisionPoint{10, 0}); + std::sort(list.begin(), list.end()); + EXPECT_EQ(2, list.size()); + EXPECT_EQ(static_cast<float>(M_PI / 2), list[0]); + EXPECT_EQ(static_cast<float>(M_PI * 3.0 / 2.0), list[1]); + } + + { + // handles one intersection point + CollisionAngles list; + circleEdgeCollisions(std::back_inserter(list), CollisionPoint{0, 1}, 1, + CollisionPoint{0, 0}, CollisionPoint{10, 0}); + EXPECT_EQ(1, list.size()); + EXPECT_EQ(static_cast<float>(M_PI / 2), list[0]); + } + + { + // only returns intersections within the line segment + CollisionAngles list; + circleEdgeCollisions(std::back_inserter(list), CollisionPoint{0, 1}, 1, + CollisionPoint{3, 1}, CollisionPoint{30, 1}); + EXPECT_EQ(0, list.size()); + } + + { + // doesnt count tangetial intersections as collisions + CollisionAngles list; + circleEdgeCollisions(std::back_inserter(list), CollisionPoint{0, 1}, 1, + CollisionPoint{-10, 1}, CollisionPoint{10, 1}); + EXPECT_EQ(0, list.size()); + } +} + +TEST(RotationRange, rotatingRotatingCollisions) { + { + // basically works + CollisionList c = rotatingRotatingCollisions( + CollisionRect{{-1, 0}, {1, 0}}, CollisionRect{{-1, 0}, {1, 0}}, + CollisionAnchor{1, 1}); + + EXPECT_EQ(2, c.size()); + EXPECT_EQ(135, round(deg(c[0][0]))); + EXPECT_EQ(135, round(deg(c[0][1]))); + EXPECT_EQ(315, round(deg(c[1][0]))); + EXPECT_EQ(315, round(deg(c[1][1]))); + } + + { + // checks if the two boxes are close enough to collide at that angle + CollisionList c = rotatingRotatingCollisions( + CollisionRect{{-1, 0}, {1, 0}}, CollisionRect{{-1, 0}, {1, 0}}, + CollisionAnchor{2, 2}); + + EXPECT_EQ(0, c.size()); + } +} diff --git a/test/test.gyp b/test/test.gyp index 400310fa10..0cea1a285f 100644 --- a/test/test.gyp +++ b/test/test.gyp @@ -4,5 +4,18 @@ '../config.gypi' ], 'targets': [ + { + "target_name": "rotation_range", + "product_name": "test_rotation_range", + "type": "executable", + "sources": [ + "./main.cpp", + "./rotation_range.cpp", + ], + "dependencies": [ + "../llmr.gyp:gtest", + "../llmr.gyp:llmr-x86" + ] + }, ] } |