| /* |
| * Copyright 2022 Rive |
| */ |
| |
| #include <rive/math/aabb.hpp> |
| #include <rive/math/raw_path.hpp> |
| #include "no_op_renderer.hpp" |
| |
| #include <catch.hpp> |
| #include <cstdio> |
| |
| using namespace rive; |
| |
| TEST_CASE("rawpath-basics", "[rawpath]") { |
| RawPath path; |
| |
| REQUIRE(path.empty()); |
| REQUIRE(path.bounds() == AABB{0, 0, 0, 0}); |
| |
| path.move({1, 2}); |
| REQUIRE(!path.empty()); |
| REQUIRE(path.bounds() == AABB{1, 2, 1, 2}); |
| |
| path = RawPath(); |
| REQUIRE(path.empty()); |
| REQUIRE(path.bounds() == AABB{0, 0, 0, 0}); |
| |
| path.move({1, -2}); |
| path.line({3, 4}); |
| path.line({-1, 5}); |
| REQUIRE(!path.empty()); |
| REQUIRE(path.bounds() == AABB{-1, -2, 3, 5}); |
| } |
| |
| TEST_CASE("rawpath-add-helpers", "[rawpath]") { |
| RawPath path; |
| |
| path.addRect({1, 1, 5, 6}); |
| REQUIRE(!path.empty()); |
| REQUIRE(path.bounds() == AABB{1, 1, 5, 6}); |
| REQUIRE(path.points().size() == 4); |
| REQUIRE(path.verbs().size() == 5); // move, line, line, line, close |
| |
| path = RawPath(); |
| path.addOval({0, 0, 3, 6}); |
| REQUIRE(!path.empty()); |
| REQUIRE(path.bounds() == AABB{0, 0, 3, 6}); |
| REQUIRE(path.points().size() == 13); |
| REQUIRE(path.verbs().size() == 6); // move, cubic, cubic, cubic, cubic, close |
| |
| const Vec2D pts[] = { |
| {1, 2}, |
| {4, 5}, |
| {3, 2}, |
| {100, -100}, |
| }; |
| constexpr auto size = sizeof(pts) / sizeof(pts[0]); |
| |
| for (auto isClosed : {false, true}) { |
| path = RawPath(); |
| path.addPoly({pts, size}, isClosed); |
| REQUIRE(path.bounds() == AABB{1, -100, 100, 5}); |
| REQUIRE(path.points().size() == size); |
| REQUIRE(path.verbs().size() == size + isClosed); |
| |
| for (size_t i = 0; i < size; ++i) { |
| REQUIRE(path.points()[i] == pts[i]); |
| } |
| REQUIRE(path.verbs()[0] == PathVerb::move); |
| for (size_t i = 1; i < size; ++i) { |
| REQUIRE(path.verbs()[i] == PathVerb::line); |
| } |
| if (isClosed) { |
| REQUIRE(path.verbs()[size] == PathVerb::close); |
| } |
| } |
| } |
| |
| ////////////////////////////////////////////////////////////////////////// |
| |
| static bool is_move(const RawPath::Iter::Rec& rec) { |
| if (rec.verb == PathVerb::move) { |
| REQUIRE(rec.count == 1); |
| return true; |
| } |
| return false; |
| } |
| |
| static bool is_line(const RawPath::Iter::Rec& rec) { |
| if (rec.verb == PathVerb::line) { |
| REQUIRE(rec.count == 1); |
| return true; |
| } |
| return false; |
| } |
| |
| static bool is_quad(const RawPath::Iter::Rec& rec) { |
| if (rec.verb == PathVerb::quad) { |
| REQUIRE(rec.count == 2); |
| return true; |
| } |
| return false; |
| } |
| |
| static bool is_cubic(const RawPath::Iter::Rec& rec) { |
| if (rec.verb == PathVerb::cubic) { |
| REQUIRE(rec.count == 3); |
| return true; |
| } |
| return false; |
| } |
| |
| static bool is_close(const RawPath::Iter::Rec& rec) { |
| if (rec.verb == PathVerb::close) { |
| REQUIRE(rec.count == 0); |
| return true; |
| } |
| return false; |
| } |
| |
| TEST_CASE("rawpath-iter", "[rawpath]") { |
| auto eq = [](Vec2D p, float x, float y) { return p.x == x && p.y == y; }; |
| |
| { |
| RawPath rp; |
| RawPath::Iter iter(rp); |
| REQUIRE(iter.next() == false); |
| REQUIRE(iter.next() == false); // should be safe to call again |
| } |
| { |
| RawPath rp; |
| rp.moveTo(1, 2); |
| rp.lineTo(3, 4); |
| rp.quadTo(5, 6, 7, 8); |
| rp.cubicTo(9, 10, 11, 12, 13, 14); |
| rp.close(); |
| RawPath::Iter iter(rp); |
| auto rec = iter.next(); |
| REQUIRE((rec && is_move(rec) && eq(rec.pts[0], 1,2))); |
| rec = iter.next(); |
| REQUIRE((rec && is_line(rec) && eq(rec.pts[0], 3,4))); |
| rec = iter.next(); |
| REQUIRE((rec && is_quad(rec) && eq(rec.pts[0], 5,6) |
| && eq(rec.pts[1], 7,8))); |
| rec = iter.next(); |
| REQUIRE((rec && is_cubic(rec) && eq(rec.pts[0], 9,10) |
| && eq(rec.pts[1], 11,12) |
| && eq(rec.pts[2], 13,14))); |
| rec = iter.next(); |
| REQUIRE((rec && is_close(rec))); |
| rec = iter.next(); |
| REQUIRE(rec == false); |
| REQUIRE(iter.next() == false); // should be safe to call again |
| } |
| } |